许彰午头像
关注

47-MetaGrid元数据表格

47-MetaGrid:16.5KB的元数据表格

列表页的万能组件——三种数据模式(server paging/store/manual)、#[fieldName]具名插槽定制列、#operations操作列、三种导出、行内编辑、复选选择。16.5KB的Vue文件是组件库里最大的通用件。这篇拆模板层的插槽路由和script层的三模式数据源。

源码:browise-vue/src/components/grid/MetaGrid.vue(16.5KB)
底座:vxe-grid(VXE-Table 4.7)+ el-pagination


一、模板层:vxe-grid的插槽路由

<vxe-grid :columns="gridColumns" :data="displayData" ...>
  <!-- 动态列插槽:#[字段名]_default -->
  <template v-for="f in slotFieldNames" :key="f" #[`${f}_default`]="scope">
    <slot :name="f" v-bind="scope" />
  </template>
  <!-- 操作列固定插槽 -->
  <template v-if="hasOperations" #operations_default="scope">
    <slot name="operations" v-bind="scope" />
  </template>
</vxe-grid>

插槽转发模式——vxe-grid的列渲染走字段名_default插槽——MetaGrid把父组件传来的同名插槽原样转发进去

<!-- 使用方 -->
<MetaGrid storeName="userStore">
  <template #psnSex="{ row }">
    <el-tag :type="row.psnSex === '1' ? 'success' : 'info'">
      {{ row.psnSex === '1' ? '男' : '女' }}
    </el-tag>
  </template>
  <template #operations="{ row }">
    <el-button @click="edit(row)">编辑</el-button>
  </template>
</MetaGrid>

#[...]的动态插槽名——Vue3的v-slot简写支持模板字符串——父组件声明什么字段名的插槽,哪一列就被定制——其他列走默认渲染。定制粒度=列,不需要整个columns重写。

slotFieldNames的来源——useSlots()拿父组件传的插槽名数组——过滤出与columns字段匹配的——只转发有效的。


二、三种数据模式

const props = withDefaults(defineProps<{
  storeName?: string     // 模式1/2:store的名字
  pageUrl?: string       // 模式1:服务端分页URL
  columns?: FieldMeta[]  // 模式2/3:列定义
  ...
}>)
模式配置数据来源典型场景
server pagingpageUrl自己发请求翻页大数据量标准列表页
store绑定storeNameuseStore(storeName).rowset主从联动/编辑提交
manualcolumns+data prop父组件灌数据一次性展示/嵌套表格

模式1(server paging)的自循环

async function loadPage() {
  loading.value = true
  const resp = await httpClient.request({
    url: props.pageUrl, method: props.pageMethod,
    data: { ...queryParams, minRow, maxRow }
  })
  displayData.value = resp.data.rows
  displayTotal.value = resp.data.total
  loading.value = false
}
onPageChange → loadPage()   // 翻页自动加载

模式2(store绑定)的响应式直通

const stores = inject(STORE_MAP_KEY, new Map())
const store = computed(() => stores.get(props.storeName))
const displayData = computed(() => store.value?.rowset.getPrimary())
// rowset的行变化(增删改)→ displayData自动重算 → 表格更新

关键差异——模式1的displayData是本地ref(自己管);模式2是computed直通store(别人管,谁改rowset谁负责)。同一组件两种数据所有权模型——props驱动哪个就走哪个。


三、gridColumns:FieldMeta到vxe列的翻译

const gridColumns = computed(() => {
  const cols = (props.columns || store.value?.meta?.columns || [])
    .filter(f => f.visible !== false)      // meta里visible=false的列不显示
    .map(f => ({
      field: f.name,
      title: f.label,
      width: f.width || undefined,
      // codeName有值 → 字典翻译formatter
      formatter: f.codeName ? dictFormatter(f.codeName) : undefined,
      // displayType → 编辑器类型(行内编辑时)
      editRender: props.editable ? editorFor(f.displayType) : undefined,
      slots: { default: `${f.name}_default` }   // 插槽路由
    }))
  // 复选列/序号列/操作列按配置前置后置
  ...
})

columns的三级来源——props.columns > store.meta.columns > 空——直接传列定义(模式3)或靠元数据自动生成(describe的结果)。零代码模式下MetaGrid连columns都不传——describe元数据经store.meta到达——列从元数据自动长出来

dictFormatter——codeName字段挂字典翻译——显示时row[f.name]的码值(“1”)翻译成名称(“男”)——字典来自useDict的缓存(第53篇dict模块的前端侧)。


四、行内编辑的editRender

function editorFor(displayType: string) {
  switch (displayType) {
    case 'date':   return { name: '$input', props: { type: 'date' } }
    case 'number': return { name: '$input', props: { type: 'number' } }
    case 'datetime': return { name: '$input', props: { type: 'datetime' } }
    default:       return { name: '$input' }
  }
}

editabled的表格开启行内编辑——双击单元格进入编辑——vxe的edit-closed事件触发——新值写回Row

function onEditClosed({ row, column }) {
  const storeRow = 找到对应的Row实例
  storeRow.setItemValue(column.field, row[column.field])
  // setItemValue的脏标记自动生效——collect('dirty')能收集到
}

行内编辑直通脏标记协议——表格改完collect提交——和表单编辑同一条链。


五、三种导出

function onExport(command: string) {
  if (command === 'server')     → window.open(exportUrl + '?token=...&' + 查询参数)
  if (command === 'client')     → 导出displayData(当前页数据)到Excel
  if (command === 'checked')    → 过滤选中的行导出
}
导出数据范围实现
server服务端全量(按当前查询条件)后端ExportController(11.7KB通用导出)
client当前加载的数据前端直接生成(数据已在内存)
checked勾选的行复选过滤后同client

server导出带token的坑——window.open发GET请求不能带Authorization头——token拼在query string(getAccessToken())——后端ExportController兼容query取token(与JwtAuthFilter的Cookie通道同理——第26篇双通道的第三变体)。


✅ 亮点:动态插槽名转发实现列级定制、三种数据模式的所有权差异(本地ref vs computed直通)、FieldMeta到vxe列的翻译层(含字典formatter)、行内编辑直通脏标记、三种导出的token传递方案。适合封装通用表格的人。扩展方向:第13篇describe元数据、第46篇useCenter、第24篇autoCount(total的来源)。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/yuhou25/article/details/165568453

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--