vite+vue3+ts+pinia+Naive UI 项目实战 —— 数据表格与渲染函数

2,770 阅读3分钟

接前两篇 《项目创建与初始配置》《国际化配置》 继续搭建我们的后台项目。

后台管理项目中大量使用的组件之一就是表格了,在 Element Plus 中,表格组件大概是这样使用的:

<!-- 代码片段一 -->
<template>
  <el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column label="Name" width="180">
      <template #default="scope">
        <el-tag>{{ scope.row.name }}</el-tag>
      </template>
    </el-table-column>
  </el-table>
</template>

只要把从接口获取的数组数据 tableData 传给 el-table 的 data,然后表格的每一列要显示什么数据就通过 el-table-column 的 prop 指定,如果需要对数据进行特殊处理可以使用插槽的形式,与之前 vue2 项目中我大多使用的 element ui 的写法一脉相承。

数据表格

Naive UI 则提供了数据表格组件 <n-data-table> 来显示数据。当我第一次阅读其演示代码时,却发现其写法与 Element Plus 大相径庭,虽然表格数据同样是通过 data 属性接收,但需要展示的列的显示则是直接通过另一个属性 columns 来定义:

<!-- 代码片段二 -->
<template>
  <n-data-table
    :columns="columns"
    :data="data"
  />
</template>

columns 的值需要是一个类型为 Array<DataTableColumn> 的数组,以我项目中的代码为例,大概是下面这样的:

// 代码片段三
import { h } from 'vue'
import { NTag } from 'naive-ui'
import type { DataTableColumn } from 'naive-ui'
const columns: DataTableColumn<any>[] = [
    {
      title: '快递单号',
      key: 'trackingNumber'
    },
    {
      title: '运费',
      key: 'isFeePaid',
      render(row) {
        return h(
          NTag,
          {
            type: row.isFeePaid ? 'success' : 'error',
            bordered: false
          },
          {
            default: () => {
              return row.isFeePaid ? '已支付' : '未支付'
            }
          }
        )
      }
    },
    // ...
  ]

在需要对某列的数据做特殊处理时,使用到了渲染函数 render,其返回值为 h()。这种不是在 <template> 内来编写 html,而是在 ts 中使用渲染函数来生成表格的写法,就需要我们对渲染函数和 h 函数有一定的了解,下面就做个简单的介绍。

渲染函数

h() 函数

我们编写的 <template> 中的 html,会经过编译生成渲染函数,然后执行生成对应的 VNode。在选项式 API 中,vue 其实也提供了渲染函数 render(),在 render() 内,我们可以通过 vue 提供的另一个函数 h(),来生成需要返回的 VNode,也就是 Naive UI 文档 中 taTableColumn Properties 里指明的返回值 VNodeChild

image.png h 是 hyperscript —— 一个基于 js 编写模板的工具 ——的简称,其实更准确的名称应该是 createVnode(),只不过用 h 更简便。

注意,如果是以选项式 API 的这种方式使用 render 函数,在 .vue 文件中就不要再有 <template> 的代码了,不然看不到渲染结果。

使用

h() 函数接收 3 个参数,除第一个外都为可选:
第一个参数是 tag,可以是一个 html 标签名或一个组件(可以是异步组件或函数式组件);
第二个参数是 props,可以是 attribute 或 property 或者事件对应的对象。如果没有可以不传,但容易引起歧义,所以如果没有 props 可以传 null
第三个参数是 children,可以是使用 h() 构建的子 VNode,或者是文本字符串,或者是有插槽的对象。

比如我们将上面的代码片段三里使用到渲染函数的部分为例:

render(row) {
  return h(
    NTag, 
   {
     type: row.isFeePaid ? 'success' : 'error',
     bordered: false
   },
   {
     default: () => {
       return row.isFeePaid ? '已支付' : '未支付'
     }
   }
  )
}

第一个参数传的就是另一个组件 NTag(标签);
第二个参数里面都是 NTag 对应的属性;
而第三个参数则是使用到了插槽,default 代表是传递给子组件默认插槽的,值为一个函数,其接收从子组件传递过来的数据作为参数(虽然上例中没有用到,但这也可以帮助理解作用域插槽功能的实现)。插槽中的内容则是使用三元运算符做了个判断。

渲染效果

image.png

感谢.gif 点赞.png