# v3ts_cms_bms
**Repository Path**: ouepacao/v3ts_cms_bms
## Basic Information
- **Project Name**: v3ts_cms_bms
- **Description**: v3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bmsv3ts_cms_bms
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-12-18
- **Last Updated**: 2023-02-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 1.创建项目
> pnpm create vue@latest
# 2.为什么会有两个tsconfig.json文件,区别是什么
> 一个是为node环境服务,一个是web的服务
composite是合成的意思,最后会合成一个tsconfig.json
# 3.pinia使用
```ts
import { defineStore } from 'pinia'
const useCounter = defineStore('counter', {
state: () => ({
counter: 100
}),
actions: {
increment(newCounter: number) {
this.counter++
}
},
getters: {
double: (state) => state.counter * 2
}
})
export default useCounter
```
```vue
main:{{ counter.counter }} - {{counter.double}}
```
# 4.axios封装
```ts
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import axios from 'axios'
// 扩展AxiosRequestConfig
interface InterceptorOptions {
requestOnFullfillCb?: (config: AxiosRequestConfig) => AxiosRequestConfig,
requestOnRejectCb?: (error: any) => any,
responseOnFullfillCb?: (res: T) => T,
responseOnRejectCb?: (error: any) => any
}
interface OuepaRequestConfig extends AxiosRequestConfig {
interceptors?: InterceptorOptions
}
class Request {
// axios实例类型
instance: AxiosInstance
// request实例对应一个axios实例
constructor(config: OuepaRequestConfig) {
this.instance = axios.create(config)
// 全局拦截器
this.instance.interceptors.request.use(
(config: OuepaRequestConfig) => {
console.log('[axios] 全局请求成功拦截')
return config
},
(error) => {
// 全局失败拦截器
return error
}
)
this.instance.interceptors.response.use(
(res: AxiosResponse) => {
console.log('[axios] 全局响应成功拦截')
return res.data
},
error => {return error}
)
// 自定义拦截器判断
this.instance.interceptors.request.use(
config.interceptors?.requestOnFullfillCb,
config.interceptors?.requestOnRejectCb
)
this.instance.interceptors.response.use(
config.interceptors?.responseOnFullfillCb,
config.interceptors?.responseOnRejectCb
)
}
// 封装网络请求的方法
request(config: OuepaRequestConfig) {
/* 单次请求的拦截处理 */
// 请求成功拦截
if (config.interceptors?.requestOnFullfillCb) {
config = config.interceptors.requestOnFullfillCb(config)
}
return new Promise((resolve, reject) => {
this.instance.request(config)
.then(res => {
// 响应成功拦截
if (config.interceptors?.responseOnFullfillCb) {
res = config.interceptors.responseOnFullfillCb(res)
}
resolve(res)
})
.catch(err => {reject(err)})
})
}
/* 常用方法封装 */
get(config: OuepaRequestConfig) {return this.request({...config, method: 'get'})}
post(config: OuepaRequestConfig) {return this.request({...config, method: 'post'})}
delete(config: OuepaRequestConfig) {return this.request({...config, method: 'delete'})}
put(config: OuepaRequestConfig) {return this.request({...config, method: 'put'})}
patch(config: OuepaRequestConfig) {return this.request({...config, method: 'patch'})}
}
export default Request
```
# 5.vite区分 development 和 production 环境
> Vite当中提供了环境变量,在import对象的meta中
+ import.meta.env.MODE(string) 当前模式 -> 'development'|'production'
+ import.meta.env.DEV(boolean) 当前模式是否为开发环境
+ import.meta.env.PROD(boolean) 当前模式是否为生产环境
+ import.meta.env.SSR(boolean) 当前模式是否为ssr环境
# 6.vite环境下创建 `dotenv` 文件,使用和创建环境变量
+ .env 文件可以创建多个
+ .env.production只有在生产环境才会被读
+ .env.development只有开发环境才会被读
+ .env.development.local 不会被git提交,不会被服务器共享,用于隐私数据
在根目录创建 ``.env`` 文件,里面可以声明变量,声明的变量最后会被vite暴露在 `import.meta.env`之中,
但是变量名称必须以`VITE_` 开头,例如:
> VITE_BASE_URL: 'http://codercba.com:1888/airbnb/api'
> 使用时`import.meta.env.VITE_BASE_URL`
# 7.配置Element-plus自动按需打包 (vite.config.ts)
```ts
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
```
# 8.使用ref时给子组件设置类型
+ 子组件自己声明
```vue
// 组件 child.vue
```
+ 使用 `InstanceType`
```ts
import Child from './child.vue'
import { ElImage } from 'element-plus'
type ElImageCtx = InstanceType
type ChildCtx = InstanceType
```
# 9. vite-plugin-style-import自动导入css插件配置
> 还有 pnpm i -D consola
```ts
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
plugins: [
//...
createStyleImportPlugin({
resolves: [ElementPlusResolve()],
libs: [
{
libraryName: 'element-plus',
esModule: true,
resolveStyle: (name: string) => {
return `element-plus/theme-chalk/${ name }.css`
}
}
]
})
]
```
# 10.axios@1.2.2版本config.headers.Authorization携带 ``Bearer``token问题
```ts
interceptors: {
requestOnFullfill: (config) => {
if (!!getToken()) {
(config.headers as AxiosHeaders).set('Authorization', `Bearer ${ getToken() }`)
}
return config
}
}
```
# 11.pinia配置数据持久化
1. > `pnpm i pinia-plugin-persist`
2. pinia配置
```ts
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
```
3. 在store中配置
```ts
persist: {
enabled: true, // 开启持久化
strategies: [
{
key: 'collapsed', // 存储的key
paths: ['isCollapsed'], // 指定需要存储的变量
storage: sessionStorage // 使用的存储方式,默认SessionStorage
}
]
}
```
# 12.vite配置全局less变量
```ts
export default defineConfig({
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
additionalData: `@import "${ path.resolve(__dirname, 'src/asset/style/base.less') }";`
}
}
}
})
```
# 13.unplugin-auto-import插件配置自动导入模块
```ts
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
imports: ['vue', 'vue-router', 'pinia'],
dirs: [], // 配置自定义引入的模块
})
```
# 14.使用全局组件自动导入
```ts
import type { App } from 'vue'
const libraryInstallation = (app: App) => {
const modules: Record = import.meta.glob('./*.vue', {eager: true})
const components: any = {}
for (const m in modules) {
components[m.split('./')[1].replace('.vue', '')] = modules[m].default
}
console.log(components)
for (const cpn in components) {
app.component(cpn, components[cpn])
}
}
export default libraryInstallation
```
# 15.nextTick原理
+ 在vue过去的版本中(例如vue2),nextTick的宏微任务进行了多次的变更,最终在vue3中确认使用微任务来执行nextTick中的回调
> 在vue2的源码中,首先对于浏览器支持情况做了判断,而后再决定使用微任务或宏任务
> 在vue3中,首先判断当前是否还有任务队列
```ts
const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise // 当前没有任务时
let currentFlushPromise: Promise | null = null // 当前任务
const RECURSION_LIMIT = 100
type CountMap = Map
export function nextTick(
this: T,
fn?: (this: T) => void
): Promise {
const p = currentFlushPromise || resolvedPromise // 判断当前是否还有任务在执行
return fn ?p.then(this ?fn.bind(this) :fn) :p
}
```
# 16.style中使用 `v-bind` 的注意事项
> v-bind 绑定变量是记得要加 字符串包裹 `[笑哭]`
# 17.countup.js 数字动画库
> pnpm i countup.js
```ts
import { CountUp } from 'countup.js'
const countup1Ref = ref()
// 参数一:执行动画的元素
// 参数二:数字递增的值
// 参数三:options
onMounted(() => {
const countup1 = new CountUp(countup1Ref.value as HTMLElement, +props.number1, {
startVal: 1
})
countup1.start()
})
```