分享缩略图

分享到:
链接已复制
首页> 新闻中心>

Vue3项目实战(vue3+vite+pinia+element

2025-06-24 11:41:52

来源:新华网

字体:

许苑后台管理系统

  • 一、项目介绍
    • 1、技术栈
    • 2、业务功能
    • 3、应用场景
    • 4、项目源码
  • 二、项目实战
    • 2.1、项目初始化
    • 2.2、项目实战
      • 1、引入router配置
      • 2、App.vue组件引入
      • 3、创建RootView根路由组件
      • 4、依次创建
      • 5、进行对应各个环境的配置环境设置

一、项目介绍

在这里插入图片描述

1、技术栈

  • vue3+vite+vue-router
  • pinia
  • element-plus
  • axios
  • mock
  • Echarts

2、业务功能

  • 登录
  • 首页
  • 商品
  • 用户管理

3、应用场景

  • 进行后台管理项目的
  • 根据不同用户的权限授予不同的功能

4、项目源码

xuyuan-upward 希望每位大佬获取时候点个小小的赞!

二、项目实战

2.1、项目初始化

1、构建项目

# npm 7+,需要添加额外的 --:npm create vite@latest my-vue-app -- --template vue

2、安装成功后进行安装依赖

npm install 

3、修改路径替代符

import{ defineConfig }from'vite'importvue from'@vitejs/plugin-vue'// https://vite.dev/config/exportdefaultdefineConfig({ plugins:[vue()],/* 添加的是别名 */resolve:{ alias:{ '@':'/src',},},})

4、引入element-plus依赖,axios,router
安装依赖内容过于简单,请自行取相关内容官网查看文档进行安装
element-plus官网
axios官网
router

2.2、项目实战

1、引入router配置

import{ createRouter,createWebHashHistory,createWebHistory }from'vue-router'constroutes =[{ path:'/',name:'main',component:()=>import('@/views/RootView.vue'),redirect:'/home',/* 访问 /home 时的行为当你访问 /home 时,会发生以下情况:匹配父路由:首先匹配到 path: '/' 的路由配置。由于 Main.vue 是父组件,它会被渲染。匹配子路由:在 Main.vue 内部的  中,会匹配到 path: '/home' 的子路由。因此,Home.vue 会在 Main.vue 的  中渲染。 */children:[{ path:'/home',name:'home',component:()=>import('@/views/MainView.vue')},]},]constrouter =createRouter({ history:createWebHistory(),routes})exportdefaultrouter

接着还需要导入main.js一些配置文件

  • 全局样式
  • pinia等等
import{ createApp }from'vue'importApp from'./App.vue'// 导入全局样式import"@/assets/less/index.less"importrouter from'@/router'importElementPlus from'element-plus'// 导入element-plus组件的全局样式import'element-plus/dist/index.css'import*asElementPlusIconsVue from'@element-plus/icons-vue'import{ createPinia }from'pinia'import{ useAllDataStore }from'@/stores'/* 引入mock */import"@/apis/mock.js"/* 引入apis 管理请求接口 */importapis from"@/apis/apis.js"constpinia =createPinia()constapp =createApp(App)/* 定义全局配置使用 */app.config.globalProperties.$apis =apisapp.use(ElementPlus)app.use(pinia)// localStorage.removeItem("store")conststore =useAllDataStore()store.addRoutes(router,"refresh")app.use(router)/*function isRoute(to) {     let routes = router.getRoutes()    console.log("routes", routes);    let resFil = routes.filter(item =>        /* 相当于return */item.path ===to.path    )/*  let resFil = routes.filter(item => {       相当于一段代码,只有return为true时候才会保留对应的数据     item.path === to.path}            ) */returnresFil}/*router.beforeEach((to, from, next) => {     console.log("store.state.token", store.state.token);    if (!store.state.token && to.path !== '/login') {         console.log("to.path1", to.path);        next({  name: 'login' })    }    if (store.state.token && to.path === '/login') {         console.log("to.path2", to.path);        next({  name: 'home' })    }    if (store.state.token && to.path !== '/login') {         console.log("to.path3", to.path);        console.log("isRoute", isRoute(to));        if (isRoute(to).length === 0) {             console.log("to.path3", to.path);            next({  name: '404' })        }    }    console.log("to.path4", to.path);    next()})*/for(const[key,component]ofObject.entries(ElementPlusIconsVue)){ app.component(key,component)}app.mount('#app')

2、App.vue组件引入

<scriptsetup>script><template><divclass="app"><router-view/>div>template><style>#app,.app{ width:100%;height:100%;overflow:hidden;}style>

3、创建RootView根路由组件

<template><divclass="common-layout"><el-containerclass="main-container"><divclass="aside-container"><CommonAside/>div><el-containerclass="right-container"><el-headerstyle="height:40px;"><CommonHeader/>el-header><el-dividerstyle="margin:5px 0;"/><CommonTab/><el-main><router-view/>el-main><el-footer><Footer/>el-footer>el-container>el-container>div>template><scriptsetup>import{ reactive,toRefs,onMounted,nextTick }from'vue'importCommonAside from'@/components/CommonAside.vue';importCommonHeader from'@/components/CommonHeader.vue';importCommonTab from'@/components/CommonTab.vue';importFooter from'@/components/Footer.vue';script><stylelang='less'scoped>.common-layout,.main-container,right-container{ height:100%;background-color:#f0f2f5;  .el-main{ padding:8px;}}style>

4、依次创建

三个普通组件 CommonAside CommonHeader Footer 以及每个页面的路由组件 router-view

  • CommonAside.vue
<template><el-aside:width="width"><el-menutext-color="#fff"background-color="#545c64":collapse="isCollapse":collapse-transition="false":default-active="activeMenu"class="el-menu-vertical-demo"><divclass="title"><iclass="iconfont icon-quanpingtai">i><h4v-show="!isCollapse">许苑后台管理h4>div><el-menu-itemv-for="item in noChildren":key="item.path":index="item.path"@click="handleMenu(item)"><component:is="item.icon"class="icon"/><spanstyle="margin-left:10px">{ {  item.label }}span>el-menu-item><el-sub-menuv-for="item in hasChildren":key="item.path":index="item.path"><template#title><component:is="item.icon"class="icon"/><spanstyle="margin-left:10px">{ {  item.label }}span>template><el-menu-item-group><el-menu-itemv-for="(subItem) in item.children":index="subItem.path":key="subItem.path"><component:is="subItem.icon"class="icon"/><span>{ {  subItem.label }}span>el-menu-item>el-menu-item-group>el-sub-menu>el-menu>el-aside>template><scriptsetup>import{ ref,reactive,toRefs,onMounted,nextTick,computed }from'vue'import{ useRouter,useRoute }from'vue-router'import{ useAllDataStore }from'@/stores'conststore =useAllDataStore()constrouter =useRouter()constroute =useRoute()// 测试数据,初始化,刚开始可以使用,后续通过配置路由权限获取/* const list = ref([    {         path: '/home',        name: 'home',        label: '首页',        icon: 'house',        url: 'Home'    },    {         path: '/mall',        name: 'mall',        label: '商品管理',        icon: 'ShoppingBag',        url: 'Mall'    },    {         path: '/user',        name: 'user',        label: '用户管理',        icon: 'user',        url: 'User'    },    {         path: 'other',        label: '其他',        icon: 'location',        children: [            {                 path: '/page1',                name: 'page1',                label: '页面1',                icon: 'setting',                url: 'Page1'            },            {                 path: '/page2',                name: 'page2',                label: '页面2',                icon: 'setting',                url: 'Page2'            }        ]    }]) */constlist =computed(()=>store.state.menuList)constnoChildren =computed(()=>list.value.filter(item=>!item.children))consthasChildren =computed(()=>list.value.filter(item=>item.children))constwidth =computed(()=>store.state.isCollapse ?'60px':'200px')// 涉及组件之间的传递 => 使用pinia进行各组件之间的传递constisCollapse =computed(()=>store.state.isCollapse)constactiveMenu =computed(()=>route.path)consthandleMenu=(item)=>{ if(item.children){ return}router.push(item.path)store.selectMenu(item)}script><stylelang='less'scoped>.icon{ width:18px;height:18px;margin-right:5px;}.el-aside{ background-color:#545c64;height:100vh;    .el-menu{ border-right:none;        .title{ display:flex;align-items:center;justify-content:center;}h4{ color:#fff;font-size:17px;margin:20px;font-weight:500px;text-align:center;}}}style>
  • CommonHeader.vue
<template><divclass="header"><divclass="l-header"><el-buttonsize="small"@click="store.state.isCollapse = !store.state.isCollapse"><el-icon><Menu/>el-icon>el-button>div><divclass="r-header"><el-dropdown><spanclass="el-dropdown-link"><imgsrc="@/assets/images/xuyuan.jpg"alt=""class="r-header-avatar">span><template#dropdown><el-dropdown-menu><el-dropdown-item>个人中心el-dropdown-item><el-dropdown-item@click="handlerLogout">退出登录el-dropdown-item>el-dropdown-menu>template>el-dropdown>div>div>template><scriptsetup>import{ ref,reactive,toRefs,onMounted,nextTick,computed }from'vue'import{ useAllDataStore }from'@/stores'import{ ArrowRight }from'@element-plus/icons-vue'import{ useRouter }from'vue-router'conststore =useAllDataStore()constrouter =useRouter()letcurrentPath =computed(()=>{ console.log("store.state.currentMenu",store.state.currentMenu);returnstore.state.currentMenu;})consthandlerLogout=()=>{ store.clean()router.push('/login')}script><stylelang='less'scoped>.header{ width:100%;height:100%;display:flex;justify-content:space-between;align-items:center;    .l-header{ display:flex;justify-content:center;align-items:center;        .el-button{ margin-right:15px;}}}.r-header-avatar{ width:30px;height:30px;border-radius:50%;margin-right:10px;}style>
  • Footer.vue
<template><divclass="footer"><ahref="https://github.com/xuyuan-upward"class="toLearn"><span><iclass="iconfont icon-github">i>站长: 许苑向上span>a><ahref="https://blog.csdn.net/a147775"class="toLearn"><span><iclass="iconfont icon-bokeyuan">i>博客: xuyuan-upwardspan>a><ahref="https://user.qzone.qq.com/2517115657/main"class="toLearn"><span><iclass="iconfont icon-shouye">i>联系方式: 许苑向上span>a>div>template><scriptsetup>import{ ref,reactive,toRefs,onMounted,nextTick }from'vue'script><stylelang='less'scoped>.toGithub{ text-decoration:none;font-size:14px;font-weight:bold;padding:10px 0;display:block;text-align:center;border-radius:5px;transition:all 0.3s ease-in-out;}.iconfont{ margin-right:5px;}.footer{ height:100%;display:flex;justify-content:center;    a{ margin-right:40px;color:#00000073;        span{ line-height:60px;}}}style>
  • MainView.vue路由组件
<template><divclass="home"><el-row><el-col:span="7"><divclass="l-user"><el-cardstyle="max-width:480px"shadow="hover"class="user-info"><divclass="user"><imgsrc="@/assets/images/xuyuan.jpg"alt=""style="width:100px;height:100px;border-radius:50%;margin-right:10px;"><divclass="userInfo"><h>adminh><pstyle="margin-top:20px;color:#999;">超级管理员p>div>div><el-divider/><divclass="login-info"><p>上次登录时间:<span>2024-11-18 1:00:00span>p><pstyle="margin-top:10px;">上次登录地点:<span>广西span>p>div>el-card><el-cardstyle="max-width:480px"shadow="hover"class="user-table"><el-table:data="tableData"style="width:100%"><el-table-columnv-for="(val, key) in tableLabel":key="key":prop="key":label="val">el-table-column>el-table>el-card>div>el-col><el-col:span="17"><divclass="r-echart"><divclass="top"><el-cardv-for="(item) in counterData":key="item.name":body-style="{  padding: '20px', display: 'flex'}"shadow="hover"><component:is="item.icon"class="icons":style="{  background: item.color }"/><divclass="detail"><pclass="num">¥{ {  item.value }}p><pclass="txt">¥{ {  item.name }}p>div>el-card>div><divclass="bottom"><divclass="echart-top"><el-cardshadow="hover"><divref="echart"style="height:220px;">div>el-card>div><divclass="echart-bottom"><el-cardshadow="hover"><divref="userEchart"style="height:140px">div>el-card><el-cardshadow="hover"><divref="videoEchart"style="height:140px">div>el-card>div>div>div>el-col>el-row>div>template><scriptsetup>import{ ref,reactive,toRefs,onMounted,nextTick,getCurrentInstance }from'vue'import*asecharts from'echarts';//这个tableData是假数据,等会我们使用axios请求mock数据const{ proxy }=getCurrentInstance()consttableData =ref([])constcounterData =ref([])//observer 接收观察器实例对象constobserver =ref(null)//这个是折线图和柱状图 两个图表共用的公共配置constxOptions =reactive({ // 图例文字颜色textStyle:{ color:"#333",},legend:{ },grid:{ left:"20%",},// 提示框tooltip:{ trigger:"axis",},xAxis:{ type:"category",// 类目轴data:[],axisLine:{ lineStyle:{ color:"#17b3a3",},},axisLabel:{ interval:0,color:"#333",},},yAxis:[{ type:"value",axisLine:{ lineStyle:{ color:"#17b3a3",},},},],color:["#2ec7c9","#b6a2de","#5ab1ef","#ffb980","#d87a80","#8d98b3"],series:[],})constpieOptions =reactive({ tooltip:{ trigger:"item",},legend:{ },color:["#0f78f4","#dd536b","#9462e5","#a6a6a6","#e1bb22","#39c362","#3ed1cf",],series:[]})constgetTableData=async()=>{ constdata =awaitproxy.$apis.getTableData()console.log("home,tableData获取到的数据:",data);tableData.value =data.tableData}constgetCounterData=async()=>{ constdata =awaitproxy.$apis.getCounterData()console.log("home,counterData获取到的数据:",data);counterData.value =data}constgetChartData=async()=>{ // 获取图标信息 ,解构const{ orderData,userData,videoData }=awaitproxy.$apis.getChartData()console.log("home,orderData获取到的数据:",orderData);//对第一个图表的xAxis和series赋值xOptions.xAxis.data =orderData.date    xOptions.series =Object.keys(orderData.data[0]).map(val=>{ return{ name:val,data:orderData.data.map(item=>item[val]),type:"line"}})//one               echarts.init方法初始化ECharts实例,需要传入dom对象constOneEcharts =echarts.init(proxy.$refs["echart"])//setOption方法应用配置对象OneEcharts.setOption(xOptions)//对第二个图表的xAxis和series赋值xOptions.xAxis.data =userData.map((item)=>item.date)xOptions.series =[{ name:"新增用户",data:userData.map((item)=>item.new),type:"bar",},{ name:"活跃用户",data:userData.map((item)=>item.active),type:"bar",}]//twoconstTwoEcharts =echarts.init(proxy.$refs["userEchart"])TwoEcharts.setOption(xOptions)//对第三个图表的series赋值pieOptions.series =[{ data:videoData,type:"pie",},]//threeconstThreeEcharts =echarts.init(proxy.$refs["videoEchart"])ThreeEcharts.setOption(pieOptions);//ResizeObserver 如果监视的容器大小变化,如果改变会执行传递的回调observer.value =newResizeObserver(entries=>{ OneEcharts.resize()TwoEcharts.resize()ThreeEcharts.resize()})//如果这个容器存在if(proxy.$refs["echart"]){ //则调用监视器的observe方法,监视这个容器的大小observer.value.observe(proxy.$refs["echart"]);}}onMounted(()=>{ getTableData()getCounterData()getChartData()console.log(proxy);})consttableLabel =ref({ name:"课程",todayBuy:"今日购买",monthBuy:"本月购买",totalBuy:"总购买",})script><stylelang='less'scoped>.home{ height:100%;overflow:hidden;    .l-user{ .user-info{ .user{ display:flex;align-items:center;                .userInfo{ margin-left:30px;}}.login-info{ p{ font-size:14px;color:#999;                    span{ color:#666;margin-left:30px;}}}}.user-table{ margin-top:50px;}}.r-echart{ .top{ display:flex;justify-content:space-between;flex-wrap:wrap;            .el-card{ width:30%;margin-bottom:10px;margin-left:20px;}.icons{ width:50px;height:50px;border-radius:50%;margin-right:20px;}.detail{ display:flex;flex-direction:column;justify-content:center;                .num{ margin-bottom:10px;}}}.bottom{ margin-left:20px;            .echart-top{ margin-bottom:20px;}.echart-bottom{ display:flex;justify-content:space-between;align-items:center;                .el-card{ width:48%;}}}}}style>
  • UserView.vue组件
<template><divclass="user"><divclass="user-head"><el-buttontype="primary"@click="handleAdd">新增el-button><el-form:inline="true":model="formData"><el-form-itemlabel="请输入"><el-inputplaceholder="请输入姓名"v-model="formData.keyWord">el-input>el-form-item><el-form-item><el-buttontype="primary"@click="handlerSearch">搜索el-button>el-form-item>el-form>div><divclass="user-table"><el-dialogv-model="dialogVisible":title="action == 'add'? '新增用户': '编辑用户'"width="35%":before-close="handleClose"><el-form:inline="true":model="formUser":rules="rules"ref="userForm"><el-row><el-col:span="12"><el-form-itemlabel="姓名"prop="name"><el-inputv-model="formUser.name"placeholder="请输入姓名"/>el-form-item>el-col><el-col:span="12"><el-form-itemlabel="年龄"prop="age"><el-inputv-model.number="formUser.age"placeholder="请输入年龄"/>el-form-item>el-col>el-row><el-row><el-col:span="12"><el-form-itemlabel="性别"prop="sex"style="width:80%;"><el-selectv-model="formUser.sex"placeholder="请选择"class="select-clean"><el-optionlabel="":value="1"/><el-optionlabel="":value="0"/>el-select>el-form-item>el-col><el-col:span="12"><el-form-itemlabel="出生日期"prop="birth"><el-date-pickerv-model="formUser.birth"type="date"placeholder="请输入"style="width:100%"/>el-form-item>el-col>el-row><el-row><el-form-itemlabel="地址"prop="addr"><el-inputv-model="formUser.addr"placeholder="请输入地址"/>el-form-item>el-row><el-rowstyle="justify-content:flex-end"><el-form-item><el-buttontype="primary"@click="handleCancel">取消el-button><el-buttontype="primary"@click="onSubmit">确定el-button>el-form-item>el-row>el-form>el-dialog><el-table:data="tableData"style="width:100%"><el-table-columnv-for="item in tableLabel":key="item.prop":prop="item.prop":label="item.label":width="item.width"/><el-table-columnfixed="right"label="Operations"min-width="120"><template#="scoped"><el-buttontype="primary"size="small"@click="onEdit(scoped.row)">编辑                        el-button><el-buttontype="danger"size="small"@click="onDelete(scoped.row)">删除el-button>template>el-table-column>el-table><el-paginationlayout="prev, pager, next":total="config.total"@current-change="handlerChangePage"class="page"/>div>div>template><scriptsetup>import{ ref,reactive,toRefs,onMounted,nextTick,getCurrentInstance }from'vue'import{ ElMessage,ElMessageBox }from'element-plus'const{ proxy }=getCurrentInstance()consttableData =ref([])consttableLabel =reactive([{ prop:"name",label:"姓名",},{ prop:"age",label:"年龄",},{ prop:"sex",label:"性别",},{ prop:"birth",label:"出生日期",width:200,},{ prop:"addr",label:"地址",width:400,},])constconfig =reactive({ name:"",total:0,})constformData =reactive({ keyWord:""})constdialogVisible =ref(false)constaction =ref("add")constformUser =ref({ sex:0,})//表单校验规则construles =reactive({ name:[{ required:true,message:"姓名是必填项",trigger:"blur"}],age:[{ required:true,message:"年龄是必填项",trigger:"blur"},{ type:"number",message:"年龄必须是数字"},],sex:[{ required:true,message:"性别是必选项",trigger:"change"}],birth:[{ required:true,message:"出生日期是必选项"}],addr:[{ required:true,message:'地址是必填项'}]})consthandlerSearch=()=>{ console.log("搜索",formData.keyWord);config.name =formData.keyWord    // console.log("搜索", searchText);getUserData(config)}constgetUserData=async(query)=>{ constdata =awaitproxy.$apis.getUserData(query)console.log("UserView的数据",data);config.total =data.count    tableData.value =data.list.map((item)=>{ return{ ...item,sex:item.sex ===1?'女':'男'}})}onMounted(()=>{ getUserData()})consthandlerChangePage=(value)=>{ console.log("当前页码",value);config.page =value    getUserData(config)}constonDelete=(row)=>{ console.log("删除",row);ElMessageBox.confirm('你确定要删除吗?','删除提示',{ confirmButtonText:'确定删除',cancelButtonText:'取消',type:'danger   ',}).then(()=>{ proxy.$apis.deleteUser({ id:row.id })ElMessage({ type:'success',message:'删除成功',})getUserData()}).catch(()=>{ ElMessage({ type:'info',message:'取消删除',})})}constonEdit=(row)=>{ console.log("编辑",row);action.value ="edit"dialogVisible.value =true/* nextTick 确保在 DOM 更新完成之后再执行回调函数    也就是编辑表单    */nextTick(()=>{ formUser.value ={ ...row,}})/*   formUser.value = {          ...row,     } */}//这个方法之前定义过consthandleAdd=()=>{ action.value ="add"//打开对话窗dialogVisible.value =true}//对话框右上角的关闭事件consthandleClose=()=>{ //获取到表单dom,执行resetFields重置表单//关闭对话框dialogVisible.value =falseproxy.$refs["userForm"].resetFields()}//对话框右下角的取消事件consthandleCancel=()=>{ dialogVisible.value =falseproxy.$refs["userForm"].resetFields()}//格式化日期,格式化为:1997-01-02这种consttimeFormat=(time)=>{ vartime =newDate(time);varyear =time.getFullYear();varmonth =time.getMonth()+1;vardate =time.getDate();functionadd(m){ returnm <10?"0"+m :m;}returnyear +"-"+add(month)+"-"+add(date);}constonSubmit=async()=>{ // 获取表单数据console.log("添加的xxx",formUser.value);// 先进行校验proxy.$refs["userForm"].validate(async(validate)=>{ if(validate){ letres =null;//这里无论是新增或者是编辑,我们都要对这个日期进行一个格式化//如果不是1997-01-02这种格式,使用timeFormat方法进行格式化formUser.birth =/^\d{ 4}-\d{ 2}-\d{ 2}$/.test(formUser.birth)?formUser.birth                :timeFormat(formUser.birth)// 提交表单时候,还需要判断是add or editif(action.value ==="add"){ res =awaitproxy.$apis.addUser(formUser.value)}else{ res =awaitproxy.$apis.editUser(formUser.value)}if(res){ ElMessage({ type:'success',message:action.value ==="add"?'添加成功':"编辑成功",})dialogVisible.value =falseproxy.$refs["userForm"].resetFields()// 刷新页面数据getUserData()}}else{ ElMessage({ type:'error',message:"请输入正确内容",})}})// 校验通过,执行添加操作proxy.$apis.addUser(formUser.value)}script><stylelang='less'scoped>.user{ height:100%;    .user-head{ display:flex;justify-content:space-between;}.user-table{ height:540px;position:relative;        .page{ position:absolute;bottom:50px;right:50px;}}}style>

5、每个组件之间需要共享配置导入pinia配置进行信息共享和传递。
pinia.js

import{ defineStore }from'pinia'import{ ref,watch }from'vue'functioninitData(){ return{ isCollapse:false,tags:[{ path:'/home',name:'home',label:'首页',icon:'hone'}],currentMenu:null,/* 展示菜单列表的数组 */menuList:[],token:null,routerList:[],}}exportconstuseAllDataStore =defineStore('allData',()=>{ // 全部数据的获取和修改conststate =ref(initData())// 进行数据持久化watch(state,newObj=>{ if(!newObj.token)returnlocalStorage.setItem('store',JSON.stringify(newObj))},{ deep:true,})functionselectMenu(val){ if(val.name ==='home'){ state.value.currentMenu =null}else{ state.value.currentMenu =val            letindex =state.value.tags.findIndex(item=>item.name ===val.name)index ===-1?state.value.tags.push(val):""}}functiondeleteMenu(tag){ letindex =state.value.tags.findIndex(item=>item.name ==tag.name)// 将当前tags切除state.value.tags.splice(index,1);}functionupdateMenuList(val){ // 将当前tags切除state.value.menuList =val;}functionclean(){ // 将所有路由移除state.value.routerList.forEach(item=>{ if(item)item();state.value =initData();// 删除本地的缓存localStorage.removeItem('store')})}functionaddRoutes(router,type){ // 刷新页面时候if(type ==='refresh'){ if(JSON.parse(localStorage.getItem('store'))){ state.value =JSON.parse(localStorage.getItem('store'))//state.value.routerList =[]}else{ return;}}// 将当前tags切除constmenu =state.value.menuList;console.log("menu",menu);/* 执行该代码后  import.meta.glob可能返回的是这样的对象  '@/views/Home.vue': () => import('@/views/Home.vue'),  '@/views/About.vue': () => import('@/views/About.vue'),  '@/views/User/Profile.vue': () => import('@/views/User/Profile.vue') */constmodule =import.meta.glob('../views/*.vue')console.log("module",module);constrouteArr =[]menu.forEach(item=>{ if(item.children){ item.children.forEach(child=>{ leturl =`../views/${ child.url}.vue`console.log("url",url);child.component =module[url]console.log("child.component",child.component);routeArr.push(...item.children)})}else{ leturl =`../views/${ item.url}.vue`console.log("url",url);item.component =module[url]console.log("item.component",item.component);routeArr.push(item)}routeArr.forEach(item=>{ state.value.routerList.push(router.addRoute("main",item));})})console.log("state.value.routerList",state.value.routerList);console.log("state.value.routeArr",routeArr);}return{ /* 其实是直接返回的是state.value */state,selectMenu,deleteMenu,updateMenuList,addRoutes,clean,}})

5、进行对应各个环境的配置环境设置

config.js

// 用于获取对应的环境变量constenv =process.env.NODE_ENV||"prod";constEnvConfig ={ development:{ baseURL:"/api",mockApi:"https://mock.apipark.cn/m1/4068509-0-default/api"},test:{ baseURL:"//test.xuyuan.com/api",mockApi:"https://mock.apipark.cn/m1/4068509-0-default/api"},prod:{ baseURL:"//xuyuan.com/api",mockApi:"https://mock.apipark.cn/m1/4068509-0-default/api"},}exportdefault{ env,/* 将其重新解构成一个对象,并将其合并到默认配置中 */...EnvConfig[env],isMock:false,};

【责任编辑:新华网】
返回顶部