二次封装View Design的table组件,实现宽度自适应,内容在一行展示

由于table组件本身并不支持宽度自适应,但实际项目需要,而且多处有用到table组件,所以尝试着自己来二次封装一下组件

想法

刚开始的想法很简单,就是获取每一列中数据和标题在表格中的长度,然后将当中最大的长度作为该列的宽度就可以了。

但是我们怎么才能知道它们在表格中的长度呢?

打开F12查看表格中的数据,我们可以发现,数据的外面包了一层span标签,而且父元素设置了padding

那我就在想,能不能自己手动创建一个span标签包裹数据,然后通过offerWidth获取宽度呢?

实践

说干就干!

jsx 复制代码
// calculateColumnWidth.js文件
const getTextWidth = str => {
  const span = document.createElement('span')
  span.style.display = 'inline-block'
  span.style.visibility = 'hidden'
  span.style.fontSize = '14px'
  span.innerText = str
  document.body.appendChild(span)
  const width = span.offsetWidth
  document.body.removeChild(span)
  return width + 36 + 15
}

export const calculateColumnWidth = (columns, data) => {
  columns.forEach(c => {
    if (c.type === 'selection') return
    const arr = data.map(d => d[c.key])
    arr.push(c.title)
    // 比较某一列的所有值(包含标题名)
    c.width = Math.max(...arr.map(d => getTextWidth(d)))
  })
}

这里的getTextWidth函数是用来计算每个数据应有的宽度(加36是因为标签的父元素默认设置了左,右padding为18px,而这里加15是想数据不要占满整个表格,左右留有一定的空间。值得注意的是,如果没有修改table中的默认字体大小,则字体大小要保持一致)

而calculateColumnWidth函数是用来计算并设置每列的最大宽度的

尝试引入函数并使用watch来深度监听传入的data数据,如果数据有变,就会调用calculateColumnWidth函数,从而更新columns这个数组对象中的宽度。由于这个table组件如果不传data,也会展示表格(如下图),所以immediate需要设置为true,让calculateColumnWidth函数在页面一加载就执行一次

最终实现宽度自适应的效果,如下图:

无数据时:

有数据时:

总结

二次封装table组件的源代码:

复制代码
<!-- 二次封装table组件 -->

<template>
  <!-- 表格 -->
  <Table v-bind="attrs" ref="childRef">
    <template v-for="k in Object.keys(slots)" #[k] :key="k">
      <slot :name="k"></slot>
    </template>
  </Table>
</template>

<script setup>
import { calculateColumnWidth } from 'utils/calculateColumnWidth'
import { defineProps, ref, useAttrs, useSlots, watch } from 'vue'

const attrs = useAttrs()
const slots = useSlots()
const childRef = ref()
const { widthAuto } = defineProps({
  widthAuto: {
    type: Boolean,
    require: false,
  },
})

console.log('attrs', attrs)
console.log('slots', slots)

// 计算宽度,实现自适应表格内容宽度
widthAuto &&
  watch(
    () => attrs.data,
    () => {
      calculateColumnWidth(attrs.columns, attrs.data)
    },
    { deep: true, immediate: true }
  )

const clearSelect = () => childRef.value.selectAll(false)

//暴露方法
// eslint-disable-next-line no-undef
defineExpose({
  clearSelect,
})
</script>

父组件中使用(使用widthAuto来控制是否要宽度自适应):

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端