2023-02-01 | 项目构建 | UNLOCK | 更新时间:2023-3-22 14:27

Vitesse-Vue3项目的各种问题

Vitesse 一个快速地创建 Web 应用的 vue3 项目简单框架

项目结构

|—— locales/       //国际语言翻译
|—— src/
  |—— layouts/     //各类定义的模板
	|—— index.vue
	//...
  |—— pages/       //自动生成路由的文件
    |—— index.vue
  |—— stores/      //pinia存储的全局数据
    |—— user.ts
	//...
  |—— styles/      //各类导入的样式文件
    |—— main.css
	//...
  |—— main.css      //样式入口文件
  |—— markdown.css  //引入的markdown样式
  |—— main.ts       //入口文件
|—— index.html

项目配置

项目别名@

vite.config.js
// ... resolve: { alias: { '~/': `${path.resolve(__dirname, 'src')}/`, '@': `${path.resolve(__dirname, 'src')}/`, }, },

如果需要vscode加上路径检查的话,需要配置如下

tsconfig.json
// ... "paths": { "@/*": ["src/*"] }

未登录转跳

通过localStorage中的token来判断转跳,通过路由守卫来控制

app.vue
// ... const router = useRouter() let token = localStorage.getItem('token'); if(!token||token=='null'){ router.replace('/login') } router.beforeEach((to,from,next)=>{ if(to.name !== 'login'&&!token||token=='null'){ router.replace('/login') }else{ next() } })

文件上传

home.vue
const crp_message=`{ "dataFormat": "TUDF", "dcrRefInfo": { "dcrInitiator": "CRA01", "dcrRefId": "ABCD123456" }, "fileAction": "CRT", "noOfRecords": "10000", "remarks": "client remarks", "resumeId": "2", "submissionType": "AMEND" }` // 后端不接收json字符串,需要处理成二进制 const blob = new Blob([crp_message], { type: 'application/json', }); const data={ crp_message:blob, crp_file:fileList.list[0]?.raw } dataUpload(data).then((res) => { console.log(res) })
index.js
export const dataUpload=function(data){ //上传文件,数据提交上传 return require({ url: `${network}/${auto}/data-submission/upload`, headers: { "Content-Type": "multipart/form-data;charset=UTF-8" }, method: 'post', data, }) }

插件介绍

  • vite-plugin-pwa 通过简单的配置将你的vite项目变成pwa 应用
  • vite-plugin-vue-markdown 基于 vite 的 markdown 代码块预览插件
  • vite-ssg-sitemap SSS(服务器渲染)站点地图
  • vite-plugin-vue-component-preview 预览vue组件

顶部加载条

  • NProgress 顶部加载条,增加用户的视觉效果

npm i nprogress -S

main.js
import 'nprogress/nprogress.css' import NProgress from 'nprogress' //路由转跳开始前 router.beforeEach((to, from, next) => { NProgress.start(); //... }) //路由转跳结束前 router.afterEach(() => { NProgress.done() //... })

预定义样式

  • scss scss预定义样式

npm i sass

vite.config.ts
//...... css: { // css预处理器 preprocessorOptions: { scss: { // 引入 mixin.scss 这样就可以在全局中使用 mixin.scss中预定义的变量了 // 给导入的路径最后加上 ; additionalData: '@import "./src/styles/mixin.scss";', }, }, },

自动化引入

  • unplugin-auto-import 配置自动引入项目的引用脚本

https://www.npmjs.com/package/unplugin-auto-import

npm i -D unplugin-auto-import

vite.config.ts
import AutoImport from 'unplugin-auto-import/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig({ plugins: [ AutoImport({ imports: [ //自动导入模块 'vue', 'vue-router', ], dts: './auto-imports.d.ts', //自动导入的文件集成 dirs: [ // 自动导入目录下的模块并导出 'src/composables', 'src/stores', ], vueTemplate: false, //在Vue模板内自动导入 resolvers: [ //自定义解析器,兼容第三方组件” ElementPlusResolver() ], //... }), ], })

自动化安装

  • unplugin-vue-components 自动化安装引入项目的库包

https://github.com/antfu/unplugin-vue-components

npm install -D unplugin-vue-components

vite.config.ts
import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig({ plugins: [ Components({ extensions: ['vue'], include: [/\.vue$/, /\.vue\?vue/, /\.md$/], dts: 'src/components.d.ts', resolvers: [ElementPlusResolver()], }), ], })

国际化翻译

  • intlify/unplugin-vue-i18n 国际翻译,翻译多国语言

https://www.npmjs.com/package/@intlify/unplugin-vue-i18n

npm i -D @intlify/unplugin-vue-i18n
npm i vue-i18n

vite.config.ts
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' export default defineConfig({ plugins: [ VueI18nPlugin({ runtimeOnly: true, //在生产构建中自动使用 Vue-i18n compositionOnly: true, //将 vue-i18n API 仅作组合 API fullInstall: true, //安装VueI18n提供的全套 API、组件等 include: [path.resolve(__dirname, 'locales/**')], //设置翻译文件根目录 }), ], })
main.ts
import i18 from '@/modules/i18n.ts' //...... createApp(App) .use(i18)
src/modules/i18n.ts
import { createI18n } from 'vue-i18n' import { type UserModule } from '~/types' const messages = Object.fromEntries( Object.entries( import.meta.glob<{ default: any }>('../../locales/*.y(a)?ml', { eager: true })) .map(([key, value]) => { const yaml = key.endsWith('.yaml') return [key.slice(14, yaml ? -5 : -4), value.default] }), ) export const install: UserModule = ( app ) => { const i18n = createI18n({ legacy: false, locale: 'en', messages, }) app.use(i18n) } export default install
locales/en.yml
login: Welcome: Welcome to Credit Reference Platform Access Portal, CRP
index.vue
<script setup lang="ts"> // 此为经过AutoImport全局导入后,所以useI18n API可以直接调用 const { t } = useI18n() </script> <template> <h1>{{t('login.Welcome')}}</h1> </template>

图形化插件

  • vite-plugin-inspect 用于检查vite插件在项目中的状态

https://github.com/antfu/vite-plugin-inspect

npm i -D vite-plugin-inspect

vite.config.ts
import Inspect from 'vite-plugin-inspect' export default { plugins: [ Inspect() ], }

自动化路由

  • vite-plugin-pages 基于文件进行路由配置

https://github.com/hannoeru/vite-plugin-pages

npm install -D vite-plugin-pages
npm install vue-router

vite.config.js
import Pages from 'vite-plugin-pages' export default { plugins: [ // ... Pages({ extensions: ['vue'], //有效的文件后缀 dirs: 'src/pages', //指定文件根目录 extendRoute(route, parent) { return route }, }), ], }
main.ts
import { createApp } from 'vue' import './style.css' import App from './App.vue' import { createRouter,createWebHistory } from 'vue-router' import routes from '~pages' const router = createRouter({ history: createWebHistory(), routes, }) createApp(App).use(router).mount('#app')
App.vue
<template> <RouterView /> </template>

src/ 目录下添加 pages 文件夹。里面放置各种页面,会自动生成相关路由

src/
  |——pages/
    |——[...all].vue  //404页面,会匹配所有不被匹配的路径
    |——index.vue //首页
    |——Data/
      |——index.vue   //匹配路由 `/Data`
      |——about.vue   //匹配路由 `/Data/about`
      |——[id]/
        |——Detail.vue//匹配路由 `/Data/xxxx/Detail`

自定义布局

  • vite-plugin-vue-layouts 预设各种页面模板给其他页面使用

https://www.npmjs.com/package/vite-plugin-vue-layouts

npm install -D vite-plugin-vue-layouts

vite.config.ts
import Vue from '@vitejs/plugin-vue'; import Layouts from 'vite-plugin-vue-layouts'; export default { plugins: [Vue(), Layouts()], };
main.ts
import { setupLayouts } from 'virtual:generated-layouts' import generatedRoutes from '~pages' const routes = setupLayouts(generatedRoutes) const router = createRouter({ history: createWebHistory(), routes, }) createApp(App) .use(router)

默认使用的是default,也可以指定

<route lang="yaml">
meta:
  layout: home
</route>
layouts/home.vue
<template> <main> <RouterView /> </main> </template>

VUE语法糖

  • unplugin-vue-macros 在项目添加各种语法糖

https://github.com/sxzz/unplugin-vue-macros#readme

npm i unplugin-vue-macros -D

vite.config.ts
import VueMacros from 'unplugin-vue-macros/vite' import Vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [ VueMacros({ plugins: { vue: Vue(), }, }), ], })
  • defineOptions 可以在setup使用选项式代码
  • defineModel 简化声明和改变 v-model 的步骤
  • defineProps 正确的解构 props 的类型,返回 refs
  • definePropsRefs defineProps 返回的是 refs 而不是响应式对象,但 definePropsRefs 可以在不失去响应式的情况下被解构
  • defineOptions 可以在 setup 中声明 SFC 中 slots 的类型
  • defineRender 可以在 setup 中定义渲染函数
  • shortEmits 简化 emits 的定义
  • shortVmodel v-modal的语法糖
  • setupComponent (实验功能) 可以将 setup 中的代码放在没有 Volar 扩展的 纯 JS/TS(X) 中
  • setupSFC (实验功能) 和setupComponent一起使用

选项式API

该模块可以由vue语法糖整合一起引入,也可以单独引入,以下为单独引入部分

  • unplugin-vue-define-options 可以在setup中使用选项式API

https://vue-macros.sxzz.moe/macros/define-options.html

npm i -D unplugin-vue-define-options

vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite' export default defineConfig({ plugins: [DefineOptions()], })
Foo.vue
defineOptions({ name: 'Foo', inheritAttrs: false, })

use组合程序

VueUse 是一个基于 Composition API 的实用程序函数集合

  • @vueuse/core 可以使用各种封装的函数

https://vueuse.org/guide/

npm i @vueuse/core

  • 自动化导入
vite.config.ts
import AutoImport from 'unplugin-auto-import/vite' // ...... AutoImport({ imports: [ '@vueuse/core', ], dts: 'src/auto-imports.d.ts', }),

VueUse/head

VueUse/head 是为了给我们的页面添加标题和元标签等标题标签,用于更好的SEO

npm i @vueuse/head

  • 自动化导入
vite.config.ts
import AutoImport from 'unplugin-auto-import/vite' // ...... AutoImport({ imports: [ '@vueuse/head', ], dts: 'src/auto-imports.d.ts', }),

安装UnoCss

按需安装所需要的CSS

https://github.com/unocss/unocss

npm i -D unocss

vite.config.ts
import UnoCSS from 'unocss/vite' export default { plugins: [ UnoCSS({ /* options */ }), ], }
uno.config.ts
// 创建一个文件 import { defineConfig } from 'unocss' export default defineConfig({ // ...UnoCSS options })
main.ts
import 'uno.css'

在线文档地址:https://uno.antfu.me/

icon图标引入

该模块引入了icon的图标集合,可以全部引入,也可以单独引入

https://www.npmjs.com/package/@iconify/json

npm install –save @iconify/json

vite.config.ts
// 通过UnoCss对图标进行配置 import UnoCSS from '@unocss/vite' import { presetIcons,presetAttributify } from 'unocss' export default { plugins: [ UnoCSS({ presets: [ presetAttributify(), presetIcons({ scale: 1.2, warn: true }) ], rules:[ ], }), ], }

组件介绍

状态管理

  • Pinina 状态管理容器,管理全局状态state

https://pinia.vuejs.org/zh/getting-started.html

npm install pinia

src/stores/user.js
import {defineStore} from 'pinia' // 类似vuex export const useCounterStore=defineStore('min',()=>{ state:()=>({ //箭头函数return对象 name:"1230", }), getters: { double: (state) => state.count * 2, }, actions: { increment() { this.count++ }, }, }) // 或者类似setup export const useCounterStore = defineStore('counter', () => { const count = ref(0) const double = computed((state) => state.count * 2) function increment() { count.value++ } return { count, double, increment } })
setup
import { useCounterStore } from '@/stores/user' const store = useCounterStore() store.increment()

UI组件库

原框架有UnoCSS原子预设插件,我不想用,这里我引入ElementPlusUI库,同时使用自动化安装模块

https://element-plus.org/zh-CN/guide/installation.html

npm install -D unplugin-vue-components unplugin-auto-import

vite.config.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 IconsResolver from 'unplugin-icons/resolver' export default defineConfig({ // ... plugins: [ // ... AutoImport({ resolvers: [ ElementPlusResolver(), //导入组件 IconsResolver({ //导入图标 prefix: 'Icon', }), ], }), Components({ resolvers: [ ElementPlusResolver(), IconsResolver({ enabledCollections: ['ep'], }), ], }), ], })

代码示例

App.vue
<script setup lang="ts"> // 用了vueuse里的一些函数程序 useHead({ title: 'Vitesse', meta: [ { name: 'description', content: 'Opinionated Vite Starter Template' }, { name: 'theme-color', content: computed(() => isDark.value ? '#00aba9' : '#ffffff'), }, ], link: [ { rel: 'icon', type: 'image/svg+xml', href: computed(() => preferredDark.value ? '/favicon-dark.svg' : '/favicon.svg'), }, ], }) </script> <template> <RouterView /> </template>