Vue实现顶部标签以及左侧层级导航栏

        场景:因为从数据需要分类,所以在主数据详情页要加一个顶部的标签来实现分类,再根据左侧的从数据id来实现浏览从数据,但是其中有一个分类下面又分了层类,所以要用到左侧导航栏,样式如下:

        第一种:左侧没有层级导航直接是从数据模块

        第二种:左侧从数据包含层级导航栏

HTML 代码

<a-spin :spinning="spinning1">
  <div class="bottom-table">
    <a-tabs default-active-key="0" @change="callback" style="width: 100%">
      <a-tab-pane :key="index" :tab="item" v-for="(item, index) in tabs" class="ant-tabs-tab">
        <div class="table-left">
          <a-menu
              style="width: 100%"
              :open-keys.sync="openKeys"
              mode="inline"
              @click="handleClick"
              v-show="!isNotHierarchy"
			  v-model="openRows"
          >
            <!--一级菜单菜单-->
            <a-sub-menu :key="index"  v-for="(item, index) in firstFloor" >
              <span slot="title" class="a-sub"><span>{{ item }}</span></span>
			    <!--一级菜单下数据模块-->
                <a-menu-item :key="item2.value" v-for="(item2, index2) in subMenu[index]">
                  {{item2.name}}
                </a-menu-item>
              <!--二级菜单-->
              <a-sub-menu @titleClick="titleClick" :key="item3.value" :title="item3.name" v-for="(item3, index3) in subMenu2[index]" class="a-sub2">
				<!--二级菜单下数据模块-->
                <a-menu-item :key="item4" v-for="(item4, index4) in subMenu3[item3.value]">
                  {{item4}}
                </a-menu-item>
              </a-sub-menu>
            </a-sub-menu>
          </a-menu>
          
          <!--左侧不带层级导航栏直接展示从数据项-->
          <div  v-for="item in tableList" class="left-info" @click="getInfos(item)" v-show="isNotHierarchy">
           {{item.name}}
          </div>
        </div>
		<!--右侧数据展示-->
        <div class="table-right">
          <a-spin :spinning="spinning2" :tip="tip">
			<!--右侧数据标题-->
            <div class="right-title-two">
              <span class="title-left"></span>
              <span class="title-right">{{ tableTitle }}</span>
            </div>
			
			<!--数据不同展示样式不同,根据showList来控制-->
			<!--右侧数据为List<Map>展示样式-->
            <a-table  v-show="!showList" :columns="columns" :data-source="data"
                     :selectedRowKeys="selectedRowKeys" :pagination="pagination" :scroll="{y: '250px'}">
              <template slot="operation" slot-scope="text,record">
                <a @click="ok(record)" style="margin-right:16px;color:#2ab62b"><img src="../public/img/ok.svg" alt="" style="width: 14px;height: 14px;transform: translateY(-3px);"> 确认 </a>
              </template>
            </a-table>
			
			<!--右侧数据为Map<String,List>展示样式-->
            <div class="taskill" v-show="showList">
				<!--右侧数据表头也就是map的kye-->
                <div class="taskill-nav" style="white-space: nowrap; width: 1200px" >
                    <span
                        v-for="(item,i) in listTitle"
                        :key="i"
                        :title="item"
                    >
                    {{item}}</span>
                </div>
				<!--右侧数据的列表也就是map的value-->
                <div class="taskill-content">
                    <div class="taskill-li" v-show="tableTitle ==='配置文件目录'>
                      <span :class="item === '暂无数据'?'spanNull':'spanNotNull'" v-for="(item,i) in taskillList" :key="i">{{item}}</span>
                    </div>
                </div>
            </div>
          </a-spin>
        </div>
      </a-tab-pane>
    </a-tabs>
  </div>
</a-spin>

data属性

data: [],

//点击顶部导航栏左侧列表实际显示部分(根据点击的导航栏来控制显示哪些)
tableList:[],

//接口返回全部数据
tableList2:[],

//顶部导航栏标签列表
tabs:['top1','top2','top3','top4'],

//顶部导航栏第二项的左侧导航栏一级菜单
firstFloor:['left1','left2','left3','left4'],

//一级菜单下的数据项(根据业务确定接口返回的数据不是菜单而是数据项的列表,key对应的是一级菜单的下标)
subMenu:{0:[],1:[],2:[],3:[],4:[],5:[]},

//二级菜单(根据业务确定接口返回的数据哪些是二级菜单,key对应的是一级菜单的下标,value是二级模块key的列表)
subMenu2:{0:[],1:[],2:[],3:[],4:[]},

//二级菜单所细分数据项模块
subMenu3:{二级模块key:['二级目录下模块1','二级目录下模块2'],
			......
          },
		  
//点击左侧导航栏存放所有展开菜单的唯一key
openKeys:[],

//绑定模拟点击的数据项唯一key用来展示点击效果(实现模拟点击的效果)
openRows:[],

//控制是否展示左侧导航栏
isNotHierarchy:false,

//是否第一次点击top下边为1的导航栏,第一次才触发模拟点击
isFirstClick:true,

//加载中控制属性
spinning1:true,
spinning2:true,

//加载中显示文字属性
tip:'',

js方法

watch: {
  //点击展开/关闭层级导航时触发
  openKeys(val) {
    console.log('openKeys', val);
    //第一次进来才会模拟点击(解决进来点击别的一级菜单下也触发模拟点击且点击效果不会取消)
    if (this.isFirstClick){
      debugger
      let script = {}
      if (this.subMenu[val[0]].length!==0){
		//一级菜单下有数据项点击数据项
        console.log("进来了1")
        console.log(this.subMenu[val[0]])
        let data = this.subMenu[val[0]]
        console.log(data[0])
        this.openRows.push(data[0].value)
        script = {name:data[0].name,value:data[0].value}
        console.log("script",script)
        try {
          this.getInfos(script)
        }catch (e) {
          console.log(e)
        }
      }else if (this.subMenu2[val[0]].length!==0){
		//一级菜单下有二级菜单点击二级菜单且点击二级菜单下的数据项
        let data = this.subMenu2[val[0]]
        console.log(this.openKeys)
        //如果不判断就回进入死循环,因为添加key进去也相当于点击,所以就会一直调用本方法
        if (this.openKeys.includes(data[0].value)){
          let valueList = this.subMenu3[data[0].value]
          console.log("valueList",valueList)
          this.openRows.push(valueList[0])
          script = {name:valueList[0],value:data[0].value}
          console.log("script",script)
          try {
            this.getInfos(script)
          }catch (e) {
            console.log(e)
          }
          return
        }
        this.openKeys.push(data[0].value)
      }
      this.isFirstClick=false
    }
  },
},
methods: {
  //点击数据项模块触发方法
  handleClick(e) {
	//e.key中的数据是根据我们设置导航栏的时候的:key来决定  e中还有一个keypath是当前数据项所在层级倒叙的目录列表,从当前key往外推
	console.log('click', e);
	//确认是否为二级菜单
    let includes = false
    let scriptName = ''
	//循环二级菜单下的模块列表,看看所点击模块是否存在其中,如果存在就是二级菜单下的模块
    for (let key in this.subMenu3){
      let arr = this.subMenu3[key]
      includes = arr.includes(e.key);
	  //如果存在
      if (arr.includes(e.key)){
		//就将当前所选三级菜单的二级菜单的key封装起来发送请求,因为后端只接收二级模块key的请求
        scriptName = key
        break
      }
    }
	
    if (includes){
      //二级菜单下的请求数据封装
      let newScriptName = this.scriptName[scriptName]
      let script = {name:newScriptName,value:scriptName}

	  //发送请求的方法
      this.getInfos(script)
      this.tableTitle = e.key
    } else {
	  //一级菜单下的数据项模块请求数据封装
      let newScriptName = this.scriptName[e.key]
      let script = {name:newScriptName,value:e.key}
      this.getInfos(script)
    }
  },
  
  //点击二级导航栏触发的方法
  titleClick(e) {
    console.log('titleClick', e);
  },
  
  //top导航栏切换方法
  callback(key) {
    if (key !== 1) {
	  this.openKeys=[]
      this.openRows=[]
	  //非左侧带有层级目录的top导航下左侧显示数据逻辑
      this.isNotHierarchy = true;
      let newThis = this
      newThis.tableList=[]
      //根据点击的哪个top导航栏来决定左侧的数据列表中的数据...(接口返回的数据分开存放在不同的top导航下)
	  if (key === 0) {
        this.tableList2.forEach(function (item, index, lis) {
            if (item.value === 's05_firmware_base' ||  item.value === 's28_kernel_bin') {
                newThis.tableList.push(item)
            }
        })
      }
	  ....
	  
	  //判空处理
      if (newThis.tableList.length===0){
        let data = "暂无数据";
        this.tableList=[{name:data,value:""}]
      }
	  ....
      this.$nextTick(()=>{
        $(".left-info")[0].click();
      })
    } else {
	  this.isFirstClick=true
      this.isNotHierarchy = false;
	  this.tableTitle = ''
      this.data = []
      let newThis = this
      newThis.subMenu={0:[],1:[],2:[],3:[],4:[],5:[]}
      newThis.subMenu2={0:[],1:[],2:[],3:[],4:[]}
	  //决定哪些数据是在此top标签页下的数据
      this.tableList2.forEach(function (item, index, lis) {
		//来决定数据是左侧导航栏哪个一级导航栏下的数据项存放subMenu中,哪些是二级导航栏存放subMenu2中,0,1,2.....代表是一级导航栏下标
		
		//第一个一级导航栏下
        if (item.value === 's70_file_check' ....) {
            if (item.value === 's70_file_check'){
              newThis.subMenu2[0].push(item);
            }else {
              newThis.subMenu[0].push(item);
            }
        }
		//第二个一级导航栏下
        if (item.value === 's60_file_check' ....) {
            if (item.value === 's60_file_check'){
              newThis.subMenu2[1].push(item);
            }else {
              newThis.subMenu[1].push(item);
            }
        }
		........
      })
	  //遍历所有下拉选项,用左边去数据项跟二级菜单中查是否有值,有则模拟点击并且推出方法,没有则往下
	  for (let key in this.firstFloor){
        if (this.subMenu[key].length !== 0 || this.subMenu2[key].length!==0){
          this.$nextTick(()=>{
            $(".a-sub")[key].click();
          })
          break
        }
      }
      this.columns = [{
        title: '序号',
        dataIndex: 'index',
        align: 'center',
        width: 100,
        ellipsis: true,
        customRender: (text, record, index) =>
            `${
                (this.pagination.current - 1) * this.pagination.pageSize +
                (index + 1)
            }`,
      }]
    }
  },
  
  //获取数据库当中英文脚本跟中文的对应值放到属性当中
  getScriptName(){
    getAll().then(res=> {
      res.data.forEach(item => {
        this.$set(this.scriptName, item.spareOne, item.scriptName);
      })
    })
  },
  
  //获取所有从数据方法
  initTableList(taskId){
    let id = this.$route.params.record.id;
    let param={
      firmwareId:id,
      taskId:taskId
    }
    getTableList(param).then(res=>{
      this.spinning1=false
      if(res.data){
        let keys =Object.keys(res.data);
        let scripts = new Array();
		//接口返回带数量的名称,这里先删除掉数量,找到对应的中文再将数量添加进去
        for (let i = 0; i < keys.length; i++) {
          let value = keys[i];
          let index = value.indexOf("(");
          let newValue = value.substring(0,index);
          let sum = value.substring(index);
		  //找到对应的中文名
          let newScriptName = this.scriptName[newValue]+sum;
          let script = {name:newScriptName,value:newValue};
          scripts.push(script);
        }
        this.tableList2 = scripts;
        this.$nextTick(()=>{
          $(".ant-tabs-tab")[0].click();
        })
      }else{
        this.tableTitle = data
        let column = this.columns[0];
        this.columns=[];
        this.columns.push(column);
        this.data=[];
        this.pagination.total = 0
      }
    })
  },
  
  
  //从数据切换方法
  getInfos(item) {
    if (item.name!=='暂无数据'){
      console.log('暂无数据')
      this.spinning2=true
      this.tip='数据努力加载中......'
    }else {
      this.spinning2=false
      this.data=[]
      this.listTitle=[]
    }
    //将点击的数据赋值给数据标题
    this.tableTitle = item.name
    this.tableTitleValue = item.value
    
    //这段代码是Vue.js中的路由参数获取方法,用于获取路由中的参数值。
    //具体来说, this.$route.params 是一个对象,包含当前路由中所有的参数。
    //而 .record.id 则是获取名为 record 的参数对象中的 id 属性值。 
    let firmwareId = this.$route.params.record.id;
    let param={
      firmwareId:firmwareId,
      taskId:this.taskListDefault
    }
    param.type = item.value;
    getTableList(param).then(res=>{
      this.spinning2=false
      let data = res.data;
      if(data){
        console.log(data)
        let cwedatas;
        let columIndex =  this.columns[0];
        let colum = new Array();
        this.listTitle= []
        colum.push(columIndex);
  	    //动态设置样式为table的数据表头以及数据
        if(item.value == 's20_shell_check'){
          cwedatas = data;
  		  //固定的colum新增此数据的表头
          colum.push(...s20Col);
        }
        ...
  	  
		//设置哪些数据展示样式为Map<List>的数据表头以及数据
        if (item.value == 's15_bootloader' || item.value =='s40_weak_perm' || item.value =='s35_http_file'){
  		
			this.showList=true
			//右侧数据表头
			for (const key in data[0]) {
			this.listTitle.push(key)
			}
	
			//接口返回数据封装这里使用的多个不同的list,可以改成使用一个数据map然后循环写入,右侧展示的时候可以根据title来取list
			this.taskillList = data[0][this.listTitle[0]]
            this.taskillList1= data[0][this.listTitle[1]]
			......
	
			//数据为空处理
			if (this.taskillList.length<=0){
			this.taskillList = ["暂无数据"]
			}
			....。。
			return
        }
  
		//如果不是Map<List>方法会走到这里那么就展示table样式
        this.showList=false
        this.columns = colum;
        this.data = cwedatas;
        this.pagination.total = cwedatas.length
      }
    })
  },
}

        主要思路就是将左侧导航栏一级菜单作为一个集合,然后循环展示,在点击此top标签页的时候,进行一个数据划分

        将不同类别的数据分到不同的一级导航栏下,没有二级导航栏直接作为数据项展示的放入subMenu对应一级导航栏下标的value中,有二级导航栏的放入subMenu2对应的value中;(提前确定好数据分别是在哪个一级菜单下的)

        subMenu:{0:[],1:[],2:[],3:[],4:[],5:[]},

        subMenu2:{0:[],1:[],2:[],3:[],4:[]},

        如果此从数据存在二级细分模块,写一个二级导航栏下的数据模块map,key是二级导航栏的唯一标识,然后value写这个二级导航栏下的模块集合;

        subMenu3:{二级导航key:['二级目录下模块1','二级目录下模块2'],
            ......
          },

      


        因为二级导航栏下的细分模块现在是写死的,那如果要动态的,空数据模块不显示的话,有两种办法(前提是在点击二级导航栏的时候处理):

        第一种:在点击二级导航栏时,对接口返回数据进行判断,如果返回数据中细分的模块为空就从subMenu3的value中将对应的模块移除掉;(可以创建一个二级目录下模块跟接口返回数据英文key的一个map对象,循环接口返回数据,判断哪个key的value为空,然后去找到这个二级导航栏下的细分模块list,然后去移除掉)

        第二种:就是将上述(下图)更改为map,key为接口返回数据的英文key,value为list

        然后在循环展示二级导航栏下的细分模块时,添加一个v-show属性,也创建一个创建一个二级目录下模块跟接口返回数据英文key的一个map对象去找到对应的英文key,在上图的map中去判断是否有值!

        注意:上面说的是右侧只显示一个list数据。更改了上图的数据解构为map,因为现在非top2不做二次三次分类的数据还存在右侧展示多个list的情况(下图),是多个div展示不同的list,并且用v-show来控制展示几个,改成map以后就可以循环遍历。

        

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Vue顶部导航栏的动态效果,可以采用以下步骤: 1.在Vue组件中定义一个导航栏的数据对象,包括导航栏的标题、菜单项等信息; 2.使用Vue的v-for指令遍历菜单项,生成导航栏的菜单列表; 3.使用Vue的v-bind指令动态绑定导航栏的类名和样式,实现导航栏的样式变化; 4.使用Vue的事件处理机制,监听导航栏菜单的点击事件,实现导航栏菜单的交互效果; 5.使用Vue的路由机制,实现导航栏菜单与页面路由的绑定,实现页面的跳转和切换。 下面是一个简单的Vue顶部导航栏动态实现的示例代码: ```html <template> <div class="navbar"> <div class="navbar-title">{{ title }}</div> <ul class="navbar-menu"> <li v-for="item in menu" :key="item.id" :class="{ active: item.active }" @click="handleClick(item)"> <a :href="item.link">{{ item.name }}</a> </li> </ul> </div> </template> <script> export default { data() { return { title: 'Vue Navigation', menu: [ { id: 1, name: 'Home', link: '/', active: true }, { id: 2, name: 'Products', link: '/products', active: false }, { id: 3, name: 'Services', link: '/services', active: false }, { id: 4, name: 'About Us', link: '/about', active: false }, { id: 5, name: 'Contact Us', link: '/contact', active: false } ] } }, methods: { handleClick(item) { this.menu.forEach(menuItem => menuItem.active = false) item.active = true // 触发路由跳转 this.$router.push(item.link) } } } </script> <style scoped> .navbar { display: flex; justify-content: space-between; align-items: center; height: 60px; background-color: #333; color: #fff; padding: 0 20px; } .navbar-title { font-size: 24px; font-weight: bold; } .navbar-menu { display: flex; justify-content: center; align-items: center; height: 100%; margin: 0; padding: 0; } .navbar-menu li { list-style: none; margin: 0 10px; padding: 0; } .navbar-menu li.active a { color: #f00; } .navbar-menu li a { color: #fff; text-decoration: none; transition: color 0.3s ease-in-out; } .navbar-menu li a:hover { color: #f00; } </style> ``` 在这个示例中,我们定义了一个navbar组件,包含了导航栏的标题和菜单项。通过v-for指令遍历菜单项,生成导航栏的菜单列表。使用v-bind指令动态绑定导航栏的类名和样式,实现导航栏的样式变化。通过事件处理机制,监听导航栏菜单的点击事件,实现导航栏菜单的交互效果。最后,通过路由机制,实现导航栏菜单与页面路由的绑定,实现页面的跳转和切换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值