还在多次copy ElTable组件吗?试试dyingtable插件吧

981 阅读5分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

hello 大家好,🙎🏻‍♀️🙋🏻‍♀️🙆🏻‍♀️

我是一个热爱知识传递,正在学习写作的作者,ClyingDeng 凳凳!

作为参与了6、8月更文活动的老用户,这期又怎么少得了我呢!嘿嘿!

本文主要针对table表格item多次渲染进行了一个二次封装,节省代码量。将table表头和表体数据独立出来,通过js数据去控制其表头展示文字。

业务需求

我相信在很多业务场景中,尤其是做管理台这种的,有这样的一个需求。每个页面有个一两个表格,但是表格样式可能不同,比如一个页面要这样的:

image.png 另一个页面要这样的:

image.png 又或者是带操作按钮的表格:

image.png

emmm,如果项目小可以不用考虑优化,大不了多写几个表格。一旦遇到大型的项目,再这样一个表格一个sfc是不是不妥呢?如果有个10个表格,那么每个表格内部牵扯到的逻辑操作顺带着查询、对话框每个文件的代码行数都是一个不小的数字,并且内部重复量是非常大的一个数值!

那么,问题来了,如何以尽量少的代码去完成呢?

解决方案

目前,以element-plus为基础组件。只考虑单表格样式、数据、行内操作等情况(查询、分页可以在此基础再进行封装)。将其table组件单独做成一个插件。

实例展示

安装

通过npm命令安装dyingtable。

npm install dyingtable --save

快速上手

在vue项目中的入口文件main.ts中:

import { createApp } from 'vue'
import App from './App.vue'
import DyTable from 'dyingtable'

createApp(App).use(DyTable).mount('#app')

注意:dyingtable 插件是面向Vue3版本哦!vue2版本的封装是混合在其他项目中,有兴趣也可以点击这里去看看哟

demo实现

由于对于表格应用场景有很多demo,可自行前往dyingtable,在此,我们就展示基础表格、选择行表格和多级表头三个demo。

基础表格

先看看element表格 image.png 自己根据所需表格列,去渲染。换个数据不同的表格,再次需要自己去拷贝一份table表格修改。

对于 dyingtable 来说,可以根据传入你所需要的表头和所需对应列的数据即可。
tHeads中的props值需要与tableData中所对应。

表格头部label绑定表头名称,props作为唯一标识,width表格列宽度,align控制列左中右对齐。

<dy-table :tHeads="tHeads" :tableData="tableData"></dy-table>
<script lang="ts">
import Vue, { defineComponent, reactive } from 'vue'
export default defineComponent({
  setup() {
    let tHeads = reactive([
      {
        label: '日期',
        props: 'date',
        width: '200',
        align: 'center',
      },
      ...
    ])

    let tableData = reactive([
      {
        date: '2016-05-02',
        name: '王小虎',
        age: 22,
        address: '上海市普陀区金沙江路 1518 弄',
      },
      ...,
    ])
    return { tableData, tHeads }
  },
})
</script>

效果

basic.png

选择行表格

选择多行数据时使用 Checkbox。 给表格添加ref属性,通过refs给组件内table传入ref属性。给表头添加 { type: 'selection' }属性,展示Checkbox。

<dy-table ref="multiple" :refs="refs" :tHeads="tHeads" :tableData="tableData"></dy-table>
<div style="margin-top: 20px">
  <el-button @click="toggleSelection([tableData[1], tableData[2]])">
    切换第二、第三行的选中状态
  </el-button>
  <el-button @click="toggleSelection()">取消选择</el-button>
</div>
<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
export default defineComponent({
  setup() {
    let tHeads = reactive([
      { type: 'selection' },
      {
        label: '日期',
        props: 'date',
        width: '200',
        sortable: false,
        align: 'center',
        className: 'stripa', // 列样式
      },
    ])

    let tableData = reactive([
      {
        date: '2016-05-02',
        name: '王小虎',
        age: 22,
        address: '上海市普陀区金沙江路 1518 弄',
      },
      {
        date: '2016-04-04',
        name: '王小虎',
        age: 12,
        address: '上海市普陀区金沙江路 1517 弄',
      },
      ...
    ])

    let multiple: any = ref(null)
    let refs = ref('multipleTable')
    let toggleSelection = (rows: any) => {
      let ref = multiple.value.$refs
      if (rows) {
        rows.forEach((row: any) => {
          ref.multipleTable.toggleRowSelection(row)
        })
      } else {
        ref.multipleTable.clearSelection()
      }
    }
    return { tableData, tHeads, multiple, refs, toggleSelection }
  },
})
</script>

效果

multipleSelect.gif

多级表头

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。使用tHeads的children属性来渲染子表头。一定要注意的是:需要展示列数据的,一定要绑定props

<dy-table :tableData="tableData" :tHeads="tHeads"></dy-table>
<script lang="ts">
import { defineComponent, reactive } from 'vue'
export default defineComponent({
  setup() {
    let tHeads = reactive([
      {
        label: '日期',
        props: 'date',
        width: '200',
        sortable: false,
        align: 'center',
      },
      {
        label: '配送信息',
        children: [
          {
            label: '姓名',
            props: 'name',
            width: '200',
            sortable: false,
            align: 'center',
          },
          {
            label: '地址',
            sortable: false,
            align: 'left',
            children: [
              {
                label: '省份',
                props: 'province',
                width: '150',
              }
              ...
            ],
          },
        ],
      },
    ])

    let tableData = reactive([
      {
        date: '2016-05-03',
        name: '王小虎',
        province: '上海',
        city: '普陀区',
        address: '上海市普陀区金沙江路 1518 弄',
        zip: 200333,
      },
    ])
    return { tableData, tHeads }
  },
})
</script>

moreHead.png

效果

rollup 踩坑

在此呢,我也是比较爱折腾。
原本用element-ui、vue2实现了table的封装。
又想着现在的vue3,那就再用vue3和element-plus再试试。
写完了把,又想把这个组件单独拎出来,搞个插件玩玩。好吧,用vue-cli搞的插件跑通了。
又想着要不用rollup试试,这下好了,试着试着,踩到了个大泥潭里面了。。。

看着官网文档,emmm,就像个天书一样🪁🪁🪁
这个学法呢,我是借鉴我之前使用rollup打包的项目配置,先将最基础能够编译ts文件的所需配置先搭建好。

因为我是使用的vue3、element-plus去封装自己的组件。所以必须要安装能够解析vue文件和element-plus的插件并配置的。
安装下段代码中所需依赖:

import Components from 'unplugin-vue-components/rollup'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import vue from 'rollup-plugin-vue'
export default {
 plugins: [
    vue({
      compileTemplate: true,
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    })
  ]
}

你以为安装好,就可以正常跑通了吗,那你可就太天真了🎃

321,来!上BUG:

请问,这是什么问题?

e6a4ee10663625e1adea24f80e243fa.png

这是典型的rollup打包问题: Error: "[name] is not exported by [module]"
一旦遇到什么东西导出错误,一定要检查自己安装的commonjs插件是否支持自己所有依赖的npm模块导出格式。

那这个你知道吗?

14e04146e05b51831b437fd4d9b6f96.png

遇到这个问题当时我百度不得其解,看到唯一一个有点相关的问题,竟然是这个。好家伙,人家直接用vite解决了。。。🙃🙂🙃

想知道我是怎么解决的吗?

🎊铛铛铛,答案揭晓:
当时安装 rollup-plugin-vue 时,直接使用的是 npm i rollup-plugin-vue。。。然后我将其依赖卸载,重新安装,安装时给它加了个 -D。然后,它就好了。我也很无语😶

npm 发版踩坑

npm 发版遇到的问题主要是TLS升级问题。

从 2021 年 10 月 4 日开始,所有与 npm 网站和 npm 注册表的连接(包括软件包安装)都必须使用 TLS 1.2 或更高版本。点击即可查看并升级TLS版本。 除了更新TLS版本之外还要将npm更新到7版本以上版本。
再看看自己的npm版本: 2fe0d0570a73e4a9a8a5e09ffe386fb.png

通常npm版本更新频率是高于node版本更新的。emmm,那就下一个最新版的npm把:

npm install npm@latest -g

此外还需将npm注册表设置为https端点如下图: 288ef8178c907699204e3f7ae7a4ea9.png

至于登录npm账号进行npm发版没有遇到太大问题,在此不再过多赘述。

关于 dyingtable 插件