本来想在 jsfiddle 重现下的, 结果没有成功, 就给大家看截图吧
截图
vue 版本: 2.5.3
element-ui 版本: 1.4.13
浏览器: chrome 66.0.3359.170
大家可以发现, 固定了高度的 table 不仅出现了纵向滚动条, 横向滚动条也出现了 (只能滚动一点点), 其实宽度是足够显示的.
然后将问题在网上搜寻, 查到了相关的 issues
- https://github.com/ElemeFE/element/issues/2945
- https://github.com/ElemeFE/element/issues/78
其中 #78 的问答者给出了一个解决方案 https://github.com/QingWei-Li/element/commit/a019e57da9f6271d120e04c67ab330c4f48e56c6
有一点和 #78 相似, 我的 table 也是配置化的, 表头和内容都是作为属性传过去, 可能导致表格在初次渲染时宽度计算不准确, 导致最后宽度超过了 2px(经查验是 border 的宽度); 但解决方案不适用, 一方面项目采用的是 cdn 加载方式, 另一方面我尝试了 1.4.13 版本和解决方案的 1.0.1 版本代码结构不一致, 而我对 element 组件不了解无从下手, 所以我尝试自己去解决.
先贴上我配置化 table 的代码, 便于后面查阅
- <template>
- <div>
- <el-table border :data="data" height="550" v-loading="isLoading">
- <el-table-column v-for="{value, label, options} in columns" :key="value" :label="label" :prop="value">
- <template slot-scope="{row}">
- <span v-if="!options">{{row[value]}}</span>
- <div v-else-if="options && options.filter">{{row[value] | filterData(options.filter)}}</div>
- </template>
- </el-table-column>
- <el-table-column label="操作">
- <template slot-scope="{row}">
- <!-- 这里可在父级插入自定义操作按钮 -->
- <slot :row="row"/>
- </template>
- </el-table-column>
- </el-table>
- <Pagination :total="total" @fetchData="$emit('fetchData')"/>
- </div>
- </template>
- <script>
- import Pagination from 'FORM/Pagination'
- import {formatTimestamp} from 'UTILS'
- export default {
- props: {
- isLoading: {
- type: Boolean,
- default: false,
- required: true
- },
- columns: {
- type: Array,
- default: [],
- required: true
- },
- data: {
- type: Array,
- default: [],
- required: true
- },
- total: {
- type: Number,
- default: 0,
- required: true
- }
- },
- components: {
- Pagination
- },
- filters: {
- filterData: function (value, filter) {
- if (!filter) return value
- switch (filter) {
- case 'formatDate':
- return formatTimestamp(value)
- break;
- default:
- return value
- }
- }
- }
- }
- </script>
方案一: 尝试在渲染后修改数据让 table 重绘
在配置化组件的 updated 钩子更新 columns 数据 (中间做了一层转换, 没有直接修改 props ), 但 table 貌似不会将数据进行双向绑定 (这方面不确定, 只是我调试时修改 table 的内容不能实时更新, 需要刷新浏览器), 所以 table 没有出现改变, 也就不会触发第二次宽度计算.
方案二: 尝试在渲染后将 2px 的 border 去掉
在浏览器中调试发现去掉. el-table 的左右 border 后, 是可以解决内容溢出产生滚动条的问题的; 具体做法是在 updated 1s 后给 el-table 绑定一个 class, 去除 border, 但没有 border 太不美观了...
方案三: 将宽度计算交给浏览器
也是在浏览器中调试, 发现将
.el-table__body-wrapper
的 overflow 属性隐藏再显示, 横向滚动条就不会出现了, 应该是重新添加 overflow: auto; 使得浏览器自身重新计算了 table 的宽度, 所以宽度足够的情况下不需要显示横向滚动条;
那做法就是:
- <!-- template -->
- <el-table ref="configurationTable" border :data="data" :height="height" v-loading="isLoading" :class="['configurationTable', {afterRenderClass: showAfterRenderClass}]">
- <!-- xxx -->
- </el-table>
- // script
- data () {
- return {
- showAfterRenderClass: false
- }
- },
- updated () {
- /**
- * 用于隐藏固定高度时显示不必要的 scrollX 的定时器
- * 这是 el-table 初次渲染时宽度计算的 bug, 可在渲染后通过重新赋予 overflow: auto 调整
- */
- const handleScrollX = setInterval(() => {
- // 检测是否已经生成 table 节点, 如果不是就每隔 0.5s 检测一次
- // 只有生成了真实节点才能够通过修改 overflow 属性让浏览器重新计算
- if (this.$refs.configurationTable) {
- this.showAfterRenderClass = true
- clearInterval(handleScrollX)
- }
- }, 500)
- }
- /** style (注意不要设为 scoped) */
- /** configurationTable 和 afterRenderClass 都是为了标记仅这个组件内修改 */
- .configurationTable .el-table__body-wrapper {
- overflow: hidden;
- }
- .afterRenderClass {
- .el-table__body-wrapper {
- overflow: auto;
- }
- }
总结
因为 element-ui v1 已经停止维护了, 所以也就不提新的 issue 了, 之后还是需要迁移到 element-ui2(如果大家有迁移工具的话欢迎推荐, 官方踩过坑也可以推荐), 不然留下这个黑魔法增加维护成本.
来源: http://www.jianshu.com/p/eeb0c4bd4ae6