VueJS - 动态重复组件

时间:2017-05-30 14:23:08

标签: javascript vue.js repeater

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

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

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

&#13;
&#13;
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;
    }
  }
});
&#13;
* {
  font-family: "Helvetica", "mono";
  font-size: 16px;
}

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

.filterContainer {
  display: block;
}
&#13;
<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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

可以改变一些事情来使其发挥作用(我只是假设你正在寻找的东西!)

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

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

来删除过滤器

最后,你的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>