美文网首页
vue3路由缓存(点击菜单栏标签实现切换页面)

vue3路由缓存(点击菜单栏标签实现切换页面)

作者: 諍眼閉眼 | 来源:发表于2023-09-24 17:56 被阅读0次

    环境搭建 参考 vite+vue3环境搭建

    其次ui框架用了antdV(感觉比element更专业啊)
    上面的都安装好了后就可以开始了

    0.配置路由文件

    image.png

    1.创建pinia缓存文件

    import { defineStore } from 'pinia'
    
    export const useMenuStore = defineStore({
      id: 'menu',
      state: () => {
        return {
          openMenu: [],
          menuIdx: 0,
          menuRoute: []
        }
      },
      getters: {},
      actions: {},
      // 开启数据缓存
      persist: {
        enabled: true,
        strategies: [{
          key: 'my_project',
          storage: sessionStorage,
        }]
      }
    })
    

    2.路由入口

    <script setup>
    import { useMenuStore } from '@/stores/menu';
    import { storeToRefs } from "pinia"
    
    const menuStore = useMenuStore()
    const { openMenu } = storeToRefs(menuStore) 
    </script>
     <router-view v-slot="{ Component, route }">
                <keep-alive :include="openMenu">
                  <component v-if="route.meta.keepAlive" :is="Component" :key="route.name" />
                </keep-alive>
                <component v-if="!route.meta.keepAlive" :is="Component" :key="route.name" />
              </router-view>
    

    3.简单的写个菜单样式


    image.png
    image.png

    抽出成独立的组件

    <template>
      <div style="position: relative;border-radius: 5px;background-color: #fff;overflow: hidden;" :style="`${isScrollBtn ? 'padding: 0 20px 0 27px;' : 'padding: 0 37px 0 10px;'}`">
        <div class="leftBtn" @click="handleLeft" v-show="isScrollBtn"><DoubleLeftOutlined /></div>
        <div class="menu-tag" ref="tagBox" @scroll="menuScroll">
      
          <a-tag :closable="v != 'Index'"  v-for="(v, index) in openMenu" :bordered="false" :color="`${index == menuIdx ? '#108ee9' : 'blue'}`" @click="handleTag(v)" @close.prevent="handleClose(v, index)">{{v}}</a-tag>
    
        </div>
        <div class="rightBtn" @click="handleRight" v-show="isScrollBtn"><DoubleRightOutlined /></div>
      </div>
    </template>
    
    <script setup>
      import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue';
      import { ref, nextTick, watch } from 'vue'
      import { useMenuStore } from '@/stores/menu';
      import { storeToRefs } from "pinia"
      import { useRouter, useRoute } from "vue-router"
      const route = new useRoute()
      const router = new useRouter()
      const menuStore = useMenuStore()
      const { menuIdx, openMenu, menuRoute } = storeToRefs(menuStore) 
      const tagBox = ref(null)
    
      const isScrollBtn = ref(false)
      let offsetWidth = 0
      let scrollWidth = 0
      let scrollLeft = 0
      let isScroll = false // 是否在滚动
      let scrollLenth = 300 //滚动距离
    
      watch(() => route.name, async (now) => {
        let Idx = openMenu.value.indexOf(now)
        if(Idx == -1) {
          openMenu.value.push(now)
          menuRoute.value.push(route.path)
          menuIdx.value = openMenu.value.length - 1
          await nextTick()
          isBeyond()
        } else {
          menuIdx.value = Idx
        }
      }, {immediate: true})
      /** 监听容器盒子滚动事件 */
      let scrollTimer;
      const menuScroll = () => {
        isScroll = true
        if(scrollTimer) clearTimeout(scrollTimer);
        scrollTimer = setTimeout(() => {
          getOpton()
          isScroll = false
        }, 300);
      }
      /** 获取菜单容器宽度等信息 */
      const getOpton = () => {
        offsetWidth = tagBox.value.offsetWidth
        scrollWidth = tagBox.value.scrollWidth
        scrollLeft = tagBox.value.scrollLeft
      }
      /** 计算宽度是否超出容器宽度 */
      const isBeyond =  () => {
        getOpton()
        if(scrollWidth > offsetWidth) {
          isScrollBtn.value = true
          tagBox.value.scrollTo(scrollWidth - offsetWidth + 47, 0)
        } else {
          isScrollBtn.value = false
        }
      }
      const handleLeft = () => {
        if(isScroll) return
        tagBox.value.scrollTo(scrollLeft - scrollLenth, 0)
      }
      const handleRight = () => {
        if(isScroll) return
        tagBox.value.scrollTo(scrollLeft + scrollLenth, 0)
      }
      // 点击菜单
      const handleTag = (name) => {
        let Idx = openMenu.value.indexOf(name)
        menuIdx.value = Idx
        router.push(menuRoute.value[Idx])
      }
      // 关闭菜单
      const handleClose = async (name,index) => {
        
        // 删除的是高亮菜单
        if(index == menuIdx.value) {
          menuIdx.value -= 1
          router.push(menuRoute.value[index - 1])
        }
        openMenu.value.splice(index, 1)
        menuRoute.value.splice(index, 1)
        await nextTick()
        isBeyond()
      }
    </script>
    <style lang='less' scoped>  
      :deep(.menu-tag) {
        cursor: pointer;
        user-select: none;
      }
      .leftBtn,.rightBtn {
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 18px;
        color: #fff2f0;
        position: absolute;
        top: 0;
        
        bottom: 0;
        background-color: rgb(60 60 60 / 88%);
        width: 20px;
        z-index: 1;
        box-shadow: #fff inset 0 0px 17px;
        cursor: pointer;
        &:hover {
          color: #d8d5d5;
          background-color: #999696;
        }
      }
      .leftBtn {
        left: 0;
      }
      .rightBtn {
        right: 0;
      }
      .menu-tag {
        // width: 1000px;
        height: 40px;
        
        box-sizing: border-box;
        // margin: 10px 16px;
        
        display: flex;
        align-items: center;
        overflow: hidden;
        justify-content: flex-start;
        &>* {
          flex-shrink: 0;
        }
        
      }
    </style>
    

    最后路由缓存需要页面申明name
    使用steup语法糖 可以安装插件 vite-plugin-vue-setup-extend
    vite.config.js内配置


    image.png

    就可以直接

    <script steup name="aaaa">
    

    相关文章

      网友评论

          本文标题:vue3路由缓存(点击菜单栏标签实现切换页面)

          本文链接:https://www.haomeiwen.com/subject/kcxqbdtx.html