首页 > 解决方案 > Vue vuetify 数据表动态单元格加载

问题描述

<template>
  <v-data-table
    :headers="headers"
    :items="records"
    :items-per-page="5"
    show-select
    loading
    item-key="id"
    class="elevation-1"
  >
    <template v-slot:top>
      <div>
        <table-tabs></table-tabs>
        <v-text-field
          append-icon="mdi-close"
          class="mx-4"
          flat
          hide-details
          label="Search"
          prepend-inner-icon="mdi-magnify"
          solo-inverted
        ></v-text-field>
      </div>
    </template>
    <template v-slot:item.id="{ item }">
      <product-instance-cell v-bind:item="item" :data="item"></product-instance-cell>
    </template>
    <template v-slot:item.boxCode="{ item }">
      <serial-cell v-bind:boxCode="item.boxCode" :serial="item.boxCode"></serial-cell>
    </template>
    <template v-if="hasField('manager')" v-slot:item.manager="{ item }">
      <user-cell v-bind:user="item.manager" :user="item.manager"></user-cell>
    </template>
    <template v-slot:item.customer="{ item }">
      <customer-cell v-bind:customer="item.customer" :customer="item.customer"></customer-cell>
    </template>
    <template v-slot:item.updatedAt="{ item }">
      <date-cell v-bind:updatedAt="item.updatedAt" :date="item.updatedAt"></date-cell>
    </template>
  </v-data-table>

如下所示,我必须直接在模板下传递字段名称和单元格组件才能为特定模型和字段绘制自定义单元格。

   <template v-slot:item.id="{ item }">
      <product-instance-cell v-bind:item="item" :data="item"></product-instance-cell>
    </template>

但我坚持要做的是动态加载单元格,因为我的表没有特定的使用模型。该表可以绘制 5 种不同类型的模型Array<T>,我有一个名为的东西table spec,其中包含绘制表所需的所有信息。例如标题单元格名称、排序逻辑、最大行数、模型 <-> 字段名称的单元格组件名称等。

处理不需要其他模板的数据表头很容易,并且上面的完整模板代码也可以工作。但仅适用于一种型号。我想用规范数据创建超级动态表。如何做到这一点?

不是针对这种情况的具体解决方案,但欢迎其他 vue 的哲学方法。

标签: javascripttypescriptvue.js

解决方案


我今天处理了一个类似的问题,制作了一个非常动态的表,它为每个模型呈现不同的但有一些列,也就是v-slot:item.<name>共同的。

我有一个通用的 headers json 对象,它具有表应该为每个模型呈现的所有属性,它看起来像这样:

"headers": [
    { "text" : "Data / Hora" ,       "value" : "date" ,             "filterable" : true ,   "sortable" : true ,     "type" : "text-date" , "align" : "left" , "format" : "AAAA-MM-DD HH:MM" },
    { "text" : "Tipus pujada" ,      "value" : "upload_type" ,      "filterable" : true ,   "sortable" : false ,    "type" : "text"      , "align" : "center"    },
    { "text" : "Elements" ,          "value" : "elements" ,         "filterable" : true ,   "sortable" : false ,    "type" : "text"  },
    { "text" : "Rebut i validat" ,   "value" : "status" ,           "filterable" : true ,   "sortable" : false ,    "type" : "chip" ,   "style": [ { "color" : "red", "value" : "ERROR" } , { "color" : "green" , "value" : "OK" } ] },
    { "text" : "Log" ,               "value" : "log" ,              "filterable" : false ,  "sortable" : false ,    "type" : "icon" ,   "icon": "mdi-magnify" , "event" : "click" , "action" : "openDialog" },
    { "text" : "Fitxer pujat" ,      "value" : "uploaded_file" ,    "filterable" : false ,  "sortable" : false ,    "type" : "icon" ,   "icon": "mdi-file" , "event" : "click" , "action" : "downloadJSONFileFromJSONData", "url" : "xxxxxxxx", "filename" : "AAAA-MM-DD-filename.json" }
]

因此,我可以渲染所有具有相同标题类型的列,例如iconor textchip就好像它们在哪里一样。

为了解决让它工作而不用专门为每个标题命名,我使用了可以按类型过滤标题槽的计算属性:

computed: {
  computedHeaders: function () {
    //Filters the headers of type Icon
    return this.headers.filter(header => header.type==='icon');
  }
}

所以我可以渲染所有有共同点但命名不同的插槽:

<template v-for="(head,i) in computedHeaders" v-slot:[`item.${head.value}`]="{ item }">
 <v-icon
    :key="i"
    v-text="head.icon"
  >
  </v-icon>
</template>

推荐阅读