一、Vue3
1 基础配置
1.1 @
路径别名
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入path,node提供的模块,可以获取文件或文件夹的路径
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve('./src')
}
}
})
tsconfig.json
{
"compilerOptions": {
// 配置路径别名
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}
1.2 SCSS
全局变量
vite.config.ts
export default defineConfig({
// scss全局变量一个配置
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData: '@import "./src/styles/variable.scss";',
},
},
},
})
1.3 SVG
使用方式
vite.config.ts
// 配置svg:引入插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig({
plugins: [
createSvgIconsPlugin({
// 配置svg:指定svg资源目录
iconDirs: [path.resolve(process.cwd(), 'src/asstes/icons')],
// 配置svg:指定svg资源name
symbolId: 'icon-[dir]-[name]'
})
]
}
main.ts
// svg插件需要配置代码
import 'virtual:svg-icons-register'
使用
<svg style="width:30px; height:30px">
<use xlink:href="#icon-xxx" fill="red"></use>
</svg>
1.4 SVG
全局组件
<svg-icon name="home" color="pihk"></svg-icon>
<!-- @/components/SvgIcon/index.vue -->
<template>
<svg :style="{width, height}">
<use :xlink:href="prefix + name"></use>
</svg>
</template>
<script setup>
import { ref } from 'vue';
const prefix = ref('#icon-')
defineProps({
// 名字
name: String,
// 颜色
color:{
type: String,
defaule: ''
},
// 宽高
width: {
type: String,
default: '20px'
},
height: {
type: String,
default: '20px'
}
})
</script>
-
1、单独引入注册
main.ts
import SvgIcon from '@/components/SvgIcon/index.vue' app.components('SvgIcon', SvgIcon)
-
2、插件注册,引入
components
下组件遍历注册@/components/index.ts
import SvgIcon from './SvgIcon/index.vue' const allGloablComponent = { SvgIcon } export default{ install(app){ Object.keys(allGloablComponent).forEach(key => { app.component(key, allGloablComponent[key]) }) } }
main.ts
//引入自定义插件对象:注册整个项目全局组件 import gloalComponent from '@/components' //安装自定义插件 app.use(gloalComponent)
1.5 EL
全局图标
@/components/index.ts
// 引入全部elmentPlus的图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const allGloablComponent = { SvgIcon }
export default{
install(app){
// 将element-plus的图标全部注册
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
}
}
main.ts
// 引入自定义插件对象:注册整个项目全局组件
import gloalComponent from '@/components'
// 安装自定义插件
app.use(gloalComponent)
使用方式
<el-icon> </Edit> </el-icon>
<el-icon> <component is="Edit"> </el-icon>
2 vue-router路由
2.1 路由跳转
-
编程式导航
<script setup lang="ts"> import { useRouter } from 'vue-router'; const $router = useRouter() const toRoutes = (path) => { $router.push(path) } </script>
2.2 路由过度
<template>
<router-view v-slot="{ Component }">
<transition name="fade">
<component :is="Component" />
</transition>
</router-view>
</template>
<script setup lang="ts"> </script>
<style lang="scss" scoped>
// 此为vue3写法,与vue2类名略有不同,根据需求自定义过渡动画
.fade-enter-from {
opacity: 0;
transform: scale(0);
}
.fade-enter-active {
transition: all .3s;
}
.fade-enter-to {
opacity: 1;
transform: scale(1);
}
</style>
2.3 路由鉴权
项目当中的各个路由在什么条件下可以访问,什么条件下不可以访问
2.3 element-plus
组件
2.3.1 Menu
菜单折叠图标
问题:在使用 el-menu
菜单的折叠功能时,因为自定义路由和Menu组件,导致图标没有正常显示
解决:将图标组件移出 template
外边
<el-menu-item >
<template #title>
<el-icon> <component :is="meta.icon"></component> </el-icon>
<span>{{item.children[0].meta.title}}</span>
</template>
</el-menu-item>
<el-menu-item >
<el-icon> <component :is="item.meta.icon"></component> </el-icon>
<template #title>
<span>{{item.meta.title}}</span>
</template>
</el-menu-item>
2.3.2 Menu刷新默认菜单
问题:使用 el-menu
菜单在页面刷新时,已展开的菜单会关闭,
解决:配置 el-menu
的 default-active
属性,通过 router
将页面路径赋值给他
备注: route
获取页面路径, router
页面跳转,现 $route
以改为宏函数,可以直接在 template
使用,无需引入,若想在 script
中使用,还是得引入
<el-menu :default-active="$route.path"></el-menu>
import { useRoute } from 'vue-router'
$route = useRoute()
3 父子组件交互
3.1 defineEmits
vue3
内置 defineEmits
和 definProps
可无需引入直接使用
// son.vue
let $emit = defineEmits(['fn1', 'fn2', ...])
const updata = () => {
$emit('fn1', { name: '张三', age: '23' })
}
// father.vue
<son @fn1="fn1"></son>
const fn1 = (name='', age='') => { ... }
3.2 definProps
// father.vue
<son :name="name" :data="data"></son>
// son.vue
let props = defineProps({
name: {
type: String,
default: ''
},
data:{
type:Object,
default:() => ({ ... })
}
})
// 或
defineProps({
name:{
type:String,
default:''
},
data:{
type:Object,
default:() => ({ ... })
}
})
3.3 ref
// father.vue
<son ref="son"/>
let son = ref(null)
const fn = () => {
son.value.fnSon
}
// son.vue
const fnSon = () => {
// ...
}
defineExpose({ fnSon })
二、TypeScript
1 类型定义
-
@/api/user/index.js
import request from '@/utils/request' import type { loginFormData, loginResponseData, userInfoReponseData, } from './type' enum API { // 登录 LOGIN_URL = '/admin/acl/index/login', // 用户信息 USERINFO_URL = '/admin/acl/index/info', // 退出登录 LOGOUT_URL = '/admin/acl/index/logout', } // 登录接口 export const reqLogin = (data: loginFormData) => request.post<any, loginResponseData>(API.LOGIN_URL, data) // 获取用户信息 export const reqUserInfo = () => request.get<any, userInfoReponseData>(API.USERINFO_URL) // 退出登录 export const reqLogout = () => request.post<any, any>(API.LOGOUT_URL)
-
@/api/user/type.ts
// 请求携带参数类型 export interface loginFormData { username: string, password: string } // 基础接口返回数据类型 export interface Response { code: number|string, message?: string, ok?: boolean } // 登录接口 返回数据类型 export interface loginResponseData extends Response { data: string } // 用户信息接口 返回数据类型 export interface userInfoReponseData extends Response { data: { routes: string[] buttons: string[] roles: string[] name: string avatar: string } }
三、JavaScrpt
1 对象数组过滤对象
let objectsArray = [
{ a: 1, b: 'one' },
{ a: 2, b: 'two' },
{ a: 3, b: 'three' },
{ a: 2, b: 'anotherTwo' }
];
let valueToRemove = 2; // 这是你想从对象中过滤掉的属性 a 的值
objectsArray = objectsArray.filter(obj => obj.a !== valueToRemove);
console.log(objectsArray);
// 输出: [ { a: 1, b: 'one' }, { a: 3, b: 'three' } ]
2 对象数组的对象的属性名修改
imgList = res.data.map(item => {
return{
name: item.imgName,
url: item.imgUrl
}
})
3 Object.assign
Object.assign()
将所有可枚举的属性的值从一个或多个源对象复制到目标对象(第一个参数),具有相同属性的话,会按顺序进行覆盖,并返回目标对象
let a = reactive({ x: 1, y: 2 })
let b = { y: 3, z: 4 }
let c = { z: 3 }
let newA = Object.assign(a, b, c)
console.log(a, a===newA) // { x: 1, y: 3, z: 3 } true
// 在vue3中,如使用解构赋值的方法,会产生新的对象,会导致失去数据代理
a = {...a, ...b, ...c}
4 request.ts
@/utils/request.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'
//引入用户相关的仓库
import useUserStore from '@/store/modules/user'
const request = axios.create({
//基础路径(在项目根目录下设置)
baseURL: import.meta.env.VITE_APP_BASE_API,
//超时的时间的设置
timeout: 5000,
})
// 请求拦截器
request.interceptors.request.use((config) => {
if(useUserStore().token){
config.headers.token = useUserStore().token
}
return config
})
// 响应拦截器
request.interceptors.response.use(
(response) => {
// 成功回调,简化数据
return response.data
},
(error) => {
// 失败回调:处理http网络错误
let message = ''
// http状态码
const status = error.response.status
switch (status) {
case 401:
message = 'TOKEN过期'
break
case 403:
message = '无权访问'
break
case 404:
message = '请求地址错误'
break
case 500:
message = '服务器出现问题'
break
default:
message = '网络出现问题'
break
}
//提示错误信息
ElMessage({
type: 'error',
message,
})
return Promise.reject(error)
},
)
export default request
四、业务实现
-
左侧菜单缩放通过仓库变量(true/false)进行管理
-
刷新:通过
v-if
、nextTick
、仓库
实现刷新(销毁重建) -
全屏状态:通过
document.fullscreenElement
设置全屏状态 -
自动刷新:
window.location.reload()
,用户修改自身账号或密码之后,调用方法自动刷新 -
展示角色权限:例,后端返回全部权限,其中该角色拥有的权限的
select:true
,修改时需要把新的权限对象给后端(父级的id和权限值 + 子级的id和权限值 + …),<el-tree>
提供获取选中的节点的数组,修改完调用刷新方法一级 二级 三级 四级 1、全部数据 1.1、权限管理 1.1.1、用户管理 1.1.1.1、添加用户 1.1.1.2、删除用户 1.1.1.3、修改用户 1.1.2、菜单管理 1.2、商品管理 { "id": 1, "name": "全部数据", "level": 1, "children": [ { "id": 7, "name": "权限管理", "level": 2, "children": [ { "id": 8, "name": "用户管理", "level": 3, "children": [ { "id": 11, "name": "添加用户", "level": 4, "children": [], "select": false }, { "id": 12, "name": "删除用户", "level": 4, "children": [], "select": false } ], "select": false }, { "id": 10, "name": "菜单管理", "level": 3, "children": [], "select": false } ], "select": false } ], "select": true }
const setPermisstion = async (id) => { let result = await reqAllMenuList(id); if (result.code == 200) { // 全部权限 menuArr.value = result.data; // 拥有的权限 selectArr.value = filterSelectArr(menuArr.value, []); } } const filterSelectArr = (allData, initArr) => { allData.forEach((item) => { // 如最后一级的权限的是第四级(遍历完其最低级的权限,即可通过<el-tree>自动判断) if (item.select && item.level == 4) { initArr.push(item.id); } if (item.children && item.children.length > 0) { filterSelectArr(item.children, initArr); } }) return initArr; }
五、备注
-
在平时写代码的时候,为实现某个功能,感觉自己写的代码很冗余,可以试试将代码交于
ai
,让其优化一下,说不定JS官方
已经提供了便捷语法糖(如:ES6+新增的语法糖),或者AI
有更加便捷的实现思路 -
背景图片
.contaiter{ background: url('@/xxx/xxx.jpg') no-repeat; backgorund-size: cover; }