1.vite搭建
yarn create vite
可能会提示node版本不支持,需要根据提示升级或降级node版本
使用nvm下载对应版本
nvm download 18.x.xnvm use 18.x.x// 需要安装yarn
npm install -g yarn// 重新执行
yarn create vite
过程中会提供选择,分别选择vue、typescript,然后根据提示定位到项目,yarn安装默认依赖
2.安装router
yarn add vue-router
新建一个基础vue文件
<template><router-view v-slot="{ Component }"><keep-alive><component :is="Component" v-if="$route.meta.keepAlive"/></keep-alive><component :is="Component" v-if="!$route.meta.keepAlive"/></router-view>
</template>
新建home文件夹,index页面
<template><div>home</div>
</template><script lang="ts" setup>
</script><style scoped></style>
新建router文件夹,index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import ViewBase from '../views/viewBase.vue'const routes: RouteRecordRaw[] = [{path: '/',name: 'index',redirect: '/home/index',component: ViewBase,children: [{path: '/home',redirect: '/home/index',component: ViewBase,children: [{path: 'index',name: 'home',component: () => import('../views/home/index.vue'),meta: {title: '首页', keepAlive: false}},]},]}
]
const router = createRouter({history: createWebHashHistory(),routes
})
export default router
main.ts文件中使用router
import { createApp } from 'vue'
import router from './router' // 路由
import App from './App.vue'createApp(App).use(router).mount('#app')
给路由跳转添加css效果nprogress
yarn add nprogress
// router/index.tsimport NProgress from 'nprogress'
import 'nprogress/nprogress.css'router.beforeEach((to, from, next) => {NProgress.start()next()
})
router.afterEach(() => {NProgress.done()
})
3.安装pinia
yarn add pinia pinia-plugin-persistedstate
main.ts
import { createApp } from 'vue'
import './style.css'
import router from './router' // 路由
import { createPinia } from 'pinia' // 状态管理
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // 持久化
import App from './App.vue'createApp(App).use(createPinia().use(piniaPluginPersistedstate)).use(router).mount('#app')
新建store文件夹,user.ts
import { defineStore } from 'pinia'
export const userStore = defineStore('user', {state: () => ({userInfo: {userId: 0,userName: ''}}),persist: true // 持久化
})
在home页面获取userId
<template><div>home</div><div>{{userInfo.userId}}</div>
</template><script lang="ts" setup>import { userStore } from "../../store/user"import { storeToRefs } from 'pinia'const user = userStore()const { userInfo } = storeToRefs(user) // 保持响应
</script><style scoped></style>
4.安装element-plus
unplugin-auto-import和 unplugin-vue-components 自动引入组件和按需引入插件、@element-plus/icons-vue @iconify-json/ep unplugin-icons图标需要额外安装才能使用。
yarn add element-plus @element-plus/icons-vue @iconify-json/ep
yarn add unplugin-auto-import unplugin-vue-components unplugin-icons -D
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
// ElementPlus
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 图标
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [// 自动导入element-plus组件ElementPlusResolver(),// 自动导入图标组件IconsResolver({prefix: 'Icon',})],include: [/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx/\.vue$/,/\.vue\?vue/, // .vue/\.md$/ // .md],// 自动导入vue,vue-router相关函数,如ref,reactiveimports: ['vue', 'vue-router', '@vueuse/core'],// 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'dts: 'src/auto-import.d.ts',}),// 自动下载图标Icons({autoInstall: true,compiler: 'vue3'}),Components({resolvers: [ElementPlusResolver(),IconsResolver({// icon前缀默认i,使用方式:<i-ep-xxx/>// prefix: 'i',// 指定图标集epenabledCollections: ['ep']})],dirs: ['src/components']})],
})
使用方式:
<i-ep-edit/>
5.安装axios
yarn add axios
新建http文件夹,index.ts
// 根据接口逻辑不同调整import axios from 'axios'const $http = axios.create({timeout: 200000,
})$http.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8'$http.interceptors.request.use(config => {config.url = '/api' + config.urlreturn config
})$http.interceptors.response.use(function (response) {const code = response.data?.codeif (code === 0) {return response} else {return Promise.reject(response.data)}},function (error) {// Do something with response errorreturn Promise.reject(error)}
)
新建一个接口文件
// list.tsimport $http from '../index'export function fetchList(): any {return $http({url: '/list',method: 'GET'})
}
页面中使用
<script lang="ts" setup>import { fetchList } from '../../http/api/list'onMounted(() => {fetchList().then(res => {const data = res.data?.data || []console.log('data', data)}).catch(e => {ElMessage.error('error:' + e)})})
</script>
当后端接口没有写好时,前端使用mock数据调试,安装mock插件
yarn add vite-plugin-mock mockjs -D
配置
// vite.config.tsimport { viteMockServe } from 'vite-plugin-mock'//plugins中加入viteMockServe()
根目录新建文件夹mock,list.ts
import { MockMethod } from 'vite-plugin-mock'export default [{url: '/api/list',method: 'get',response: () => {return {"code": 0,"message": "","data": [{id: 1,name: 'Alice'}]}}}
] as MockMethod[]
6.安装less
yarn add less less-loader -D
7.其他配置
(1)src文件夹简写为@
// vite.config.tsimport path from 'path'export default defineConfig({plugins: [...],resolve: {// 简写alias: {'@': path.resolve(__dirname, 'src')}}
})// tsconfig.json{compilerOptions: {"baseUrl": "./","paths":{"@/*": ["src/*"]}}
}
(2)vue、lodash-es/nprogress等插件类型声明
// vite-env.d.ts/// <reference types="vite/client" />declare module '*.vue' {import type { DefineComponent } from 'vue'const component: DefineComponent<{}, {}, any>export default component
}declare module 'lodash-es'
declare module 'nprogress'
(3)vue.config.ts配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
// ElementPlus
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 图标
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
// mock
import { viteMockServe } from 'vite-plugin-mock'
import path from 'path'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [// 自动导入element-plus组件ElementPlusResolver(),// 自动导入图标组件IconsResolver({prefix: 'Icon',})],include: [/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx/\.vue$/,/\.vue\?vue/, // .vue/\.md$/ // .md],// 自动导入vue,vue-router相关函数,如ref,reactiveimports: ['vue', 'vue-router', '@vueuse/core'],// 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'dts: 'src/auto-import.d.ts',}),// 自动下载图标Icons({autoInstall: true,compiler: 'vue3'}),Components({resolvers: [ElementPlusResolver(),IconsResolver({// icon前缀默认i,使用方式:<i-ep-xxx/>// prefix: 'i',// 指定图标集epenabledCollections: ['ep']})],dirs: ['src/components']}),viteMockServe()],resolve: {// 简写alias: {'@': path.resolve(__dirname, 'src')}},server: {host: '127.0.0.1',port: 9000,open: true,https: false,proxy: {'/api': {target: 'https://xx.xx.xx.xx',secure: false,changeOrigin: true,timeout: 600 * 1000}}},// 生产环境打包配置build: {minify: 'terser',terserOptions: {//去除 console debuggercompress: {drop_console: true,drop_debugger: true}},assetsDir: '',outDir: path.resolve(__dirname, '../resources/static'),rollupOptions: {output: {chunkFileNames: 'js/[name]-[hash].js',entryFileNames: 'js/[name]-[hash].js',assetFileNames: '[ext]/[name]-[hash].[ext]',manualChunks(id) { //静态资源分拆打包if (id.includes('node_modules')) {return id.toString().split('node_modules/')[1].split('/')[0].toString()}}},}},optimizeDeps: {include: ['lodash-es']}
})
(4)基本样式,新建style文件夹,index.less,reset.less,custom.less
// index.less@import './reset.less' // 覆盖浏览器默认样式
@import './custom.less' // 自定义公共样式//main.tsimport '@/assets/style/index.less'
// reset.lessbody,
#app {margin: 0;font-size: 12px;
}html,
body,
#app {height: 100%;min-width: 1100px;margin: 0;padding: 0
}
.container{font-size: 12px;
}body {overflow-y: hidden;
}#app {font-family: Microsoft YaHei, 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;color: #606266;
}ul {list-style-type: none;
}ul,
ol {list-style: none
}:link,
:visited,
ins {text-decoration: none
}:focus {outline: 0
}@media (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) {html {font-size: 117.1875px}
}@media (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) {html {font-size: 129.375px}
}