【问题标题】:How can I collect selected checkboxes from all child checkbox components in vue?如何从 vue 中的所有子复选框组件中收集选定的复选框?
【发布时间】:2017-10-26 03:45:09
【问题描述】:

我有一个表格,其中行元素都由子组件填充。每个子组件中都有一个复选框。现在我想一次得到所有选中的复选框。我可以使用 prefs emit 作为双向绑定并更新父级上的数组或对象,但我想知道是否有更好的方法。

这里是模板部分的一个简短示例:

<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody v-for="element in elements" :element="element"> </list-tbody>
</table>

这是子组件

<tbody>
    <tr>
        <td>
            <input type="checkbox">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>

【问题讨论】:

  • 通常在 Vue 中,不需要 获取复选框本身,只需获取绑定到它们的数据的状态。为什么特别需要复选框?
  • 是的,你是对的@Bert。我在每个表(组件)上也有一个子表。这样每个组件都可以自己保存(折叠或不折叠)数据。其他方式我要么需要一个额外的值(isCollapsed),要么我必须将数据存储在其他地方。这就是我决定改用组件的原因。
  • 我不会像下面的答案那样做。将数据保存在父级中并发出一个事件以在每次选择更改时更新父级或使用 Vuex 更新您的元素数组(推荐)。然后您可以创建一个过滤方法来仅获取选定的元素。类似fiddle 的内容。如果这是您要查找的内容,我可以添加答案并添加更多详细信息。
  • 是的@AWolf 我认为你的第二个例子是这种情况的最佳解决方案。如果您也将其添加到此处,我可以将其用作答案。
  • 类似场景下的事件方式(vs Vuex方式)在官方文档中有一些支持:vuejs.org/v2/guide/…

标签: javascript checkbox vue.js vuejs2


【解决方案1】:

如 cmets 中所述,您可以通过两种方式处理此问题:

  • 使用 Vuex 并改变子组件中的元素数组。
  • 在每次选择点击事件上向父级发送一个事件,父级将更新元素数组。

您更喜欢第二个,因为您没有使用 Vuex,这没关系。

在子组件和父组件之间“链接”数据后,您可以使用过滤器方法仅显示选定的元素。

请看下面的演示或我评论中的小提琴。

const listTbodyVuex = {
props: ['element'],
	template: `
  	<tbody>
    <tr>
        <td>
            <input type="checkbox" @click="selected">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>
  `,
  methods: {
  	...Vuex.mapMutations(['changeSelection']),
  	selected(evt) {
    	//console.log('clicked', evt.target.checked, this.changeSelection)
      // changeSelection mutation could be also called with-out mapping
      // this.$store.commit('changeSelection', ...);
      this.changeSelection({
      	id: this.element.id, selected: evt.target.checked
      });
    }
  }
}

const listTbodyEvents = {
	props: ['element'],
	template: `
  	<tbody>
    <tr>
        <td>
            <input type="checkbox" @click="selected">
        </td>
        <td> {{element.title}} </td>
    </tr>
</tbody>
  `,
  methods: {
  	selected(evt) {
    	console.log('clicked', evt.target.checked)
      this.$emit('selected', {
      	element: this.element,
        newSelection: evt.target.checked
      })
    }
  }
}

const store = new Vuex.Store({
	state: {
  	elements: [
      {
      	id: 0,
      	title: 'first',
        selected: false
      },
      {	
      	id: 1,
      	title: 'second',
        selected: false
      },
      {
      	id: 2,
      	title: 'third',
        selected: false
      }
      ]
  },
  mutations: {
  	changeSelection(state, {id, selected}) {
    	let element = state.elements
      	.filter((element) => element.id === id)[0];
      element.selected = selected;
      //console.log('update element', JSON.parse(JSON.stringify(element)));
      Vue.set(state.elements, element.id, element);
    }
  }
})

new Vue({
	el: '#app',
  store,
  data() {
  	return {
    	elements: [
      {
      	id: 0,
      	title: 'first',
        selected: false
      },
      {	
      	id: 1,
      	title: 'second',
        selected: false
      },
      {
      	id: 2,
      	title: 'third',
        selected: false
      }
      ]
    }
  },
  computed: {
  	...Vuex.mapState({
    	vuexElements: (state) => state.elements
    })
  },
  components: {
  	listTbodyEvents,
    listTbodyVuex
  },
  methods: {
  	updateElement(data) {
    	let element = this.elements
      	.filter((element) => element.id === data.element.id)[0];
      element.selected = data.newSelection;
      // console.log('update', element)
    },
    filterSelected(data) {
    	// console.log('filter',  data.filter((item) => console.log(item.selected)))
    	return data.filter((item) => item.selected);
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.0/vuex.js"></script>
<div id="app">
<h1>Example with vuex</h1>
<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody-vuex v-for="element in elements" :element="element" :key="element.id"> </list-tbody-vuex>
</table>
  <pre>only selected: {{filterSelected(vuexElements)}}</pre>
  <pre>{{vuexElements}}</pre>
  
<hr/>
<h1>Example with events</h1>
<table>
    <thead>
        <tr>
            <th> Check </th>
            <th> Title </th>
        </tr>
    </thead>
    <list-tbody-events v-for="element in elements" :element="element" :key="element.id" @selected="updateElement"> </list-tbody-events>
</table>
  <pre>only selected: {{filterSelected(elements)}}</pre>
  <pre>{{elements}}</pre>
</div>

【讨论】:

    【解决方案2】:

    您应该真正坚持发出值以保持组件的分离。话虽如此,如果您真的想一次获取所有数据,可以执行以下操作:

    首先,您的子组件中需要一个数据属性,您的复选框与v-model 一起使用该属性。为了这个例子,我们就叫它checkbox_value。完成后,您可以在父组件方法中执行以下操作:

    var checkbox_values = [];
    this.$children.forEach(function(child) {
        //you can check the child type here if you have other non-checkbox children
        checkbox_values.push(child.$data.checkbox_value);
    });
    

    当然,我不鼓励你做这样的事情,但你必须做出判断。

    注意:以上将仅返回值。您可以改为推送对象键/值对!

    【讨论】:

      猜你喜欢
      • 2020-05-20
      • 1970-01-01
      • 2021-10-07
      • 1970-01-01
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多