# 贾成豪硅谷甄选平台
**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'
{{ setting.title }}
```
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 菜单递归组件 递归组件需要命名
```
// 递归组件需要命名
{{ item.meta.title }}
{{ item.children[0].meta.title }}
{{ item.meta.title }}
```
### 全局图标组件注册,给动态菜单使用图标
先安装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()
})
```