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

Posted

技术标签:

【中文标题】将 v-for 逻辑移动到计算属性【英文标题】:Move v-for logic to computed property 【发布时间】:2021-09-02 04:51:29 【问题描述】:

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

从计算属性到计算属性的逻辑但不成功,我认为表结构不正确,但我没有想法。任何人都可以帮忙吗? 不幸的是,“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   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>

【问题讨论】:

您还可以将&lt;p v-html 中的代码移动到采用rowitemsearch 的方法中。计算属性不能接受参数 AFAIK。 【参考方案1】:

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

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

<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>

【讨论】:

首先,非常感谢您的帮助。我知道这是从模板中分离逻辑的良好做法,这就是我寻求帮助的原因。我稍微修改了您的代码,现在一切正常。再感谢你的帮助:)

以上是关于将 v-for 逻辑移动到计算属性的主要内容,如果未能解决你的问题,请参考以下文章

在做vue计算属性,v-for处理数组时遇到的一个bug

计算属性或其他方式根据 Vue 中 v-for 中的值更改样式

计算属性computed

将计算属性添加到 wcf 客户端以进行绑定

使用计算或方法获取 v-for 中的索引

vue-----5计算属性