Vue3+Vite+Ts项目搭建及常用插件汇总

  • Post author:
  • Post category:vue




概述

个人使用vue vite ts创建项目时笔记以及相关插件的使用汇总。



初始化

  • 创建项目
npm init vite@latest system-vue -- --template vue-ts
  • 安装初始依赖
cd system-vue
npm install
npm run dev



环境配置


  • .env.development
ENV = 'development'
​
VITE_TITLE = '开发环境'
​
VITE_BASE_URL  = 'http://127.0.0.1:8080'
​
VITE_BASE_API  = '/api'

  • .env.production
ENV = 'production'
​
VITE_TITLE = '生产环境'
​
VITE_BASE_URL  = ''
​
VITE_BASE_API  = ''

  • .env.test
ENV = 'test'
​
VITE_TITLE = '测试环境'
​
VITE_BASE_URL  = ''
​
VITE_BASE_API  = ''



相关配置



vite

为保证node使用建议安装

@types/node

  • 安装
npm install @types/node --save-dev
  • 添加配置
//  vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import * as path from 'path'
​
export default defineConfig({
    plugins: [
        vue()
    ],
    resolve: {
        alias: {
            '@': path.resolve(__dirname, 'src'),
            '@views': path.resolve(__dirname, 'src/views'),
            '@layout': path.resolve(__dirname, 'src/layout'),
            '@components': path.resolve(__dirname, 'src/components')
        }
    },
    server: {
        host: '127.0.0.1',
        port: 3000,
        cors: true,
        open: false,
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8080',
                changeOrigin: true,
                rewrite: (path: string) => path.replace(/^/api/, '')
            }
        }
    }
})

解决打包错误

package.json

{
  "script": {
    "build": "vue-tsc --noEmit --skipLibCheck && vite build"
  }
}



typescript

配置

tsconfig.json

{
  "compilerOptions": {
    "jsx": "preserve",
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "useDefineForClassFields": true,
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [
      "node",
      "vite/client"
    ]
  },
  "skipLibCheck": true,
  "noImplicitAny": true,
  "noImplicitThis": true,
  "strictNullChecks": true,
  "suppressImplicitAnyIndexErrors": true,
  "baseUrl": ".",
  "paths": {
    "@": [
      "src"
    ]
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "vite.config.ts"
  ],
  "references": [
    {
      "path": "./tsconfig.node.json"
    }
  ]
}



eslint

  • 安装
npm install eslint eslint-plugin-vue --save-dev
# 由于ESLint默认使用Espree语法解析,是不能识别TypeScript某些语法,所以需安装@typescript-eslint/parser替换掉默认解析器
npm install @typescript-eslint/parser --save-dev
# 补充额外得typescript语法的规则
npm install @typescript-eslint/eslint-plugin --save-dev
  • 创建配置文件

    .eslintrc.js



    .eslintrc.json
// .eslintrc.js
module.exports = {
    root: true,
    env: {
        node: true,
        es6: true,
        browser: true
    },
    extends: [
        'plugin:vue/vue3-recommended',
        'plugin:@typescript-eslint/recommended',
        'eslint:recommended'
    ],
    parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: '8',
        sourceType: 'module',
        ecmaFeatures: {
            jsx: true
        }
    },
    rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'indent': 0,
        'space-before-function-paren': 0
    }
}
  • 创建忽略文件

    .eslintignore
index.html
dist
node_modules
*.md
.vscode
.idea
public



less/sass

# less
npm install less less-loader -D
# sass
npm install sass sass-loader -D



vue-router

  • 安装
npm install vue-router@4
  • 配置
//  src/router/index.ts
import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router'
​
const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        redirect: '/login'
    },
    {
        path: '/:pathMatch(.*)*',
        name: 'NotFound',
        component: () => import('../views/error/404.vue')
    },
    {
        path: '/login',
        name: 'login',
        meta: {
            title: '登录',
            keepAlive: true,
            requireAuth: false
        },
        component: () => import('@views/login.vue')
    }
]
​
const router = createRouter({
    history: createWebHistory(),
    routes
})
​
router.beforeEach((to, from, next) => {
    next()
})
​
router.afterEach(() => {
})
​
export default router
  • 使用
// main.ts
import {createApp} from 'vue'
import App from './App.vue'
​
import router from './router'
​
const app = createApp(App)
​
app.use(router)
    .mount('#app')



nProgress

  • 安装
npm install nprogress --save
  • 配置
// 在src/router/index.ts中添加下列配置
import * as nProgress from 'nprogress'
​
router.beforeEach((to, from, next) => {
    nProgress.start()
    next()
})
​
router.afterEach(() => {
    nProgress.done()
})
​
nProgress.configure({
    ease: 'linear',
    speed: 500,
    showSpinner: false  // 是否使用进度环
})
​
// 在mian.ts中引入样式
import 'nprogress/nprogress.css'
  • 配置进度条颜色
// App.vue
<style>
/*设置进度条颜色  不配置时为默认颜色*/
#nprogress .bar {
  background: red !important;
}
</style>

解决引用错误问题

//  在env.d.ts中添加
declare module 'nprogress'



element plus

  • 安装
# element plus
npm install element-plus --save
# element plus icon
npm install @element-plus/icons-vue
  • 配置
// src/plugins/element-plus.ts
import {App} from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import * as Icons from '@element-plus/icons-vue'
​
export default {
    install(app: App) {
        app.use(ElementPlus, {
            locale,
            size: 'small' || 'default' || 'large'
        })
        Object.keys(Icons).forEach((key: string) => {
            app.component(key, Icons[key as keyof typeof Icons]);
        })
    }
}
  • 使用
// main.ts
import {createApp} from 'vue'
import App from './App.vue'
import ElementPlus from './plugins/element-plus'
​
const app = createApp(App)
​
app.use(ElementPlus)
    .mount('#app')



style



global.scss

新建

src\assets\style\global.scss

样式文件

/*全局公共样式表*/
html, body, #app {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: Avenir, Helvetica, Arial, sans-serif;
​
  a {
    text-decoration: none;
    color: #333;
  }
​
  ul, li {
    list-style: none;
  }
​
}
​
/*设置滚动条样式*/
::-webkit-scrollbar {
  width: 5px;
}
​
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track {
  border-radius: 10px;
  background-color: rgba(0, 0, 0, 0.1);
}
​
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 6px rgba(26, 25, 25, 0.3);
  background-color: rgba(0, 0, 0, 0.1);
}
​
/*设置进度条颜色  不配置时为默认颜色*/
#nprogress .bar {
  /*background: rgba(41, 236, 127, 0.5) !important;*/
}
  • 使用
//  APP.vue
@import 'assets/style/global.scss';



reset.css
  • 安装
npm install reset.css --save
  • 使用
// APP.vue
@import 'reset.css';



animate.css
  • 安装
npm install animate.css --save
  • 使用
// APP.vue
@import 'animate.css';

通过class

使用详情

<h1 class="animate__animated animate__bounce">An animated element</h1>



windi css

官网:

Windi Css

  • 安装
npm install -D vite-plugin-windicss windicss
  • 配置
//  在vite.config.ts中添加下列配置
import WindiCSS from 'vite-plugin-windicss'
​
export default {
    plugins: [
        WindiCSS(),
    ],
}
​
// 在main.ts中引入样式文件
import 'virtual:windi.css'
  • 使用


使用详情




axios

  • 安装
npm install axios --save
  • 配置
// src/utils/axios.ts
import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'
import {ElMessage, ElNotification} from 'element-plus'
import {useRouter} from 'vue-router'
import * as nProgress from 'nprogress'
import {useMainStore} from '../store'
​
axios.create({
    baseURL: import.meta.env.VITE_BASE_URL,
    timeout: 5000,
    withCredentials: true
})
​
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8';
​
axios.interceptors.request.use((config: AxiosRequestConfig) => {
    nProgress.start()
    if (useMainStore().getAuthorization && localStorage.getItem('Authorization')) {
        if (config.headers) {
            config.headers.Authorization = useMainStore().getAuthorization
        }
    }
    return config;
}, ((error: any) => {
    ElNotification.error('请求错误!')
    return Promise.reject(error);
}))
​
axios.interceptors.response.use((response: AxiosResponse) => {
    nProgress.done()
    switch (response.status as number) {
        case 401: {
            ElMessage.warning('请先登录')
            const router = useRouter()
            router.push('/login')
            break
        }
        case 403: {
            ElMessage.warning('拒绝访问')
            break
        }
    }
    return response;
}, ((error: any) => {
        ElNotification.error('响应错误!')
        return Promise.reject(error);
    }
))
​
export default axios
  • 使用
// api/user/user.ts
import axios from '../../utils/axios'
import * as qs from 'qs'
​
const baseAPI = import.meta.env.VITE_BASE_API
​
export const login = (data: any) => {
    return axios({
        method: 'POST',
        url: baseUrl + '/login',
        data: qs.stringify(data),
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    })
}



pinia

  • 安装
npm install pinia
  • 配置
//  store/index.ts
import {defineStore} from 'pinia'
​
interface storeTypes {
}
​
export const useMainStore = defineStore('main', {
    // 存储全局状态
    state: (): storeTypes => {
        return {}
    },
​
    // 封装计算属性 具有缓存功能
    getters: {},
​
    // 封装业务逻辑 修改state
    actions: {}
})
  • 使用
//  main.ts
import {createApp} from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
​
const app = createApp(App)
​
app.use(createPinia())
    .mount('#app')



i18n

什么是

i18n


i18n

(internationalization)是“国际化”的简称。由于其首尾分别为 i 和 n ,中间有18 个字符。故简写为

i18n

。在vue.js中,有vue i18n国际化插件。可以轻松实现项目国际化的操作。

如何使用

i18n

  • 安装

    i18n

    插件
npm install vue-i18n
  • 创建所需语言文件(这里仅以中英文为例)

中文语言文件:

zh_CN

英文语言文件:

en.ts

1.文件

en.ts

// src/i18n/language/en.ts
export default {
    system: {
        title: 'test i18n'
    }
}

2.文件

zh_CN.ts

// src/i18n/language/zh_CN.ts
export default {
    system: {
        title: '测试 i18n'
    }
}
​
  • 配置 i18n

    index.ts
// src/i18n/index.ts
import {createI18n} from 'vue-i18n'
import zh_CN from './language/zh_CN'
import en from './language/en'
​
const messages = {
    zh_CN: {...zh_CN},
    en: {...en}
}
​
// 获取浏览器当前语言
const getCurrentLanguage = () => {
    const language = navigator.language
    const currentLanguage = language.indexOf('zh') !== -1 ? 'zh_CN' : 'en'
    localStorage.setItem('language', currentLanguage)
    return currentLanguage
}
​
// 创建i18n实例
const i18n = createI18n({
    legacy: false,
    globalInjection: true,
    locale: localStorage.getItem('language') || getCurrentLanguage() || 'zh_CN',
    messages: messages
})
​
export default i18n
  • 全局注册
import {createApp} from 'vue'
import App from './App.vue'
import i18n from './i18n'
​
const app = createApp(App)
​
app.use(i18n)
    .mount('#app')
  • 使用案例
<script setup lang="ts">
import {useI18n} from 'vue-i18n'
import {computed} from 'vue'
​
// 创建i18n对象
const i18n = useI18n()
​
// 获取当前语言
const currentLanguage = computed(() => i18n.locale.value)
​
// 切换语言
const changeLanguage = (language: string) => {
  localStorage.setItem('language', language)
  i18n.locale.value = language
}
</script>
​
<template>
  <el-dropdown @command="changeLanguage">
    <span class="el-dropdown-link">切换语言</span>
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item command="zh_CN" :disabled="currentLanguage==='zh_CN'">中  文</el-dropdown-item>
        <el-dropdown-item command="en" :disabled="currentLanguage==='en'">English</el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
  <hr/>
<p>{{ $t(`system.title`) }}</p>
</template>
​
<style scoped lang="scss">
    
</style>



vueUse


VueUse

是一个基于

Composition API

的实用函数集合。

  • 安装
npm install @vueuse/core
  • 基本使用

更多使用请访问:

vueUse

​
<template>
  <h1>鼠标坐标:{{x}},{{y}}</h1>
</template>
<script lang="ts" setup>
import {useMouse} from '@vueuse/core'
​
const {x, y} = useMouse()
</script>
​



其他插件



prettier

  • 配置
// prettier.config.js
module.exports = {
    semi: false,
    singleQuot: true,
    trailingComma: "none",
    printWidth: 100,
    vueIndentScriptAndStyle: true,
    singleQuote: true,
    proseWrap: 'never',
    htmlWhitespaceSensitivity: 'strict',
    endOfLine: 'auto',
}
  • 配置

    .prettierignore
/node_modules/**
/public/*



qs

  • 安装
npm install qs
  • 使用
import * as qs from 'qs'

解决引用报红

//  env.d.ts
declare module 'qs'



cookie

  • 安装
# 由于universal-cookie依赖于vueuse/integrations 故需要安装
npm install @vueuse/integrations
# cookie依赖安装
npm install universal-cookie
  • 使用
import {useCookies} from '@vueuse/integrations/useCookies'



base64

  • 安装vueUse
npm install @vueuse/core
  • 使用
import { Ref, ref } from 'vue'
import { useBase64 } from '@vueuse/core'

const text = ref('')
const { base64 } = useBase64(text)



svgIcon

  • 安装
npm install vite-plugin-svg-icons -D
  • 创建组件
// src/components/svgIcon/index.vue
<template>
  <svg :aria-hidden="true"
       class="svg-icon"
       :style="{color:color,height:size+'em',width:size+'em',fill:fill}">
    <use :xlink:href="symbolId"/>
  </svg>
</template>

<script setup lang="ts">
import {computed, PropType} from 'vue'

const props = defineProps({
  prefix: {type: String as PropType<string>, default: 'icon'},
  name: {type: String as PropType<string>, required: true},
  color: {type: String as PropType<string>, default: ''},
  size: {type: Number as PropType<number>, default: 1},
  fill: {type: String as PropType<string>, default: 'currentColor'}
})

const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>

<style scoped lang="scss">
.svg-icon {
  vertical-align: -0.15em;
  overflow: hidden;
}
</style>
  • 配置
//  vite.config.ts
import {defineConfig} from 'vite'
import * as path from 'path'
import {createSvgIconsPlugin} from 'vite-plugin-svg-icons'
​
export default defineConfig({
    plugins: [
        createSvgIconsPlugin({
            // svg图标存放路径
            iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],
            symbolId: 'icon-[dir]-[name]'
        })
    ]
})
  • 注册
import {createApp} from 'vue'
import App from './App.vue'
import 'virtual:svg-icons-register'
import svgIcon from '@components/svgIcon/index.vue'
​
const app = createApp(App)
​
app .component('svg-icon', svgIcon)
    .mount('#app')
  • 使用
<svg-icon name="bug"/>



版权声明:本文为qq_14818715原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。