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
项目配置
项目别名@
// ...
resolve: {
alias: {
'~/': `${path.resolve(__dirname, 'src')}/`,
'@': `${path.resolve(__dirname, 'src')}/`,
},
},
如果需要vscode加上路径检查的话,需要配置如下
// ...
"paths": {
"@/*": ["src/*"]
}
未登录转跳
通过localStorage中的token来判断转跳,通过路由守卫来控制
// ...
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()
}
})
文件上传
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)
})
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
import 'nprogress/nprogress.css'
import NProgress from 'nprogress'
//路由转跳开始前
router.beforeEach((to, from, next) => {
NProgress.start();
//...
})
//路由转跳结束前
router.afterEach(() => {
NProgress.done()
//...
})
预定义样式
- scss scss预定义样式
npm i sass
//......
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
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
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
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/**')], //设置翻译文件根目录
}),
],
})
import i18 from '@/modules/i18n.ts'
//......
createApp(App)
.use(i18)
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
login:
Welcome: Welcome to Credit Reference Platform Access Portal, CRP
<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
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
import Pages from 'vite-plugin-pages'
export default {
plugins: [
// ...
Pages({
extensions: ['vue'], //有效的文件后缀
dirs: 'src/pages', //指定文件根目录
extendRoute(route, parent) {
return route
},
}),
],
}
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')
<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
import Vue from '@vitejs/plugin-vue';
import Layouts from 'vite-plugin-vue-layouts';
export default {
plugins: [Vue(), Layouts()],
};
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>
<template>
<main>
<RouterView />
</main>
</template>
VUE语法糖
- unplugin-vue-macros 在项目添加各种语法糖
https://github.com/sxzz/unplugin-vue-macros#readme
npm i unplugin-vue-macros -D
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 的类型,返回 refsdefinePropsRefs
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
import DefineOptions from 'unplugin-vue-define-options/vite'
export default defineConfig({
plugins: [DefineOptions()],
})
defineOptions({
name: 'Foo',
inheritAttrs: false,
})
use组合程序
VueUse 是一个基于 Composition API 的实用程序函数集合
- @vueuse/core 可以使用各种封装的函数
npm i @vueuse/core
- 自动化导入
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
- 自动化导入
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
import UnoCSS from 'unocss/vite'
export default {
plugins: [
UnoCSS({ /* options */ }),
],
}
// 创建一个文件
import { defineConfig } from 'unocss'
export default defineConfig({
// ...UnoCSS options
})
import 'uno.css'
在线文档地址:https://uno.antfu.me/
icon图标引入
该模块引入了icon的图标集合,可以全部引入,也可以单独引入
https://www.npmjs.com/package/@iconify/json
npm install –save @iconify/json
// 通过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
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 }
})
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
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'],
}),
],
}),
],
})
代码示例
<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>