欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

元素表列踩坑

最编程 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一看,果然发现了端倪。 image-20220414133426623 可以看到.el-table__body-wrapper就是我们的整个table的内容。 image-20220414133712954

但除了.el-table__body-wrapper,居然还有两个.el-table__fixed-body-wrapper也是我们的整个table的内容!!! table居然在页面上被多渲染了两次!!! 仔细看代码我们就会发现居然是el-table-column的fixed在作怪 flex的作用是用于固定列,像这样 image-20220414134409409image-20220414134314506

没想到这个fixed是靠着重新渲染一个table,再使用css的position:absolute;实现的... em....好了,发现问题所在了,我们想一下怎么解决.这里我想到几个方案

  1. 直接不使用fixed(em...肯定是不行的,我们必须要有固定列)...
  2. 删除fixed,我们自己使用CSS实现固定列
  3. 在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,就不会造成重复请求啦...有更优方案请在评论区留言讨论