昨天写的 tabs标签页切换中存在一个问题,除了默认展示的页面,其他页面也可以切换,只是发生了坍缩,挤成了一小块。
-
经过这两天的工作,我总结的问题所在 及注意点。
- tabs是一次性渲染完毕的
- 注意点: 图表的展示需要一个宽高确定的容器
首先 tabs 是一次性渲染完毕的
- 我是这样理解的:
- 图表不是真正意义上的坍缩,而是在一次性渲染的时候他的宽高就那么大,所以图也就那么大. 要想证明也不难,看看图表组件内部的 created 钩子在点击的时候会不会执行就可以。
- 执行-就证明它是会在点击的时候重新构建的。
js
<template>
<div class="charts" ref="chart"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
name: "Chart",
props: {/* ··· */},
created(){
console.log('我被创造出来了!');
},
data() {
return {/* ··· */};
},
mounted() {/* ··· */},
methods: {/* ··· */},
watch: {/* ··· */},
};
</script>
<style scoped lang="less"> /* ··· */ </style>
- 很显然,一经挂载它就执行了9次说明它只会在最初的时候会对这些数据进行处理。
-
通过显示的小图,其实也可以窥见到,每一项的 tab-pane 是有多大(挺有趣的),虽然没啥用。
-
从上面可以得到两个结论
- 1.首次展示是正常的。
- 2.渲染是一次性渲染完毕的。
-
也就是说只有我们看见的时候渲染的组件显示是 "正常" 的。
其次 图表的展示需要 宽高确定的容器
- 容器的高度必须给确定值 百分比无效( el-input的宽度也一样 );
-
无效的情况
-
- 这个问题我在遇见的时候,迷迷糊糊不清楚原因,临时解决是给他设置了 vw 和 wh ( 最大值100 和百分比的用法一样 不过他是 以屏幕大小作为计算依据的 )
- 当时只想着不能给死值,且是在 el-card 的包裹里面 ,怎么设置怎么不生效别说撑开了,让它显示都难。
- el-card 设置样式有一个设定好的方法 :body-style="{width:"100%",/*···*/}" ; 这也是后两天才发现的。( 去翻的文档)
最后 是解决方式
- 既然只有首次挂载,看的见的才能 "正常" 那就每次挂载,都让它 卸载再挂载一次。
- 我采用的方式也是最简单的,就是 v-if
- v-if 为true 时显示组件 为false 时不显示,且dom信息直接消失,是删除不是隐藏。
- v-show 是隐藏 不是消失 (我认为:在大量数据 且切换频繁的组件用 v-show 比较合适),这里并不能起到效果
- 只有把组件删除掉,才会在挂载的时候 触发挂载,不然一直都在的哪里来的挂载。
- 我选择在 点击事件都是用的 为图表更改数据的方法里(省事,只写一次);
js
editOption( index = 0){
this.chartOption.xAxis.data = Object.keys(this.titleContent2[index]);
this.chartOption.series.data = Object.values(this.titleContent2[index]);
this.chartShow = false
clearTimeout(this.time)
this.time = setTimeout(()=>{
this.chartShow = true;
},200);
}
问题出来了,他在切换的时候会缩进去。 原因是切换的时候,它的内容(图表)是销毁了的,没有东西撑着,它就缩进去了。 给tabs 设置固定高度,百分比无效
以下就是完整的代码了!
js
<template>
<div class="box">
<h2 style="color:rgb(122, 105, 204)">el-tabs 渲染</h2>
<el-tabs v-model="value" @tab-click="handleClick">
<el-tab-pane v-for="(item,index) in titleList1" :key="index"
:label="item"
:name="item"
>
<el-tabs style="height:240px" v-model="value2" @tab-click="handle2Click">
<el-tab-pane v-for="(arrItem,index) in titleList2" :key="index"
:label="arrItem"
:name="arrItem"
>
<Chart v-if="chartShow" class="chartHeight"
:option="chartOption"
/>
</el-tab-pane>
</el-tabs>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import axios from 'axios';
import Chart from "../../components/Chart.vue";
export default {
name: "RenderingForObjectForm",
data() {
return {
chartOption: {
xAxis: { data: [] },
series: {
type: "line",
smooth: true,
data: [],
},
},
objData:{},
// 渲染一级 标题的数据
titleList1:[],
// 一级 标题对应的数据
titleContent1:[],
titleList2:[],
titleContent2:[],
value: "",
value2:"",
time:'',
chartShow:true,
};
},
mounted(){
// 我是用了mock
this.getList();//获取数据 的方法
},
methods: {
async getList(){// 初始化
// 我们通过发请求,拿到了数据,并赋值给了 objData
let data = await axios.get("/web/getList")
this.objData = data.data
console.log(this.objData);
// 解析出来渲染一级 标题的数据
this.titleList1 = Object.keys(this.objData);
this.titleContent1 = Object.values(this.objData);
// 首先设置 一级title的默认值
this.value = this.titleList1[0];
this.setList1()
},
handleClick() { // 点击事件
this.setList1()
},
handle2Click() {
this.titleList1.forEach((item,index)=>{
if(item == this.value){
this.titleList2.forEach((item,index)=>{
if(item == this.value2){
this.editOption(index)
}
})
}
})
},
setList1(){
this.titleList1.forEach((item,index)=>{
if(item == this.value){
let t2 = this.titleContent1[index];
this.titleList2 = Object.keys(t2);
this.titleContent2 = Object.values(t2);
this.value2 = this.titleList2[0]
this.editOption()
}
})
},
editOption( index = 0){
this.chartOption.xAxis.data = Object.keys(this.titleContent2[index]);
this.chartOption.series.data = Object.values(this.titleContent2[index]);
this.chartShow = false
clearTimeout(this.time)
this.time = setTimeout(()=>{
this.chartShow = true;
},200);
}
},
components: { Chart },
};
</script>
<style scoped lang="less">
.chartHeight {
height: 200px;
width: 100%;
}
</style>