VueJS - 动态重复组件

VueJS - Dynamic repeating component

我在 .vue 文件中有一个 <filter> 组件,它具有一些属性来控制查询的过滤器。

这个 <filter> 可以根据用户需要即时添加/删除。它的行为与 Google Analytics 细分过滤器或 WordPress 的高级自定义字段非常相似。

我看到的唯一解决方案是动态实例化此组件并在我的主 app 中迭代这些组件的数组,但我不知道该怎么做。

Vue.component("my-filter", {
  template: "#filterTemplate",
  data: function() {
    return {
      field: null,
      value: null
    }
  },
  mounted: function() {
    this.$emit("filter-created", this);
  },
  methods: {
   removeFilter: function() {
     console.log("Remove this filter");
    }
  }
});

var app = new Vue({
  el: "#app",
  data: {
    filtersCount: 5,
    filters: [] // PROBLEM! I can't decrement on my filtersCount and remove the correct filter. Iteration should be over my "filtersCount" property.
  },
  methods: {
    filterCreated: function(filterObj) {
   this.filters.push(filterObj);
    },
    addFilter: function() {
     this.filtersCount += 1;
    }
  }
});
* {
  font-family: "Helvetica", "mono";
  font-size: 16px;
}

.filterContainer + .filterContainer {
  margin-top: 10px;
}

.filterContainer {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<!-- I shouldn't iterate over an integer value, but over an array of objects to remove the right ones -->
  <my-filter v-on:filter-created="filterCreated" v-for="(index, filter) in filtersCount" :key="index"></my-filter>
  <br>
  <button @click="addFilter">Add filter</button>
</div>
<script type="text/x-template" id="filterTemplate">
  <div class="filterContainer">
    <input type="text" :value="field" placeholder="Field" />
    <input type="text" :value="value" placeholder="Value" />
    <button @click="removeFilter">Remove filter</button>
  </div>
</script>

可以更改一些内容以使其正常工作(我只是假设您正在寻找什么!)

首先,您不需要数据 属性 来计算过滤器 (filtersCount),您可以循环遍历 filters 属性.

其次,将 this 添加到 filters 属性 会导致意外行为,因为 this 引用了整个 Vue 组件。我建议添加表示 filter 数据的普通对象并将数据作为 props 传递。注意:索引也作为一个 prop 传递,可以被引用并允许通过 emitting

删除过滤器

最后,您的 v-for 似乎被颠倒了。它应该是 (filter, index) 而不是 (index, filter).

Vue.component("my-filter", {
  template: "#filterTemplate",
  props: [
    'field',
    'value', // filter data
    'id',
    'index'   // index that allows this filter to be removed
  ],
  data: function() {
    return {
      field: this.field,
      value: this.value
    }
  },
  methods: {
    removeFilter: function() {
      this.$emit('remove-filter', this.index);
    },
    handleInput: function(prop, e) {
     this.$emit('update-filter', { index: this.index, prop, value: e.target.value });
    }
  }
});

window.vm = new Vue({
  el: "#app",
  data: {
    filters: [
      { id: 1, field: null, value: null },
      { id: 2, field: null, value: null },
      { id: 3, field: null, value: null },
      { id: 4, field: null, value: null },
      { id: 5, field: null, value: null }
    ]
  },
  methods: {
    addFilter: function() {
   var id = Math.max.apply(Math,this.filters.map(function(o){return o.id;})) + 1;
      this.filters.push({ id, field: null, value: null });
    },
    removeFilter: function(index) {
      this.filters.splice(index, 1);
    },
    updateFilter: function(payload) {
      this.filters[payload.index][payload.prop] = payload.value;
    }
  }
});
* {
  font-family: "Helvetica", "mono";
  font-size: 16px;
}

.filterContainer + .filterContainer {
  margin-top: 10px;
}

.filterContainer {
  display: block;
  border: 1px solid black;
  padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
  <button @click="addFilter">Add Filter</button>
  <br><br>
  <my-filter v-for="(filter, index) in filters" :key="index" :field="filter.field" :value="filter.value" :id="filter.id" :index="index" @remove-filter="removeFilter" @update-filter="updateFilter"></my-filter>
</div>

<script type="text/x-template" id="filterTemplate">
  <div class="filterContainer">
   <div>Index: {{ index }}, ID: {{ id }}</div>
    <input type="text" :value="field" placeholder="Field" @input="handleInput('field', $event)" />
    <input type="text" :value="value" placeholder="Value" @input="handleInput('value', $event)" />
    <button @click="removeFilter">Remove filter</button>
  </div>
</script>