元素表列踩坑
最编程
2024-04-16 17:59:29
...
Element table column踩坑
前言
element的table相信大家都使用过,它像这样
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column fixed prop="date" label="Date" width="150" />
<el-table-column prop="name" label="Name" width="120" />
<el-table-column prop="state" label="State" width="120" />
<el-table-column prop="city" label="City" width="120">
<template #default="scope">
{{ scope.row.city.name }}
</template>
</el-table-column>
<el-table-column prop="address" label="Address" width="600" />
<el-table-column prop="zip" label="Zip" width="120" />
<el-table-column fixed="right" label="Operations" width="120">
<template #default>
<el-button type="text" size="small">Detail</el-button>
<el-button type="text" size="small">Edit</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
setup() {
const tableData = [];
return {
tableData,
};
},
};
</script>
直至有一天,需求变动
我需要在使用每一条数据的city再去请求,获取详细数据处理完成后再放在页面展示,于是我写成了一个组件,代码变成了这样
//table.vue
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column fixed prop="date" label="Date" width="150" />
<el-table-column prop="name" label="Name" width="120" />
<el-table-column prop="state" label="State" width="120" />
<el-table-column prop="city" label="City" width="120">
<template #default="scope">
<CityText :city="scope.row.city" />
</template>
</el-table-column>
<el-table-column prop="address" label="Address" width="600" />
<el-table-column prop="zip" label="Zip" width="120" />
<el-table-column fixed="right" label="Operations" width="120">
<template #default>
<el-button type="text" size="small">Detail</el-button>
<el-button type="text" size="small">Edit</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
import CityText from './CityText.vue'
export default {
components: {
CityText
},
setup() {
const tableData = [];
return {
tableData,
};
},
};
</script>
//CityText.vue
<template>
<span>{{ cityText }}</span>
</template>
<script>
import { onMounted,ref } from 'vue';
export default {
props: {
city: Object,
},
setup(props) {
const cityText = ref('');
onMounted( () => {
request(`city/${props.city.id}`).then( res => {
//一顿处理
cityText.value = 'xxxxx';
})
})
return {
cityText
}
},
};
</script>
正准备打开F12开一下请求是否正确,却发现出现了多次重复请求,这明显是不合理的。 赶紧打开万能的chrome搜索起el-table-column的BUG,然而在Element官网和github上好像都没有找到类似问题。 我猜想了重复请求的可能,onMounted应该只会执行一次,但我打开F12一看,果然发现了端倪。 可以看到.el-table__body-wrapper就是我们的整个table的内容。
但除了.el-table__body-wrapper,居然还有两个.el-table__fixed-body-wrapper也是我们的整个table的内容!!! table居然在页面上被多渲染了两次!!! 仔细看代码我们就会发现居然是el-table-column的fixed在作怪 flex的作用是用于固定列,像这样
没想到这个fixed是靠着重新渲染一个table,再使用css的position:absolute;实现的... em....好了,发现问题所在了,我们想一下怎么解决.这里我想到几个方案
直接不使用fixed(em...肯定是不行的,我们必须要有固定列)...- 删除fixed,我们自己使用CSS实现固定列
- 在CityText做请求缓存 折腾了一会CSS后,我决定采纳第三种方案...有想法和解决方案的同学可以留言讨论
在CityText做请求缓存
//CityText.vue
<template>
<span>{{ cityText }}</span>
</template>
<script>
import { onMounted,ref } from 'vue';
const cacheCityPromise = {};
const cacheCityText = {};
const cityReq = (city) => {
if( !cacheCityPromise[city.id] ){
cacheCityPromise[city.id] = request(`city/${props.city.id}`)
cacheCityPromise[city.id].then( res => {
delete cacheCityPromise[city.id];
})
}
return cacheCityPromise[city.id];
}
const cityTextPromise = (city) => {
return new Promise( (resolve,reject) => {
if(!cacheCityText[city.id]){
cityReq(city).then( res => {
//一顿处理
cacheCityText[city.id] = 'xxxxx';
resolve(cacheCityText[city.id]);
})
}else{
resolve(cacheCityText[city.id]);
}
})
}
export default {
props: {
city: Object,
},
setup(props) {
const cityText = ref('');
onMounted( () => {
cityTextPromise(props.city).then( cityText => cityText.value = cityText )
})
return {
cityText
}
},
};
</script>
最后
CityText.vue变成了这样,在import CityText from './CityText.vue'时新增了像个缓存变量cacheCityPromise和cacheCityText,就不会造成重复请求啦...有更优方案请在评论区留言讨论