vue3从0开始搭建的学习记录(三)

上期链接:vue3从0开始搭建的学习记录(二)-CSDN博客

vuedraggable

上次没有搞完的vuedraggable,在vue2和3中使用的依赖有所不相同

先贴官网:GitHub - SortableJS/vue.draggable.next: Vue 3 compatible drag-and-drop component based on Sortable.js

 安装依赖 :npm install -S vuedraggable@next

<draggable
        v-model="pageList"
        animation="300"
        ghost-class="ghostClass"
        @end="onEnd"
        item-key="path"
      >
        <template #item="{ element, index }">
          <el-breadcrumb-item
          @contextmenu.prevent.native="rightBtnClick($event,element)"
          :class="{ 'active-page': $route.path === element.path }"
          :to="{ path: element.path }"
          :key="element.code"
          
          >{{ element.name}}<i
            v-if="element.path!=='/homepage'"
            class="el-icon-error deleteIcon"
            @click.stop="deletePage(element)"
        /></el-breadcrumb-item>
        </template>
        
      </draggable>

在我这里使用的和vue2版本的主要区别是多了一个item-key的使用,并且必须使用item的作用域插槽,不需要在内部循环要拖拽的元素了,绑定的v-model就已经循环了

效果:

const pageList=ref([{
  path:'/11122/33',
  name:'candan1'
},{
  path:'/11132/33',
  name:'candan2'
}])

页签状态管理

现在通过vuex来对页签做管理,定义一个activeMenu数组来做页签的存储

先粘官网:开始 | Vuex

安装依赖:npm install vuex@next --save

首先在src下创建一个store文件夹,加入index.js主文件、getters.js、mutations.js、actions.js(暂时用不上)

index.js

我把state直接放在index.js里了,因为我觉得要是主文件一点干货都没有还是有点造孽的(虽然目前只有一个状态缓存)

index.js

import { createStore } from 'vuex'
import getters from './getters';
import mutations from './mutations';
import actions from './actions';


const store = createStore({
  state: {
    activeMenu:[],
  },
  getters,
  mutations,
  actions,
  modules: {},
})

export default store

getters.js

getters.js里有个menuIndex,用来获取目标页签在当前的页签列表中的位置,目前应该还用不上,但是由于页签做了拖拽,所以有可能有业务需要获取这个位置,就先加上了

使用方法就是$store.getters.menuIndex(参数) //这里的参数为route对象

getters.js

const getters = {
  //获取activeMenu
  activeMenu(state){
    return state.activeMenu
  },
  /**获取页签位置
   * data 目标页签
   */
  menuIndex(state){
    return (data)=>{
      var res=state.activeMenu.findIndex(item=>item.path===data.path)
      return res||res===0?res:-1
    }
  },
}
export default getters

mutations.js

这里是一些写操作的方法,其中的data参数均为route对象

mutations.js

import $router from '@/router'
const mutations={
  /**添加页面标签
   * data      目标页签
   */
  addActiveMenu(state,data){
    if(!state.activeMenu.find(item=>item.path===data.path)){
        state.activeMenu.push(data)
    }
  },
  //删除指定页面标签
  deleteActiveMenu(state,data){
    const index=state.activeMenu.findIndex(item=>item.path===data.path)
    state.activeMenu.splice(state.activeMenu.findIndex(item=>item.path===data.path),1)
    // $router.go(-1)
    if(data.path!==$router.router.currentRoute.value.path){//当被删除页签不是当前页面时,不做操作
      
    }else if(index>0){
      $router.router.replace(state.activeMenu[index-1].path)
    }else{
      $router.router.replace('/')
    }
  },
  //删除其他全部页面标签
  deleteOtherActiveMenu(state,data){
    const current=state.activeMenu.find(item=>item.path===data.path)
    state.activeMenu=[current]
  },
  //删除全部页面标签
  clearActiveMenu(state){
    state.activeMenu=[]
    $router.replace('/');
  },
  //刷新页面标签
  resetActiveMenu(state,list){
    state.activeMenu=list
  }
}
export default mutations

 main.ts

将store引入main.ts

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

const app= createApp(App)

//引入store
app.use(store)

app.mount('#app')

菜单数据获取

接下来把菜单维护出来,目前干脆就直接用router数据来做菜单数据吧,一般来讲菜单要单独维护的,我就偷个懒

把路由表重新写了一下,这里没想要写什么菜单,先随便写了几个一级菜单,顺便加了个登录的路由,登录逻辑后面再说,先把文件结构给他加上

修改router.js

修改router/index.js并将routes也暴露出来

import {createRouter,createWebHistory } from 'vue-router'
import Layout from "../layout/index.vue";
const routes=[
  {
    path:'/login',
    component:()=>import('@/login/index.vue'),
    redirect:'/homepage',
    meta:{
      hide:true,           //加一个标志位,作为隐藏菜单的标志
    }
  },
  {
    path:'/',
    component:Layout,
    redirect:'/pages/homepage',
    meta:{
      hide:true,           //加一个标志位,作为隐藏菜单的标志
    },
  },
  {
    path:'/pages',
    component:Layout,
    redirect:'/pages/homepage',
    meta:{},
    children:[
      {
        path:'/pages/homepage',
        code:'homepage',
        name:'首页',
        meta:{},
        component:()=>import('@/view/homePage/index.vue')
      },
      {
        path:'/pages/pagesManagement',
        code:'pagesManagement',
        name:'页面管理',
        meta:{},
        component:()=>import('@/view/pagesManagement/index.vue')
      },
      {
        path:'/pages/componentsManagement',
        code:'componentsManagement',
        name:'组件管理',
        meta:{},
        component:()=>import('@/view/componentsManagement/index.vue')
      },
    ]
  },
]
 const router = createRouter({
  history:createWebHistory(),
  routes:routes
})
export default {router,routes};

修改main.ts

 这样的话需要把router引入的main.ts修改一下

然后我们的路由守卫这里也要加入一下了

import '@/router/guard.js'
app.use(router.router)  //原来是app.use(router)

 guard.js

import router from './index.js';
import $router from '@/router'
import store from '../store';


router.router.beforeEach(async (to, from, next) => {
  console.log('to',to);
  // 主页不添加页签
  if(to.path!=='/pages/homepage'){
    store.commit('addActiveMenu',to)
  }
  next();
});

修改layout/index.vue

 修改layout/index.vue里菜单列表的来源,页面的样式问题修改我就不再贴上来了

<script setup lang="ts">
import menuTab from './menuTab.vue';
import myMenu from './myMenu.vue'
import myRouter from '@/router/index'  //引入数据
const collapse=ref(false)

//只获取path==='/'的一级路由下的children作为菜单
const menuList:object[]=myRouter.routes.find(item=>item.path==='/').children

const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
</script>

修改layout/myMenu.vue 

修改layout/myMenu.vue的逻辑,当meta.hide为true时,不显示菜单,给<el-menu>标签加上router属性开启index跳转

<template v-for="menu in props.menuList">
        <!-- 隐藏的判断逻辑 -->
        <template v-if="!menu.meta.hide">
          <el-sub-menu v-if="menu.children&&menu.children.length>0" :index="menu.path" :key="menu.code">
            <template #title>
              <el-icon>
                <component :is="menu.icon" /></el-icon>
              <span>{{menu.name}}</span>
            </template>  
            <myMenu :isChild="true" :menuList="menu.children"></myMenu>     
          </el-sub-menu>
          <el-menu-item v-else :index="menu.path" :key="menu.code+'n'">
            <el-icon>
              <component :is="menu.icon" />
            </el-icon>
            <span>{{menu.name}}</span>
          </el-menu-item>
        </template>

修改layout/menuTab.vue

使用vuex的store需要用useStore()方法,这里把原来的变量名pageList换成了activeMenu,上方绑定的也要记得修改,删除页签的逻辑也加上去

<script setup lang="ts">

//获取vuex里的activeMenu
const store = useStore()
const activeMenu=computed(()=>store.getters.activeMenu) //原来的pageList
function deleteOthers() {
  store.commit('deleteOtherActiveMenu',currentPage)
}
function deleteAll() {
  store.commit('clearActiveMenu')
}
function deletePage(page:object) {
  store.commit('deleteActiveMenu',page)
}
</script>

将useStore()加入auto-import

这里发现unplugin-auto-import/vite依赖里没有useStore,那不行,要给他加进去,我不想手动写

import { useStore } from 'vuex'

那就要就改一些文件

auto-imports.d.ts文件global里加入这一句

  const useStore: typeof import('vuex')['useStore']

 vite.config.ts文件imports里加入vuex

AutoImport({  
      imports: [  
        'vue',  
        'vue-router',  
        'vuex'  //加入vuex
      ],
      dts: resolve('./auto-imports.d.ts'),
    }),

至此,基本框架就大功告成了

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值