这段时间,在开发过程中接到一个需求,当时接到这个需求的时候,本来想着是找一找ui组件啥的来,但是后面找了一圈后,没有找到符合的,没办法,只能自己花点时间写一下了
先看下需求,在页面的顶部加入一样table,当我们点击table时底部的页面切换,中间的内容根据切换的tab来切换,tablei里还有小table,当点吉小table时,小table也跟着切换,先来看下实际的结果图
先说一下我的逻辑吧,我将顶部的table写成一个组件,将父组件渲染table的数据通过props将数据传递过来,在用watch监听props数据,当切换父组件时,顶部table实时更新,代码如下:
通过将父组件的数据拿到后,在页面上渲染出来,然后写2套css,一套是选中的状态还有一套是没有选中的状态,在html代码里,给class加上三木运算,根据某个参数来觉得当前选中的内容,
到现在是实现了,当点击父组件的内容是,顶部table实时更新,然后要实现的就是我们点击顶部的table,父组件的内容更新了,这里我们需要做的就是,获取到当前点击的是什么内容,然后通过emit函数,将我们选中的内容传递出去,让父组件根据我们传递的数据实时渲染。大概逻辑就是,我们顶部table里分一级table和二级table,这些都是通过for循环渲染出来的,for循环的key不就是最好的数据吗?代码如下
然后,因为我们的二级table是写在一级table里的,所以我们在一级table的点击事件里把emit写上,当我们点击一级table时,将当前选中的数据传递出去;
到这里后,还有一个小bug,就是,比如我们切换第一个table,第一个table的二级table选中了某一项后,然后切换到第二个table时会导致里面的二级table没有重置,因为我选中哪一个table都是通过下标来确定的,下标没有重置就会导致没有数据,比如我第一个table有3个二级table,而第二个table则只有2个,当我们在第一个table时将二级table选中第三个的话,就会导致我们切换到第二个table时第二个table的二级table没有选中数据,因为没有下标是2的数据,这时候我们就要监听一级table的下标,当下标变化时,将二级table的下标重置为0,也就是重新选中第一个table。
这里解释下,为什么在emit那里要用到settimeout,这是因为,像父组件传值比我们赋值要快,这样就是导致像父组件传的值都是旧值,,简单说,wacth比emit执行的慢,只能让emit等待下了,等watch将数据更新后在提交了。
总代码如下:
<template>
<div class="table-container">
<table cellspacing="0" cellpadding="0">
<tr>
<td :class="outerindex == key ? 'box' : 'onbox'"
:style="key == 0 ? 'border-radius: 4px 0px 0px 4px;' : key == length - 1 ? 'border-radius: 0px 4px 4px 0px;' : ''"
v-for="(item, key) in tabledata" :key="key" @click="table(key)">
<span>{
{ item.name }}</span>
<div>
<button v-for="(itemb, key) in item.tab" :key="key"
:class="withinindex == key ? 'button' : 'onbutton'" @click="innertable(key)">{
{ itemb.tabName
}}</button>
</div>
</td>
</tr>
</table>
</div>
</template>
<script lang="ts">
import { reactive, ref, watch, onMounted, computed } from "vue"
export default ({
name: 'tab',
props: {
tablearr: Object
},
setup(props: any, contest: any) {
// 思考 ref 响应式和 reactive 响应式的区别; 修改对象属性值,是否会刷新数据
let tabledata = reactive(props.tablearr)
console.log(props.tablearr, 12)
let outerindex = ref(0) //外层大table每次默认选择第一个
let withinindex: any = ref(0) //里层小tab每次进入时默认选择第一个
const length = ref(0)
onMounted(() => {
length.value = props.tablearr.length
})
watch(props, () => { //监听父组件传过来的props数据,当父组件切换小table时,子组件实时更新
tabledata = props.tablearr
})
watch(outerindex, () => { //当切换最外层的的table时,必须将里层的table重置到第一位
withinindex.value = 0
})
const table = (key: any) => { //点击大table对小tab进行切换
outerindex.value = key
setTimeout(()=>{contest.emit("item", [outerindex.value, withinindex.value])},50)//当点击table时,将当前选择的是哪个table告诉父组件,暂定格式是 [外层table的下标,里层table的下标]
}
const innertable = (key: any) => {
withinindex.value = key
}
return {
tabledata,
outerindex,
table,
withinindex,
length,
innertable
}
}
})
</script>
<style lang="stylus" scoped>
.table-container{
td{
height:68px;
width:173px;
}
span{
font-weight: 550;
font-size:16px;
}
button{
width:45px;
height:30px;
border: none;
margin-left:2px;
}
/*选中的状态 */
.box{
border: 1px solid #26D6B9;
background: #F8FFFE;
table{
border: 0;
}
span{
font-family: "思源黑体 Regular";
color: #3E3E3E;
}
.button,.onbutton{
border-bottom: 2px solid #26D6B9;
background:rgba(0,0,0,0);
color:#0AC8A9;
}
.onbutton{
border-bottom: 2px solid #E4E7ED;
color:#707070;
}
}
/*未选中的状态 */
.onbox{
border: 1px solid #DCDFE5;
span{
color: #707070;
}
button{
border-bottom: 2px solid #E4E7ED;
background:rgba(0,0,0,0);
color:#707070;
}
}
}
</style>
父组件传递来的数据:
tabs: [{buttonName: '新增排放源',
tab: [
{ tabName: '材料', name: 1, sendType: 10 },
{ tabName: '能耗', name: 2, sendType: 11 },},
{buttonName: '新增排放源',
tab: [
{ tabName: '材料', name: 1, sendType: 10 },
{ tabName: '能耗', name: 2, sendType: 11 },}]
BAIBAI