Vue Web开发(八)

1. VueWeb面包屑和tag的布局

  本章节完成VueWeb面包屑和tag的布局,并且与左侧菜单联系,涉及组件间通信。

1.1. 页面创建

  (1)首先我们先完成每个页面的路由,之前已经有home页面和user页面,缺少mail页面和其它选项下的page1和page2页面。在view文件夹下新建mail文件夹,新建index.vue,填充user页面的内容即可。在view下新建other文件夹,新建pageOne.vue和pageTwo.vue,页面内容简单填充即可。三个页面都要更改name属性,后面会用到,首字母大写。

  新建src/ciews/mail/index.vue

javascript 复制代码
//src/ciews/mail/index.vue
<template>
	<div>网上商品页面</div>
</template>
<script>
	export default {
		name: 'mail',
		data() {
			return {}
		}
	}
</script>

  新建src/ciews/other/pageOne.vue

javascript 复制代码
//src/ciews/other/pageOne.vue
<template>
	<div>网上PageOne页面</div>
</template>
<script>
	export default {
		name: 'PageOne',
		data() {
			return {}
		}
	}
</script>

  新建src/ciews/other/pageTwo.vue

javascript 复制代码
//src/ciews/other/pageTwo.vue
//User.vue文件
<template>
	<div>网上PageTwo页面</div>
</template>
<script>
	export default {
		name: 'PageTwo',
		data() {
			return {}
		}
	}
</script>

  (2)配置路由:在路由主文件添加路由,路由位置在CommonAside的menu数组中保持偶一致。这里的name属性是小写,与上面不相同。

javascript 复制代码
 // isCollapse: false,
                menu: [
                    {
                        id: 0,
                        path: "/home",
                        name: "home",
                        label: "首页",
                        icon: "s-home",
                        url: "Home/Home",
                    },
                    {
                        id: 1,
                        path: "/mail",
                        name: "mail",
                        label: "商品管理",
                        icon: "video-play",
                        url: "MailManage/MailManage",
                    },
                    {
                        id: 2,
                        path: "/user",
                        name: "user",
                        label: "用户管理",
                        icon: "user",
                        url: "UserManage/UserManage",
                    },
                    {
                        label: "其他",
                        icon: "location",
                        children: [
                            {
                                id: 3,
                                path: "/page1",
                                name: "pageOne",
                                label: "页面1",
                                icon: "setting",
                                url: "Other/PageOne",
                            },
                            {
                                id: 4,
                                path: "/page2",
                                name: "pageTwo",
                                label: "页面2",
                                icon: "setting",
                                url: "Other/PageTwo",
                            }
                        ],
                    },
                ]

  (3)为左侧导航栏其他模块二级菜单添加点击事件。为el-menu-item添加点击事件。

javascript 复制代码
 <el-menu-item-group v-for="(subItem,subIndex) in item.children"
                                :key="subItem.path+''">
      <el-menu-item @click="clickMenu(subItem)" :index="subIndex.toString()">
              {{subItem.label}}
      </el-menu-item>
 </el-menu-item-group>

1.2. 面包屑功能

  (1)面包屑有数据记忆存储功能,每次点击导航栏后后记录选中的导航栏并列出。这里需要用到Vuex.Store,我们前面左侧导航栏的收起与展开同样使用到Vuex.Store,store可以看做是容器,里面有四个值,由State、Getters、Mutation、Actions这四种组成。在src/store下的tab.js文件,默认数据定义在state中,我们定义为一个数组tabsList,数组里有多个对象,但这里知识默认对象,对象里有四个属性,path、name、label、icon。currentMenu为一个临时变量,存储点击的tab。

javascript 复制代码
// src/store/tab.js
    state: {
        isCollapse: false,
		//默认菜单面包屑
        tabsList: [{
			id: 0,
			path: "/home",
			name: "home",
			label: "首页",
			icon: "s-home",
			url: "Home/Home",
        }],
		//当前菜单面包屑
        currentMenu: null
    },

  (2)改变tabsList里的内容要用到Vuex.store的mutations。改变state数据的发都会以函数的形式写在mutations中,之后在页面调用即可。selectMenu函数接收两个参数,state和val,此时需要进行判断,当前点击的导航栏是不是首页,用name属性判断,判断传入的item.name是否等于'home',如果不是home,需要赋值val给currentMenu,这样currentMenu就会不断累加,最多为五个(首页、用户、商品、其他1、其他2)。此处还需要一个判断,判断当前点击的导航栏是是不是刚刚已经点击过来,点击过了不再进行累加,而是将面包屑跳转到点击过的那一个。这里用到findIndex()方法。判断item.name里是否有val.name。 有的话为1,无的话为-1,无的话那么使用push()方法将val累加到currentMenu。如果点击是'home'的情况,currentMenu置空。

javascript 复制代码
// src/store/tab.js
 //更改 Vuex 的store中的状态的唯一方法是提交mutations
    mutations: {
        collapseMenu(state) {
            state.isCollapse = !state.isCollapse
        },
        selectMenu(state, val) {
            if (val.name !== 'home') {
                state.currentMenu = val
                const result = state.tabsList
                    .findIndex(item => item.name === val.name)
                if (result === -1) {//不存在
                    state.tabsList.push(val)
                }
            } else {
                state.currentMenu = null
            }
        },
    }

  (3)在src/componentsCommonAside中调用currentMenu,并传入item,item实际就menu数组中的任一对象。

javascript 复制代码
// src/componentsCommonAside.vue
 this.$store.commit('selectMenu',item)
javascript 复制代码
// src/componentsCommonAside.vue
 /**
   * 一级、二级菜单点击事件
   * @param item
    */
    clickMenu(item) {
     //全局引用router跳转
     this.$router.push({
      // name: item.name //名字路由指引
              path:item.path//路径路由指引
       }).catch(e => {})
       this.$store.commit('selectMenu',item)
  },

  (4)更改CommonHeader.vue,使用element ui的面包屑元素。

javascript 复制代码
//element ui官方案例:Breadcrumb,面包屑
<el-breadcrumb separator="/">
  <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
  <el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
  <el-breadcrumb-item>活动列表</el-breadcrumb-item>
  <el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>

  我们需要进行数据渲染,渲染成动态数据,v-for循环tags,:key使用item.path识别。{{}}表示动态渲染数据。

  这里数据比较比较长,item--tags--tabsList--menu。tabsList里的数据也是menu动态加载进去的。

javascript 复制代码
    <el-breadcrumb separator="/">
        <el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path: item.path }">{{item.label}}</el-breadcrumb-item>
    </el-breadcrumb>

  (5)修改src/CommonHeader.vue

  src/CommonHeader.vue引入mapState,这个是vuex的辅助函数。

javascript 复制代码
// src/CommonHeader.vue
 import { mapState } from 'vuex'

在computed属性中进行注入,这里起了一个别名tags。

javascript 复制代码
  // src/CommonHeader.vue
  computed:{
      //当前组件需要的全局数据,映射为当前组件computed属性
     //数据注入
      ...mapState({
          tags:state => state.tab.tabsList
      })
  }

  (6)页面会根据面包屑进行,路由也会自行更改。

  VueWeb Element Ui面包屑示例下载

1.3. tag区域

  这个功能其实类似于面包屑,只是多了删除功能。使用element ui的tag组件。tag组件的close属性表示组件是否可以关闭。tag组件有两个触发事件click、close。分别是点击tag和删除tag。

 &emsp(1);tag组件为公共组件,在components下新建CommonTag.vue。v-for遍历tags,这里注意,首页tag是不能删除的,closable属性表示有删除按钮,后面可以附带条件。effect属性为主题(样式),表示为高亮显示。判断方法是根据路由地址和当前tag的名称是否一致,注意是route(不是router)一致则为dark(高亮),不一致为plain(白色)。添加改变tag事件和删除tag事件。这里用模块化,用函数实现。

javascript 复制代码
//src/components/CommonTag.vue
<template>
	<div class="tabs">
		<el-tag v-for="(tag,index) in tags" :key="tag.name" :closable="tag.name !== 'home'"
			:effect="$route.name === tag.name ? 'dark' : 'plain'" @click="changeMenu(tag)"
			@close="handleClose(tag,index)" size="small">
			{{ tag.label }}
		</el-tag>
	</div>
</template>

  (2)渲染tag,同样需要用到tabsList,引入mapState,在computed属性中注入,注入为三个点(...),这里同样将tabsList赋值给tags,两个页面的tags互不干扰。

javascript 复制代码
//src/components/CommonTag.vue
<script>
	import {mapState,mapMutations} from 'vuex'
	export default {
		name: 'CommonTag',
		data() {
			return {

			}
		},
		computed: {
			...mapState({
				tags: state => state.tab.tabsList
			}),

		},
		methods: {
			...mapMutations({
				close: 'closeTag'
			}),
			changeMenu()
			handleClose()
		},
	}
</script>

  (3)在src/views/Main.vue引入组件

javascript 复制代码
// src/views/Main.vue
import CommonTag from "../src/components/CommonTag.vue";
export default {
  name: "Home",
  components: {
    CommonTag
  },

   注意在el-header和el-main之间,因为这个组件并不属于header也不属于main,所以在中间。

javascript 复制代码
// src/views/Main.vue
<el-header>
   <common-header></common-header>
</el-header>
<common-tag></common-tag>
<el-main>
   <router-view></router-view>
</el-main>

   覆盖样式

javascript 复制代码
// src/views/Main.vue
<style lang="less" scoped>
    .tabs{
        padding: 20px;
        .el-tag{
            margin-right: 15px;
            cursor: pointer;
        }
    }
</style>

   (4)接下来完成//src/components/CommonTag.vue点击事件个删除事件(重难点!!!),点击就是路由切换。methods里更改函数。

javascript 复制代码
//src/components/CommonTag.vue
   changeMenu(item) {
        this.$router.push({name: item.name})
        console.log(name)
},

   (5)删除tag:

   删除tag也会删除对应的面包屑,面包屑对应的是state.tabsList。首先拿到tag的总长度,总长度减1就是我们当前选中的tag,赋值给length,判断length和index的长度进行比较,如果这两个值相等,那么就表示此时我们选中的tag是tag中的最后一项。首先判断tag.name与当前的路由是否一致,如果不一致,不需要额外操作,直接return,即高亮   在最后一个tag,删除的tag是非选中的tag,所以无需操作。

如果当前删除的tag是最后一个tag,那么高亮部分一个向左移动一格。如果当前菜单高亮才当在中间,并且你删除当前的菜单时,高亮显示向右移动一格。

javascript 复制代码
//src/components/CommonTag.vue
            handleClose(tag,index){
                this.close(tag)
                const length = this.tags.length - 1
                if(tag.name !== this.$route.name){
                    return;
                }
                //高亮向左移动,这里视频代码错误,应该是上面不减1,下面减1.
                if(index === length){
                    this.$router.push({
                        name: this.tags[index].name
                    })
                }else{
                    this.$router.push({
                        name: this.tags[index - 1].name
                    })
                }
            }

   (5)此时在src/store/tab.js需要删除state下的tabsList,修改state必须使用mutations。因此需要在mutations中声明closeTag。

javascript 复制代码
//src/store/tab.js
  closeTag(state,val){
      const result = state.tabsList.findIndex(item => item.name === val.name)
      state.tabsList.splice(result,1)
  }

   (6)在src/components/CommonTag.vue下调用mutations

javascript 复制代码
//src/components/CommonTag.vue
import { mapState,mapMutations } from 'vuex'
            ...mapMutations({
                close:'closeTag'
            }),

   (7)在src/components/CommonTag.vue总体的script代码。

javascript 复制代码
// src/components/CommonTag.vue
<script>
import { mapState,mapMutations } from 'vuex'
    export default{
        name:'CommonTag',
        data(){
            return{
 
            }
        },
        computed:{
            ...mapState({
                tags:state => state.tab.tabsList
        }) ,
 
        },
        methods:{
            ...mapMutations({
                close:'closeTag'
            }),
            changeMenu(item){
                this.$router.push({ name: item.name })
                console.log(name)
            },handleClose(tag,index){
                this.close(tag)
                const length = this.tags.length - 1
                if(tag.name !== this.$route.name){
                    return;
                }
                //高亮向左移动,这里视频代码错误,应该是上面不减1,下面减1.
                if(index === length){
                    this.$router.push({
                        name: this.tags[index].name
                    })
                }else{
                    this.$router.push({
                        name: this.tags[index - 1].name
                    })
                }
            },
 
        }
        
    }
</script>

  效果图

   VueWeb Tag示例下载

相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端