vue项目实现面包屑导航

Georgia ·
更新时间:2024-11-10
· 1797 次阅读

本文实例为大家分享了vue项目实现面包屑导航的具体代码,供大家参考,具体内容如下

安装依赖

npm i vuex

创建 tagView.vue

<template>   <div class="tags-view-container">     <scroll-pane class="tags-view-wrapper" ref="scrollPane">       <router-link          ref="tag"           :to="tag"           :class="isActive(tag)? 'action' : ''"          class='scrollPane_item'         @contextmenu.prevent.native="openMenu(tag,$event)"          v-for="tag in Array.from(visitedViews)"          :key="tag.path">         {{tag.title}}         <span class="el-icon-error close_Icon" :class="isActive(tag)? 'IconActive' : ''"  @click.prevent.stop='closeSelectedTag(tag)'></span>       </router-link>     </scroll-pane>     <ul class='contextmenu' v-show="visible" :style="{ left: left+'px', top: top+'px'}">       <li @click="closeSelectedTag(selectedTag)">关闭</li>       <li @click="closeOthersTags">关闭其他</li>       <li @click="closeAllTags">关闭所有</li>     </ul>   </div> </template> <script>   import ScrollPane from '../scrollPane/scrollpane'   export default {     name: "tags-view",     components: { ScrollPane },     data(){       return{         visible: false,         top: 0,         left: 0,         selectedTag: {},         ScrollAction: false       }     },     computed:{       visitedViews(){         return this.$store.state.tagsView.visitedViews       }     },     watch:{       $route(){         this.addViewTags()         this.moveToCurrentTag()       },       visible(value) {         if (value) {           document.body.addEventListener('click', this.closeMenu)         } else {           document.body.removeEventListener('click', this.closeMenu)         }       }     },     mounted() {       this.addViewTags()     },     methods:{       generateRoute(){         if (this.$route.name) {           return this.$route         }         return false       },       isActive(route) {         return route.path === this.$route.path       },       addViewTags() {         const route = this.generateRoute()         if (!route) {           return false         }         this.$store.dispatch('addVisitedViews', route)       },       moveToCurrentTag() {         const tags = this.$refs.tag         this.$nextTick(() => {           for (const tag of tags) {             if (tag.to.path === this.$route.path) {               this.$refs.scrollPane.moveToTarget(tag.$el)               break             }           }         })       },       closeSelectedTag(view) {         this.$store.dispatch('delVisitedViews', view).then((views) => {           if (this.isActive(view)) {             const latestView = views.slice(-1)[0]             if (latestView) {               this.$router.push(latestView)             } else {               this.$router.push('/homePage')             }           }         })       },       closeOthersTags() {         this.$router.push(this.selectedTag)         this.$store.dispatch('delOthersViews', this.selectedTag).then(() => {           this.moveToCurrentTag()         })       },       closeAllTags() {         this.$store.dispatch('delAllViews')         this.$router.push('/homePage')       },       openMenu(tag, e) {         this.visible = true         this.selectedTag = tag         this.left = e.clientX  + 30 // 15: margin right         this.top = e.clientY       },       closeMenu() {         this.visible = false       }     }   } </script>  <style>   @import './tagView.scss'; </style> 

创建 tagView.scss

.tags-view-container {   height: 100%; } .contextmenu {   margin: 0;   background: #fff;   z-index: 100;   position: absolute;   list-style-type: none;   padding: 5px 0;   border-radius: 4px;   font-size: 12px;   font-weight: 400;   color: #333;   box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); } .contextmenu li {   margin: 0;   padding: 7px 16px;   cursor: pointer; } .contextmenu li:hover {   background: #eee; } .tags-view-wrapper a {   display: inline-block;   position: relative;   width: 100px;   padding: 0 10px;   color: #000;   background: #fff;   text-align: center;   font-size: 15px; } .action {   border-bottom: 2px solid #1AB394; } .close_Icon {   color: #fff;   margin-left: 3px; } .IconActive {   color: #b1b1b1; }

创建 tagViews.js

const tagsView = {   state: {     visitedViews: [],     cachedViews: []   },   mutations: {     ADD_VISITED_VIEWS: (state, view) => {       if (state.visitedViews.some(v => v.path === view.path)) return       state.visitedViews.push(Object.assign({}, view, {         title: view.meta.title || 'no-name'       }))       if (!view.meta.noCache) {         state.cachedViews.push(view.name)       }     },     DEL_VISITED_VIEWS: (state, view) => {       for (const [i, v] of state.visitedViews.entries()) {         if (v.path === view.path) {           state.visitedViews.splice(i, 1)           break         }       }       for (const i of state.cachedViews) {         if (i === view.name) {           const index = state.cachedViews.indexOf(i)           state.cachedViews.splice(index, 1)           break         }       }     },     DEL_OTHERS_VIEWS: (state, view) => {       for (const [i, v] of state.visitedViews.entries()) {         if (v.path === view.path) {           state.visitedViews = state.visitedViews.slice(i, i + 1)           break         }       }       for (const i of state.cachedViews) {         if (i === view.name) {           const index = state.cachedViews.indexOf(i)           state.cachedViews = state.cachedViews.slice(index, i + 1)           break         }       }     },     DEL_ALL_VIEWS: (state) => {       state.visitedViews = []       state.cachedViews = []     }   },   actions: {     addVisitedViews({ commit }, view) {       commit('ADD_VISITED_VIEWS', view)     },     delVisitedViews({ commit, state }, view) {       return new Promise((resolve) => {         commit('DEL_VISITED_VIEWS', view)         resolve([...state.visitedViews])       })     },     delOthersViews({ commit, state }, view) {       return new Promise((resolve) => {         commit('DEL_OTHERS_VIEWS', view)         resolve([...state.visitedViews])       })     },     delAllViews({ commit, state }) {       return new Promise((resolve) => {         commit('DEL_ALL_VIEWS')         resolve([...state.visitedViews])       })     }   } } export default tagsView

创建 scrollPane.vue

<template>   <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">     <div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">       <slot></slot>     </div>   </div> </template> <script>   const padding = 15 // tag's padding   export default {     name: 'scrollPane',     data() {       return {         left: 0       }     },     methods: {       handleScroll(e) {         const eventDelta = e.wheelDelta || -e.deltaY * 3//wheelDelta:-120;deltaY:-120         const $container = this.$refs.scrollContainer//外面的container         const $containerWidth = $container.offsetWidth//外面的container的宽度         const $wrapper = this.$refs.scrollWrapper//里面         const $wrapperWidth = $wrapper.offsetWidth//里面的宽度         if (eventDelta > 0) {           this.left = Math.min(0, this.left + eventDelta)//min() 方法可返回指定的数字中带有最低值的数字。         } else {           if ($containerWidth - padding < $wrapperWidth) {             if (this.left < -($wrapperWidth - $containerWidth + padding)) {               this.left = this.left             } else {               this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)             }           } else {             this.left = 0           }         }       },       moveToTarget($target) {         const $container = this.$refs.scrollContainer         const $containerWidth = $container.offsetWidth         const $targetLeft = $target.offsetLeft         const $targetWidth = $target.offsetWidth         if ($targetLeft < -this.left) {           this.left = -$targetLeft + padding         } else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {         } else {           this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)         }       }     }   } </script> <style>   .scroll-container {     white-space: nowrap;     position: relative;     overflow: hidden;     width: 100%;     height: 100%;     box-sizing: border-box;   }   .scroll-wrapper {     height: 100%;     line-height: 41px;     position: absolute;   } </style>

store中index.js配置

import Vue from 'vue' import Vuex from 'vuex' import * as types from './types' import tagsView from '../assets/js/tagsview' Vue.use(Vuex)  const store = new Vuex.Store({    modules: {     tagsView   } }) export default store

store中的type.js配置

export const LOGIN = 'login' export const LOGOUT = 'logout' export const TITLE = 'title'

router.js修改配置

对点击左侧按钮根据router-view显示 清理缓存

最后在main.js中引入 store.js

import store from './store/index' // 导入状态管理器VueX  new Vue({   el: '#app',   router,   store,   components: { App },   template: '<App/>' })



VUE 面包 面包屑导航 面包屑

需要 登录 后方可回复, 如果你还没有账号请 注册新账号