npm install less vue-router element-plus -s
elementplus
路由引入组件第二种写法:
使用动态的import( )语法(推荐使用)(路由懒加载)
component:()=>import('路径')
component:()=>import('@/views/Main.vue')
打包之后的文件将会异常的大,需要加载的内容过多时间过长,出现长时间的白屏,不利于用户体验,运用懒加载就可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时。
filter函数
filter用于对数组进行过滤。
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
const hasChildren=computed(()=>list.filter(item=>item.children));
过滤掉没有children的数组元素
v-if和v-for
vue2中v-for优先;vue3中v-if优先
is
component组件是一个动态组件,跟随:is里的变量动态显示加载组件
使用场景:适用于组件会动态变化的场景,如新闻类型可能是视频、图片、文字,在遍历渲染新闻列表时,根据新闻类型的不同,渲染不同的组件。
<component class="icons" :is="item.icon">
</component>
new URL()
mokejs
生成随机数据,拦截 Ajax 请求
mokejs官网
getCurrentInstance()
在Vue3中,getCurrentInstance()可以用来获取当前组件实例
let { proxy } = getCurrentInstance();
getCurrentInstance只能在setup或生命周期钩子中使用。
1.在onMunted生命周期中打印getCurrentInstance
2.定义一个test方法,通过click事件触发方法
封装axios
- 拦截器
api/request.js
import axios from "axios";
import {} from 'element-plus';
const server=axios.create();
// 添加请求拦截器
server.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
server.interceptors.response.use(
(res)=>{
const {code,data,msg}=res.data;
if(code===200){
return data;
}else{
const NETWORK_ERROR="网络错误,请稍后重试";
ElMessage.error(msg|| NETWORK_ERROR);
return Promise.reject(new Error(msg|| NETWORK_ERROR));
}
}
);
function request(options){
options.method=options.method||"get";
return server(options);
}
export default request;
- 统一管理axios
api/api.js
// 整个项目api的统一管理
import request from "./request";
export default {
// 获取首页左侧的表格数据
getTableData(){
return request({
url:"/api/home/getTableData",
method:"get"
})
},
};
- main.ts配置全局api
import api from './api/api';
// 全局api
app.config.globalProperties.$api = api;
- 使用
import {unMounted,getCurrentInstance} from 'vue'
const {proxy} = getCurrentInstance();
const getTableData=()=>{
const data = proxy.$api.getTableData();
tableData.value=data.tableData;
}
echarts
生成图表
安装: npm install echarts -D
文档
Object.keys()
- 遍历对象(必须包含属性和方法的对象);
- 返回对象中每一项key的数组(遍历一个对象,返回一个全是key的数组)
用法:1.如果对象是一个对象,会返回对象的属性名组成的数组;
Object.keys()
let obj={a:1, b:2, c:3}
Object.keys(obj) // ['a', 'b', 'c']
2.如果对象是一个数组或字符串,则返回索引组成的数组
Object.values()和Object.keys() 相反
map
返回值错误:
返回的是{}里面的的值,不是[{},{},{}];
2.正确写法:
监听图表页面
const observer=ref();
// 监听页面的变化
observer.value=new ResizeObserver(()=>{
oneEchart.resize();
twoEchart.resize();
threeEchart.resize();
});
if(proxy.$refs.echart){
observer.value.observe(proxy.$refs.echart);
}
搜索功能
分页
scope.row
confirm、alert、prompt
element plus
nextTick
问题:点击编辑后,再点击添加用户后表单里的信息变成了编辑用户的信息(本来是没有值的)
原因:
// 编辑
const handleEdit=(val)=>{
dialogFormVisible.value = true;
action.value=1;
// 赋值(表单的值设置为当前行的值)
// 当dialogFormVisible.value = true后弹出对话框表单才会出现,(表单在对话框里)
// 异步非常快,会把Object.assign(form,{...val,addr:val.address})当成初始值
//导致关闭对话框再次打开后显示Object.assign(form,{...val,addr:val.address})的值
Object.assign(form,{...val,addr:val.address})
}
解决方式1:
nextTick(()=>{//不要忘记先引入nextTick
Object.assign(form,{...val,addr:val.address})
})
解决方式2:
setTimeout(()=>{
Object.assign(form,{...val,addr:val.address})
},100)
useRouter和useRoute
router.push
json.stringfy和json.parmars
vite的glob
动态生成路由
// 动态生成路由
function addMenu(router){
const menuList=state.value.menuList;//根据登陆身份拿到对应的菜单列表
const module=import.meta.glob("../views/**/*.vue");//批量
const routeArr=[];
menuList.forEach(item=>{
if(item.children){
item.children.forEach(val=>{
let url=`../views/${val.url}.vue`;
val.component=module[url];
routeArr.push(val);
});
}else{
let url=`../views/${item.url}.vue`;
item.component=module[url];
routeArr.push(item);
}
})
routeArr.forEach(item=>{
state.value.routerList.push(router.addRoute("main",item));
});
};
glob
多账号登陆问题
不是管理员账号,但能访问到mall页面
// 动态生成路由
function addMenu(router){
const menuList=state.value.menuList;//根据登陆身份拿到对应的菜单列表
const module=import.meta.glob("../views/**/*.vue");//批量
const routeArr=[];
menuList.forEach(item=>{
if(item.children){
item.children.forEach(val=>{
let url=`../views/${val.url}.vue`;
val.component=module[url];
routeArr.push(val);
});
}else{
let url=`../views/${item.url}.vue`;
item.component=module[url];
routeArr.push(item);
}
});
// 解决多种账号登陆bug
state.value.routerList=[];
let routes=router.getRoutes();//拿到所有路由
routes.forEach(val=>{
if(val.name==='main'||val.name==='login'){
return //不做处理
}else{
router.removeRoute(val.name);
}
});
routeArr.forEach(item=>{
state.value.routerList.push(router.addRoute("main",item));
});
};
解决登录后刷新页面消失的路由问题
对pinia的stores/index.js下的state进行持续化存储
// state持久化存储
watch(state,(newObj)=>{
if(!newObj.token) return ;
localStorage.setItem("store",JSON.stringify(newObj));
},{deep:true})
main.js
import router from './router/index';
import { useAllDataStore } from './stores';
const store = useAllDataStore();//放到app.use(pinia)后
store.addMenu(router,"refresh")//传递路由并传类别//这一步要在使用路由前
app.use(router)
退出登录
const handleLoginOut=()=>{
store.clean()
router.push('/login');
}
stores/index.js
export const useAllDataStore = defineStore("allData",()=>{
/****/
function clean(){
state.value.routerList.forEach(item=>{
if(item) item();//删除(console.log(item)后得到是一个removeRoute删除路由)
});
// 重置
state.value=initState();
// 删除本地缓存
localStorage.removeItem("store");
}
/*****/
return {state,updateMenuList,addMenu,clean}
})
路由守卫
// 路由守卫
function isRoute(to){
let res=router.getRoutes();
let resFil=res.filter(item=>item.path===to.path);//拿到要去往的路由
return resFil.length>0;//判断是否在路由列表中
}
router.beforeEach((to,from)=>{
if(to.path!=='/login'&&!store.state.token){
// next('/login');
return {name:'login'}
}
if(!isRoute(to)){
// next('/404');
return {name:'404'}
}
})