将 v-for 逻辑移动到计算 属性

Move v-for logic to computed property

我的代码没有错(我希望),尽管我觉得它可以写得更好。我尝试将

逻辑从 属性 移动到计算 属性 但没有成功,我认为 table 结构不正确,但我没有想法。任何人都可以帮忙吗? 不幸的是,“tabl”来自服务器,我无法更改此变量

<template>
  <movable-div>
    <template #header>
      <div class="header">
        <h3>{{ name }}</h3>
        <div @mousedown.stop="dragMouseDown">
          <input type="text" v-model="search" placeholder="Search..." />
        </div>
        <div class="button-group">
          <svg width="1.2em" height="1.2em" viewBox="0 0 10240 10240" @click="toggleTable()" :class="[showTable ? 'go' : 'back']">
            <path some long svg code... />
          </svg>
          <p @click="showTableAttributes()">X</p>
        </div>
      </div>
      <table v-if="showTable">
        <tr>
          <th v-for="head in tableHead" :key="head.Name">
            {{ head.Name }}
          </th>
        </tr>
        <tr
          v-for="row in filteredRow"
          :key="row.Key"
          class="data"
          @click="zoomToFeatureExtent(row)"
        >
          <td v-for="item in tableHead" :key="item.Name">
            <p v-html="row.filter((obj) => obj.Key === item.Name)
                  .map((item) => item.Value)
                  .join()
                  .replace(search, `<span style='color:#1D7CA7'><b>${search}</b></span>`)">
            </p>
          </td>
        </tr>
      </table>
    </template>
  </movable-div>
</template>

<script>

export default {
  props: ['olMap', 'LayerStyleName', 'name'],
  data() {
    return {
      tableHead: null,
      rows: null,
      table: {
       ColumnList: [{name: "ex1"},{name: "ex2"}],
       Name: "Example",
       RowList: [{Original:[{Key: "ex1", Value: "exampleValue"}]},
                 {Original:[{Key: "ex2", Value: "exampleValue"}]}]
      },
      showTable: true,
      layer: null,
      filteredRow: [],
      search: null,
    };
  },
  mounted() {
    this.rows = this.table.RowList;
    this.tableHead = this.table.ColumnList.filter((item) => item.Name !== 'geometry');
    this.search = '';
  },
  inject: ['showTableAttributes'],
  methods: {
    toggleTable() {
      this.showTable = !this.showTable;
    },
    zoomToFeatureExtent(value) {
      let extent = value
        .filter((item) => item.Key === 'geometry')
        .map((item) => item.Value);
      let view = this.olMap.getView();
      view.fit(extent[0], this.olMap.getSize());
      let res = view.getResolution();
      if (res < 0.5) {
        view.setResolution(0.9);
      }
    },
  },
  watch: {
    search: function (val) {
      this.filteredRow = [];
      for (let row of this.rows) {
        if (row.Original.map((obj) => obj.Value.toString().includes(val))
            .filter((i) => (i === true ? i : null))
            .join()) {
          this.filteredRow.push(row.Original);
        } else null;
      }
    },
  },
};
</script>

让模板不包含任何复杂逻辑是一种很好的做法(恕我直言)。它使代码更易于维护,因为您没有在模板和脚本之间拆分功能。如果您可以将方法卸载到缓存变量以防止代码的静态部分不必要地重新计算,它还可以提高性能。

以下是改进潜力的一个很好的例子

<tr
  v-for="row in filteredRow"
  :key="row.Key"
  class="data"
  @click="zoomToFeatureExtent(row)"
>
  <td v-for="item in tableHead" :key="item.Name">
    <p
      v-html="row.filter((obj) => obj.Key === item.Name)
        .map((item) => item.Value)
        .join()
        .replace(search, `<span style='color:#1D7CA7'><b>${search}</b></span>`)"
    ></p>
  </td>
</tr>

我发现在模板中阅读此内容比在脚本块(但 YMMV)中更难,但在性能方面您正在执行额外的循环。此脚本执行 3 个循环:行(filteredRow)、列(tableHead),然后再次行(row.filter)。

如果将逻辑移动到computed,可以简化逻辑并提高性能。 computed 将保留数据缓存并根据需要更新,因此如果您更改 search 的值,它将重新计算,但如果不相关的变量发生变化,则不会,模板也不会' 必须再次重新计算这些值。在您的代码中,其他值似乎没有太多变化,但无论如何都是好的做法。

这是可能的样子(未经测试的代码)

computed: {
  tableData() {
    return this.filteredRow.map(row => {
      const cols = [];
      this.tableHead.forEach(item => {
        let value = "";
        if (col.Name === row.Key) {
          let value = item.Value.replace(search, `<span style='color:#1D7CA7'><b>${search}</b></span>`)
        }
        cols.push(value)
      });
      return {...row, cols};
    }) 
  }
},
<table v-if="showTable">
  <tr>
    <th v-for="head in tableHead" :key="head.Name">
      {{ head.Name }}
    </th>
  </tr>
  <tr
    v-for="row in tableData"
    :key="row.Key"
    class="data"
    @click="zoomToFeatureExtent(row)"
  >
    <td v-for="(cell, i) in row.cols" :key="i">
      <p v-html="cell"></p>
    </td>
  </tr>
</table>