# 贾成豪硅谷甄选平台 **Repository Path**: runler/jch_vue3_ts ## Basic Information - **Project Name**: 贾成豪硅谷甄选平台 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-11-05 - **Last Updated**: 2024-01-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # jch_vue3_ts 环境: node 18.18.2 pnpm 8.10.2 ## 初始化项目 ```js pnpm create vue@latest √ 请输入项目名称: ... jch_vue3_ts // 贾成豪主讲的 vue3+ts 学习项目 √ 是否使用 TypeScript 语法? ... 否 / 是 √ 是否启用 JSX 支持? ... 否 / 是 √ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是 √ 是否引入 Pinia 用于状态管理? ... 否 / 是 √ 是否引入 Vitest 用于单元测试? ... 否 / 是 √ 是否要引入一款端到端(End to End)测试工具? » 不需要 √ 是否引入 ESLint 用于代码质量检测? ... 否 / 是 √ 是否引入 Prettier 用于代码格式化? ... 否 / 是 cd jch_vue3_ts pnpm install // vue 3.3.4 pnpm dev // vite 4.5.0 pnpm run format pnpm lint pnpm dev pnpm build ``` ### src目录配置@别名 vite.config.ts 已自动实现了 ```js resolve: { alias: { '@': path.resolve('./src'), // 相对路径别名配置,使用 @ 代替 src }, }, ``` vscode编辑器提示作用的 tsconfig.json -> 引入的 tsconfig.app.json 中 也自动实现了 ```js "paths": { "@/": ["./src/"] } ``` ### Git 初始化管理项目 ```sh git init git add . git commit -m 'init' ``` ### Eslint配置 .vue .ts 文件 默认格式化 选择eslint Eslint>Format:Enable onsave Editor:Format On Save 个性编辑 .eslintrc.cjs ```js // 个性化格式配置 rules: { 'vue/multi-word-component-names': 0, // 不再强制要求组件命名 'prettier/prettier': [ 'error', { semi: false, // 每行结尾符 ;取消 wrapAttributes: false, // 属性单独占一行关闭 printWidth: 100, // 每行最大字符数 endOfLine: 'auto' // 换行符根据系统自动配置 } ] } ``` ### ElementPlus 安装-按需导入-ts类型错误配置 ```sh pnpm install element-plus --save // 安装 按需自动导入2个插件 pnpm install -D unplugin-vue-components unplugin-auto-import pnpm install @element-plus/icons-vue pnpm i -D unplugin-icons // 图标自动导入插件 还需要unplugin-auto-import 上面已安装了 ``` ```js // vite.config.ts ... import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' import Icons from 'unplugin-icons/vite' import IconsResolver from 'unplugin-icons/resolver' export default defineConfig({ plugins: [ vue(), // 按需自动导入 AutoImport({ imports: ['vue'], // 自动导入vue 相关函数,如:ref, reactive, toRef 等,也可增加vue-router自动导入 eslintrc: { enabled: true }, // 解决eslint 报no-undef错误,会生成.eslintrc-auto-import.json文件,在.eslintrc.cjs的extends:中加入 // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式) resolvers: [ ElementPlusResolver(), // 自动导入图标组件 IconsResolver({ prefix: 'Icon' }) ] }), Components({ resolvers: [ // 自动导入 Element Plus 组件 ElementPlusResolver(), // 自动注册图标组件 IconsResolver({ enabledCollections: ['ep'] }) ] }), // 自动导入图标 Icons({ autoInstall: true }) ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } }) ``` ``` import { Edit } from '@element-plus/icons-vue' 按钮图标不显示 ``` ### SVG图标配置 ``` pnpm install vite-plugin-svg-icons -D ``` #### ElementPlug 中文国家化 ```js // app.vue // 本地化中文配置 import zhCn from 'element-plus/dist/locale/zh-cn.mjs' // 报类型不识别,在my.d.ts 指定声明 ``` ### 安装sass 重置默认样式 ```sh pnpm i sass -D ``` 下载 到 src/styles/reset.scss 重置样式文件 main.ts 引入 import '@/styles/index.scss' //引入模板的全局的样式 ### vue-router 基本路由的配置 ```js // 匹配任何字符 404错误页 { path: '/:xxx(.*)*', name: 'ErrorPage', component: () => import('@/components/ErrorPage.vue') } { //任意路由 path: '/:pathMatch(.*)*', redirect: '/404', name: 'Any', meta: { title: '任意路由', hidden: true, icon: 'DataLine' } } ``` ```js import { createRouter, createWebHistory } from 'vue-router' import { constantRoute } from './routes' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: constantRoute, //滚动行为 scrollBehavior() { return { left: 0, top: 0 } } }) export default router ``` ### mock接口 ```js pnpm install -D vite-plugin-mock@2.9.6 mockjs ``` vite.config.ts配置启用插件 ```js import { viteMockServe } from 'vite-plugin-mock' // https://vitejs.dev/config/ export default defineConfig(({ command, mode }) => { // 根据模式获取环境文件配置信息对象 const env = loadEnv(mode, process.cwd()) return { plugins: [ vue(), // mock接口 viteMockServe({ localEnabled: command === 'serve' }), ``` 项目根目录创建mock目录 新建user.ts文件 ```js //createUserList:次函数执行会返回一个数组,数组里面包含两个用户信息 function createUserList() { return [ { userId: 1, avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', username: 'admin', password: '111111', desc: '平台管理员', roles: ['平台管理员'], buttons: ['cuser.detail'], routes: ['home'], token: 'Admin Token' }, { userId: 2, avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', username: 'system', password: '111111', desc: '系统管理员', roles: ['系统管理员'], buttons: ['cuser.detail', 'cuser.user'], routes: ['home'], token: 'System Token' } ] } //对外暴露一个数组:数组里面包含两个接口 //登录假的接口 //获取用户信息的假的接口 export default [ // 用户登录接口 { url: '/api/user/login', //请求地址 method: 'post', //请求方式 response: ({ body }) => { //获取请求体携带过来的用户名与密码 const { username, password } = body //调用获取用户信息函数,用于判断是否有此用户 const checkUser = createUserList().find((item) => item.username === username && item.password === password) //没有用户返回失败信息 if (!checkUser) { return { code: 201, data: { message: '账号或者密码不正确' } } } //如果有返回成功信息 const { token } = checkUser return { code: 200, data: { token } } } }, // 获取用户信息 { url: '/api/user/info', method: 'get', response: (request) => { //获取请求头携带token const token = request.headers.token //查看用户信息是否包含有次token用户 const checkUser = createUserList().find((item) => item.token === token) //没有返回失败的信息 if (!checkUser) { return { code: 201, data: { message: '获取用户信息失败' } } } //如果有返回成功信息 return { code: 200, data: { checkUser } } } } ] ``` ### axios ``` pnpm install axios ``` #### 二次封装 ``` import axios from 'axios' const request = axios.create({ baseURL: '/api', //import.meta.env.VITE_APP_BASE_API, // /api vite.config.ts 配置代理服务器后不需要 timeout: 5000 }) // 请求拦截器 request.interceptors.request.use((config) => { // config.headers 设置 Token // 请求头增加token认证 const userStore = useUserStore() if (userStore.userInfo.token) { config.headers.Authorization = userStore.userInfo.token } return config }) // 响应拦截器 request.interceptors.response.use( (response) => { // 成功的回调 简化数据 console.log('res:', response) return response }, (error) => { console.log(error) // 失败的回调 处理http网络错误 let message = '' const status = error.status switch (status) { case 401: message = 'Token过期' break case 403: message = '无权访问' break case 404: message = '请求参数错误' break case 500: message = '服务器故障' break default: message = '网络故障' break } ElMessage.error(message) return Promise.reject(error) } ) // 路由前置守卫 router.beforeEach((to, from, next) => { if (to.matched.some((r) => r.meta?.requiresAuth)) { const userStore = useUserStore() if (!userStore.userInfo.token) { next({ name: 'login', query: { redirect: to.fullPath } }) return } } next() }) // 路由全局守卫 登录后 就不可以再进入login页 进度条功能 export default request ``` #### 代理服务器配置 ``` // vite.config.ts import { defineConfig, loadEnv } from 'vite' server: { proxy: { '/api': { // target: 'http://127.0.0.1:8000', // '' 代表读 .env 文件的各环境都用的配置 development 开发环境的配置 target: loadEnv('development', process.cwd()).VITE_API_SERVE, // 获取环境变量 读取env文件 VITE_API_URL的值 changeOrigin: true // rewrite: (path) => path.replace(/^\/api/, '') } } } ``` ### 系统参数配置 1.src/setting.ts ``` //用于项目logo|标题配置 export default { title: '硅谷甄选运营平台', //项目的标题 logo: '/logo.png', //项目logo设置 logoHidden: true //logo组件是否隐藏设置 } ``` ``` import setting from '@/setting' ``` 2. layout/collapse.ts ``` export const isCollapse = ref(false) // 左侧菜单栏折叠控制参数 ``` ``` import { isCollapse } from './collapse' ``` ``` ``` ## 动态递归菜单 routers.ts 基本格式 ``` //对外暴露配置路由(常量路由):全部用户都可以访问到的路由 export const constantRoute = [ { //登录 path: '/login', component: () => import('@/views/login/index.vue'), name: 'login', meta: { requiresAuth: true, // 路由前置守卫 鉴权 title: '登录', //菜单标题 hidden: true, //代表路由标题在菜单中是否隐藏 true:隐藏 false:不隐藏 icon: 'Promotion' //菜单文字左侧的图标,支持element-plus全部图标 }, children: [ { path: '/home', component: () => import('@/views/home/index.vue'), meta: { title: '首页', hidden: false, icon: 'HomeFilled' } } ... ] }, ... ] ``` ``` import { constantRoute } from '@/router/routes' import type { RouteRecordRaw } from 'vue-router' // 菜单列表 pinia store中 const menuRoutes: RouteRecordRaw[] = constantRoute ``` cMenu 菜单递归组件 递归组件需要命名 ``` // 递归组件需要命名 ``` ### 全局图标组件注册,给动态菜单使用图标 先安装element 图标 ``` // ... import 其他需要注册的组件 import * as ElementPlusIconsVue from '@element-plus/icons-vue' export default { install(app: any) { // 注册Element全部图标组件 递归动态菜单使用 for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } } } ``` ## 全屏状态切换 ``` // 全屏 切换 const fullScreen = () => { // 获取全屏状态属性, true:全屏,false:不是全屏 let fullState = document.fullscreenElement // 为 谷歌浏览器,其他浏览器会不同 if (fullState) { // 退出全屏 document.exitFullscreen() isCollapse.value = false } else { // 切换为全屏状态 document.documentElement.requestFullscreen() isCollapse.value = true } } ``` ## 主屏幕区域刷新 ``` ``` ``` import { isRefresh } from './collapse' // 标志 控制main区域组件销毁重建 以刷新数据 const flag = ref(true) // 监听 刷新标志变化,nextTick()监听Dom变化完成后重新显示Dom watch( () => isRefresh.value, () => { flag.value = false nextTick(() => { flag.value = true }) } ) ``` ## 页面加载进度条 npm install nprogress ``` import nprogress from 'nprogress' import 'nprogress/nprogress.css' // 路由前置守卫 router.beforeEach((to, from, next) => { nprogress.start() next() }) // 路由后置守卫 router.afterEach((to, from) => { nprogress.done() }) ```