场景:因为从数据需要分类,所以在主数据详情页要加一个顶部的标签来实现分类,再根据左侧的从数据id来实现浏览从数据,但是其中有一个分类下面又分了层类,所以要用到左侧导航栏,样式如下:
第一种:左侧没有层级导航直接是从数据模块
第二种:左侧从数据包含层级导航栏
{{ item }}
{{item2.name}}
{{item4}}
{{item.name}}
{{ tableTitle }}
确认
{{item}}
{{item}}
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:'',
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以后就可以循环遍历。