自研国产零依赖前端UI框架实战005 封装第一个表格组件

259 阅读5分钟

前言

之前我们已经实现了随机用户数据的生成, 渲染, 格式化美化, 已经具备了基本的功能.

而且我们还封装了一个random随机模块和table样式模块, 能够更好的复用于后面的项目和案例.

接下来我们做些什么呢?

这里我的想法是对表格数据渲染进行封装,封装一个组件,这个组件接收表格的头部信息和内容信息,自动对数据进行提取和渲染.

那么我们开始做吧!!!

实践出真知!!!

简单的组件封装

接下来, 我们直接创建一个zdp_table1.vue, 然后把之前的App.vue中的代码复制过去, 稍微调整一下引入的地址, 代码如下:

<script setup>
import {onMounted, ref} from "vue";
import random from "../js/random.js";
import "../css/table.css";

let users = ref(random.users(8))
</script>
<template>
  <div>
    <table class="table1">
      <thead>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="(user, index) in users" :key="user.id">
        <td>{{ index + 1 }}</td>
        <td>{{ user.name }}</td>
        <td>{{ user.age }}</td>
      </tr>
      </tbody>
    </table>
  </div>
</template>

然后, 在App.vue中引入这个组件就行了, 代码如下:

<script setup>
import zdp_table1 from "./zdpui/components/zdp_table1.vue";
</script>
<template>
  <div>
    <zdp_table1/>
  </div>
</template>

此时的项目结构如下:

在这里插入图片描述

在这里插入图片描述

浏览器访问: http://localhost:5173/

在这里插入图片描述

在这里插入图片描述

可以发现效果还是和之前一样, 并没有变化, 说明我们封装得很成功.

新的想法

这个时候我们就需要进一步封装了, 那么有没有什么新的想法呢?

我的想法是传递一个columns作为头部数据进行, 再传递一个data作为表格数据进来, 但是这两个参数都不是必传的, 如果这两个参数都没有传, 那么我们还是使用原来的随机生成的用户数据.

如果传递了,则使用新的数据替代.

那么这个该怎么玩呢?

我来想一想步骤:

  • 1.在zdp_table1中定义属性,接收columns和data作为参数
  • 2.直接给这两个参数分别赋值默认值, 如果没有传就使用默认值
  • 3.根据columns和data动态渲染表格

那么我们继续开搞!!!

定义表格的属性

首先是columns:

columns:{
    type:Array,
    default:function(){
      return [
        {
          title:"序号",
          key:"id",
          width:80,
          align:"center"
        },
        {
          title:"姓名",
          key:"name",
          width:100,
          align:"center"
        },
        {
          title:"年龄",
          key:"age",
          width:100,
          align:"center"
        }
      ]
    }
  }

然后是数据:

data: {
  type: Array,
    default: function () {
      return random.users(8)
    }
}

接下来表头应该根据columns动态的进行渲染:

在这里插入图片描述

在这里插入图片描述

此时页面的渲染效果如下:

在这里插入图片描述

在这里插入图片描述

可以发现已经生效了, 但是表的内容没有跟随传进来的表头的内容, 所以这个代码还得继续改造一下.

首先见tbody改造如下:

<tbody>
<tr v-for="(v, k) in props.data" :key="k">
  <template v-for="(vv,kk) in props.columns" :key="kk">
    <td>
      {{ v[vv.key]}}
    </td>
  </template>
</tr>
</tbody>

这样我们就能够实现数据是从columns里面动态的取出来的, 此时观察一下页面, 确保页面还是正常的.

然后我们接着开搞!!!

计算列的样式

封装一个方法, 计算列的样式:

const columnStyle = column => {
  let style = {}
  // 长宽对齐等基本样式
  if (column.width) style.width = column.width + 'px'
  if (column.height) style.height = column.height + 'px'
  if (column.align) style.textAlign = column.align
  // 超过一行变省略号
  style.maxWidth = (column.maxWidth ?? 500) + 'px';
  style.overflow = 'hidden';
  style.textOverflow = 'ellipsis';
  style.whiteSpace = 'nowrap';
  return style
}

最后, 再把这个方法应用到表格中:

<table class="table1">
  <thead>
    <tr>
      <template v-for="(v,k) in props.columns" :key="k">
        <th
            :style="getColumnStyle(v)"
            >
          {{ v.title }}
        </th>
      </template>
    </tr>
  </thead>
  <tbody>
    <tr v-for="(v, k) in props.data" :key="k">
      <template v-for="(vv,kk) in props.columns" :key="kk">
        <td
            :style="getColumnStyle(vv)"
            >
          {{ v[vv.key] }}
        </td>
      </template>
    </tr>
  </tbody>
</table>

接着我们再访问 http://localhost:5173/ 进行预览, 可以发现, 不管是表头还是表内容, 都已经实现一致的样式了, 这里都实现了居中对齐的效果.

在这里插入图片描述

在这里插入图片描述

此时, 完整的zdp_table1.vue的代码如下:

<script setup>
import random from "../js/random.js";
import "../css/table.css";

const props = defineProps({
  columns: {
    type: Array,
    default: function () {
      return [
        {
          title: "序号",
          key: "id",
          width: 80,
          align: "center"
        },
        {
          title: "姓名",
          key: "name",
          width: 100,
          align: "center"
        },
        {
          title: "年龄",
          key: "age",
          width: 100,
          align: "center"
        }
      ]
    }
  },
  data: {
    type: Array,
    default: function () {
      return random.users(8)
    }
  }
})

// 获取列的样式
const getColumnStyle = column => {
  let style = {}
  // 长宽对齐等基本样式
  if (column.width) style.width = column.width + 'px'
  if (column.height) style.height = column.height + 'px'
  if (column.align) style.textAlign = column.align
  // 超过一行变省略号
  style.maxWidth = (column.maxWidth ?? 500) + 'px';
  style.overflow = 'hidden';
  style.textOverflow = 'ellipsis';
  style.whiteSpace = 'nowrap';
  return style
}
</script>
<template>
  <div>
    <table class="table1">
      <thead>
      <tr>
        <template v-for="(v,k) in props.columns" :key="k">
          <th
              :style="getColumnStyle(v)"
          >
            {{ v.title }}
          </th>
        </template>
      </tr>
      </thead>
      <tbody>
      <tr v-for="(v, k) in props.data" :key="k">
        <template v-for="(vv,kk) in props.columns" :key="kk">
          <td
              :style="getColumnStyle(vv)"
          >
            {{ v[vv.key] }}
          </td>
        </template>
      </tr>
      </tbody>
    </table>
  </div>
</template>

外部传递数据

我们之前使用的是默认值, 如果我现在有一个员工的数据, 想要渲染员工数据该如何操作呢?

这里为了和默认数据区分, 我特意在columns里面加了员工编号, 然后内容只生成了三条.

修改App.vue, 此时完整代码如下:

<script setup>
import zdp_table1 from "./zdpui/components/zdp_table1.vue";
import random from "./zdpui/js/random.js";

const columns = [
  {
    title: "员工编号",
    key: "id",
    width: 80,
    align: "center"
  },
  {
    title: "姓名",
    key: "name",
    width: 100,
    align: "center"
  },
  {
    title: "年龄",
    key: "age",
    width: 100,
    align: "center"
  }
]
const data = random.users(3)
</script>
<template>
  <div>
    <zdp_table1
        :columns="columns"
        :data="data"
    />
  </div>
</template>

接着我们再访问 http://localhost:5173/ 进行预览, 可以发现, 已经针对自定义的数据, 实现了渲染.

在这里插入图片描述

在这里插入图片描述

哈哈, 做到这一步的时候感觉好爽, 很有成就感!!!

总结

到目前为止, 我们就实现了zdp-table1这个组件的基本封装, 支持传递自定义的样式, 支持自定义表头, 表数据会自动根据表头的配置自动提取数据, 整体而言, 这个表格还是相对比较强大的.

不过这都只是玩具级别的, 因为真正的数据大部分情况下都是非常多的, 我们不可能一次性把这么多数据直接渲染出来, 我们还需要支持分页.

所以接下来要研究一下,分页该如何搞, 怎么把分页封装到我们的表格组件里面去.