vue項(xiàng)目實(shí)現(xiàn)面包屑導(dǎo)航
本文實(shí)例為大家分享了vue項(xiàng)目實(shí)現(xiàn)面包屑導(dǎo)航的具體代碼,供大家參考,具體內(nèi)容如下

安裝依賴
npm i vuex
創(chuàng)建 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)">關(guān)閉</li>
? ? ? <li @click="closeOthersTags">關(guān)閉其他</li>
? ? ? <li @click="closeAllTags">關(guān)閉所有</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>?創(chuàng)建 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;
}創(chuàng)建 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創(chuàng)建 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() 方法可返回指定的數(shù)字中帶有最低值的數(shù)字。
? ? ? ? } 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 storestore中的type.js配置
export const LOGIN = 'login' export const LOGOUT = 'logout' export const TITLE = 'title'
router.js修改配置

對(duì)點(diǎn)擊左側(cè)按鈕根據(jù)router-view顯示 清理緩存

最后在main.js中引入 store.js
import store from './store/index' // 導(dǎo)入狀態(tài)管理器VueX?
new Vue({
? el: '#app',
? router,
? store,
? components: { App },
? template: '<App/>'
})以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue實(shí)現(xiàn)動(dòng)態(tài)面包屑導(dǎo)航
- Vue2+element-ui實(shí)現(xiàn)面包屑導(dǎo)航
- vue element-ui實(shí)現(xiàn)動(dòng)態(tài)面包屑導(dǎo)航
- Vue 解決多級(jí)動(dòng)態(tài)面包屑導(dǎo)航的問題
- vue+elementUI動(dòng)態(tài)生成面包屑導(dǎo)航教程
- Vuex,iView UI面包屑導(dǎo)航使用擴(kuò)展詳解
- vue中的面包屑導(dǎo)航組件實(shí)例代碼
- vue2.0 elementUI制作面包屑導(dǎo)航欄
- vue 面包屑導(dǎo)航組件封裝
相關(guān)文章
使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤解決辦法
這篇文章主要給大家介紹了關(guān)于使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤的解決辦法,當(dāng)我們?cè)谧龃虬渲玫臅r(shí)候,出現(xiàn)了這個(gè)錯(cuò)誤,需要的朋友可以參考下2023-11-11
vue3 表單搜索內(nèi)容回顯到地址欄的實(shí)例代碼
這篇文章主要介紹了vue3 表單搜索內(nèi)容回顯到地址欄的實(shí)例代碼,地址欄輸入內(nèi)容回顯到form表單,同理表單輸入內(nèi)容也要回顯到地址欄中,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
詳解vue2父組件傳遞props異步數(shù)據(jù)到子組件的問題
本篇文章主要介紹了vue2父組件傳遞props異步數(shù)據(jù)到子組件的問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

