功能实现背景

通过Vue3实现后台管理项目一定含有表格功能,基于简单的字段渲染有时候想通过JSON配置来提高开发效率

注意:
1.项目依赖element-plus

使用规则

  1. ColumnRenderPropkey用于:v-for需要的唯一标识
  2. ColumnRenderPropprops用于:继承 el-table-column 所有属性 & 自定义属性
  3. ColumnRenderProptype用于:常在项目中出现且需要转换的字段如时间、钱等等,可自行追加
  4. ColumnRenderPropComponent用于:自定义组件
  5. ColumnRenderProprender用于:自定义渲染函数
  6. columns中优先级排序 component < render < type < props

项目代码

  1. 创建type/index.ts文件
export interface ColumnRenderProp {
  key?: string // 遍历使用key
  props?: Record<string, any> // 继承 el-table-column 所有属性 & 自定义属性
  type?: 'date'	// 常用格式的 el-table-column
  component?: Component // 自定义组件
  render?: Function // 渲染函数
}
  1. 创建ColumnRender.vue文件
<template>
  <!-- key渲染优先级: column.key > column.props.prop > index-->
  <template v-for="(column, index) in columns" :key="column.key || column.props?.prop || index">
    <!-- 优先:component -->
    <component v-if="column.component" :is="column.component" v-bind="column.props" />
    <!-- 其次:render -->
    <el-table-column v-else-if="column.render" v-bind="column.props">
      <template v-slot="props">
        <component :is="column.render(props)" />
      </template>
    </el-table-column>
    <!-- 日期 -->
    <el-table-column v-else-if="column.type === 'date'" v-bind="column.props">
      <template v-slot="{ row }: { row: any }">
        <div>{{ parseTime(row[column.props?.prop]) || EMPTYDESC }}</div>
      </template>
    </el-table-column>
    <el-table-column v-else v-bind="column.props" />
  </template>
</template>

<script setup lang="ts">
import type { ColumnRenderProp } from '@/types/index.ts'

defineOptions({
  name: 'IPSColumnRender'
})

defineProps<{
  columns: ColumnRenderProp[]
}>()

// 时间格式化 => 需自己实现
function parseTime(val: number) {
  return val
}
</script>

  1. 创建ColumnState.vue文件 => 自定义组件
<template>
  <el-table-column v-bind="$attrs">
    <template v-slot="{ row }">
      <div class="el-primary">{{ row.state }}</div>
    </template>
  </el-table-column>
</template>
  1. 创建ColumnHandle.vue文件 => 自定义组件
<template>
  <el-button type="primary" @click="handleDetail">{{ deleteVal }}</el-button>
</template>
<script setup lang="ts">
const props = defineProps<{
  deleteVal: string,
  row: any
}>()
const emit = defineEmits<{
  (e: 'detail', value: any): void
}>()

function handleDetail() {
  console.log('handleDetail', props.row)
  emit('detail', 123)
}
</script>
  1. 实现代码
<template>
  <el-table :data="tableData" style="width: 100%">
    <ColumnRender :columns="columns" />
  </el-table>
</template>

<script setup lang="ts">
import ColumnRender from './ColumnRender.vue'
import ColumnState from './ColumnState.vue'
import ColumnHandle from './ColumnHandle.vue'

import { computed, h } from 'vue'

const tableData = [
  {
    name: '张三',
    state: '已完成',
    date: '2019-05-03',
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    name: '王五',
    state: '已下单',
    date: '2019-05-03',
    address: 'No. 189, Grove St, Los Angeles',
  }
]

// 如果里面数据不会发生改变,可以移除 computed
const columns = computed(() => [
  {
  	// 普通渲染模式
    props: {
      label: '姓名',
      prop: 'name',
      width: '180'
    }
  },
  {
  	// 组件渲染模式
    key: 'state',
    props: {
      label: '状态',
      width: '180'
      // 此处可以接收组件自定义事件,也可以给组件传递props
    },
    component: ColumnState
  },
  {
  	// 自定义渲染模式 => 可接收内部事件
    key: 'handle',
    props: {
      label: '操作',
      width: '180'
    },
    render({ row }: { row: any }) {
      return h(ColumnHandle, {
        row: row,
        deleteVal: '详情1',
        onDetail(val: any) {
          console.log(val, row.name, '22==')
        }
      })
    }
  }
])
</script>

更多推荐