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

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

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

Vue实现顶部标签以及左侧层级导航栏_第1张图片

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

Vue实现顶部标签以及左侧层级导航栏_第2张图片

HTML 代码


  
{{ item }} {{item2.name}} {{item4}}
{{item.name}}
{{ tableTitle }}
{{item}}
{{item}}

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的数据表头以及数据
        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方法会走到这里那么就展示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以后就可以循环遍历。

        

你可能感兴趣的:(vue.js,前端)