vue3+ts
水平一般,还在学习阶段,主要是记录一些自己使用不怎么熟练的,欢迎指导与讨论。
nextTick
使用场景:layout中main组件,进行刷新时重新获取路由发送请求,策略为销毁路由再重新创建,不使用定时器时因为不能明确路由何时被销毁。
<template>
<!-- 路由组件出口的位置-->
<router-view v-slot="{ Component }">
<transition name="fade">
<!-- 渲染layout一级路由的子路由 -->
<component :is="Component" v-if="mainFLag"></component>
</transition>
</router-view>
</template>
<script setup lang="ts">
import useLayoutSettingStore from "@/store/modules/setting.ts";
import {watch, ref, nextTick} from "vue";
let useLayoutStore = useLayoutSettingStore()
let mainFLag = ref(true)
watch(() => useLayoutStore.refresh, () => {
// 先销毁路由组件的dom
mainFLag.value = false
// 使用nextTick保证路由组件销毁后再创建而不是延时器
nextTick(() => {
mainFLag.value = true
})
})
</script>
暗黑模式与主题颜色的切换
看element-plus官方文档即可,main.ts引入相应样式文件,获取根节点元素添加dark属性即可。
对于暗黑模式,如果有设置颜色的样式应该是不起作用的。(所以如果出现部分黑色但其他未发生拜年话的情况,可以检查一下是否已设置color属性)
const changeColor = () => {
const html = document.documentElement
html.style.setProperty('--el-color-primary',color.value)
}
// 暗黑模式开关
let dark = ref(false)
const changeDark = () => {
// 获取根节点,加上一个dark属性即可
let html = document.documentElement
dark.value ? html.className = 'dark' : html.className = ''
}
数据大屏
重点是屏幕大小的适配
两种解决思路:第一种:vw,vh;第二种:scale
对于第一种需要进行相应数值的计算,例如父组件100vh对应1920px,如果子组件设计稿高度为192px,那么应该设置为10vh。
第二种无需计算,但是要注意scale的缩放是以最近一层父组件的中心位置进行缩放,所以要注意嵌套的关系来确定缩放的中心;需要解决留白问题
一些组件使用
el-tree:一定注意是 :props 组件label一直没渲染出来,找了好久的bug
<el-tree
ref="menuTree"
:data="menuArr"
show-checkbox
node-key="id"
:default-checked-keys="selectPermissionArr"
:props="defaultProps"
/>
// 递归将所选数据存入数组
const filterSelectArr = (allData: any, initArr: any) => {
allData.forEach((item: any) => {
if (item.select && item.level === 4) {
initArr.push(item.id)
}
if (item.children && item.children.length > 0 && item.select ) {
filterSelectArr(item.children, initArr)
}
})
return initArr
}
路由的使用(配置注意数组还是对象的形式)
this.menuRoutes = [...constantRoutes, ...userAsyncRoute, ...anyRoute]解析代码:
这行代码是在定义一个名为menuRoutes
的变量,并将其赋值为一个由三个数组合并而成的新数组。这三个数组分别是constantRoutes
、userAsyncRoute
和anyRoute
。
constantRoutes
、userAsyncRoute
和anyRoute
是预先定义好的数组,它们可能包含一些路由配置对象。通过使用[...]
语法,这些数组的元素会被展开并合并到一个新数组中。
最终,menuRoutes
将成为一个包含了三个数组中所有元素的新数组。
this.menuRoutes = [...constantRoutes, ...userAsyncRoute, anyRoute解析代码:
这行代码有一个细微的差别,最后一个数组anyRoute
没有使用展开操作符[...]
。因此,anyRoute
将被当作一个单独的元素添加到menuRoutes
数组中。
所以,menuRoutes
将会包含constantRoutes
和userAsyncRoute
数组中的元素,以及anyRoute
作为一个单独的元素。最终,menuRoutes
将成为一个新数组,包含了这些元素。
异步路由加载白屏
本项目采用的路由首先存储管理常量路由,每个用户分配的异步路由是动态追加的,因此可能出现的问题是:在异步路由处刷新,虽然可能获取到用户信息,但异步路由还没有加载完毕即出现空白效果.。
解决方案:保证路由加载完成再放行。
await userStore.userInfo()
next({ ...to })
自定义指令
指令可以做哪些事情
- 操作渲染dom,比如vFocus、vMyHtml、数据格式转换
- 图片懒加载
- 上拉加载更多
- 下拉刷新
- ......
本项目中有一个控制按钮权限(按钮dom渲染)的实例:
入口文件注册:
// 引入自定义指令
import {isHasButton} from "@/directives/has.ts";
isHasButton(app)
app.mount('#app')
编写指令:
import pinia from '@/store'
import useUserStore from "@/store/modules/user.ts";
let useStore = useUserStore(pinia)
export const isHasButton = (app:any) => {
// 获取对应的用户仓库
app.directive('has', {
//使用这个指令的dom组件在挂载完毕时会执行一次
mounted(el:any, binding:any) {
// 若用户信息中没有buttons就会禁用
console.log(binding.value)
if(!useStore.buttons.includes(binding.value)){
el.parentNode.removeChild(el)
}
}
} )
}
使用:
<el-button @click="addDialog" v-has="`has`">新增用户</el-button>