【问题标题】:How to bind checkboxes to Vuex store?如何将复选框绑定到 Vuex 商店?
【发布时间】:2017-03-09 03:55:41
【问题描述】:

我有一个包含一些复选框的组件。我需要能够访问从我的 Vue 应用程序中的其他组件检查了哪些复选框,但我一生都无法弄清楚(也无法在线找到)如何正确地将复选框连接到我的 Vuex 商店。

将组件中的复选框连接到 Vuex 存储的正确方法是什么,以便它们的行为就像复选框通过 v-model 连接到组件数据一样?

这是我正在尝试做的事情的起点(在非常基本的意义上)

https://jsfiddle.net/9fpuctnL/

<div id="colour-selection">
  <colour-checkboxes></colour-checkboxes>
</div>

<template id="colour-checkboxes-template">
  <div class="colours">
    <label>
      <input type="checkbox" value="green" v-model="colours"> Green
    </label>
    <label>
      <input type="checkbox" value="red" v-model="colours"> Red
    </label>
    <label>
      <input type="checkbox" value="blue" v-model="colours"> Blue
    </label>
    <label>
      <input type="checkbox" value="purple" v-model="colours"> Purple
    </label>
    
    <chosen-colours></chosen-colours>    
  </div>
</template>

<template id="chosen-colours-template">
  <div class="selected-colours">
      {{ colours }}
    </div>
</template>

const store = new Vuex.Store({
  state: {
    colours: []
  }
});

Vue.component('colour-checkboxes', {
  template: "#colour-checkboxes-template",
  data: function() {
    return {
      colours: []
    }
  }
});

Vue.component('chosen-colours', {
    template: "#chosen-colours-template",
  computed: {
    colours() {
        return store.state.colours
    }
  }
});

const KeepTalkingSolver = new Vue({
  el: "#colour-selection"
});

目的是让颜色复选框组件中选择的颜色通过Vuex商店输出到选择颜色组件中。

【问题讨论】:

  • 一些代码会有帮助吗?

标签: checkbox vuejs2 vuex


【解决方案1】:

您可以在计算属性中使用computed property 和getter 作为vuex gettersetter,这将为该状态属性调用mutation 来执行此操作。

您可以看到这个here 的示例,它具有双向计算属性:

<input v-model="message">
// ...
computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}

【讨论】:

  • 使用复选框输入字段的示例,就像问题一样,在这里会很棒。所有在线示例都包含您在此处提供的文本字段。
  • @KatinkaHesselink 有点晚了,但我用复选框示例提供了答案
【解决方案2】:

我想提供一个实际使用复选框的答案。

这里列出了一种可能的解决方案: Vuex dynamic checkboxes binding

一个更简单的解决方案可以实现如下:

<div v-for="tenant in tenants" 
     v-bind:key="tenant.id" 
     class="form-group form-check">

<input type="checkbox" 
     class="form-check-input" 
     v-bind:id="tenant.id" 
     v-bind:value="tenant.name" 
     @change="updateSelectedTenants">

这里的关键是使用 on-change 调用方法,它会将一个事件传递给该方法,其中包含进行更改所需的所有详细信息。

@change 函数:

updateSelectedTenants(e) {
  console.log('e', e.target)
  console.log('e', e.target.value)
  this.$store.dispatch('updateSelectedTenants', e.target)
}

这里我想要值,在这种情况下是租户名称,但进一步检查目标也会给出“id”,以及复选框是“选中”还是未选中。

在 store 中,我们可以操作 'selectedTenants' 数组:

updateSelectedTenants (context, tenant) {
  if(tenant.checked) {
    // Tenant checked, so we want to add this tenant to our list of 'selectedTenants'
    context.commit('addSelectedTenant', { id: tenant.id, name: tenant.value })
  } else {
    // otherwise, remove the tenant from our list
    context.commit('removeSelectedTenant', tenant.id)
  }
}

这里是实际的变异器:

addSelectedTenant (state, tenant) {
  this.state.selectedTenants.push(tenant)
},
removeSelectedTenant (state, id) {
  this.state.selectedTenants = this.state.selectedTenants.filter(tenant => {
    return tenant.id != id
  })

vuejs 文档很棒,但有时它们可​​以通过真实世界的示例稍微了解一下。我不认为可以使用计算值、get()、set() 来实现上述目标……但我希望看到一个解决方案。

【讨论】:

  • 这是 waaaay 太多的代码来做一些内置于 vuejs 的事情。而是在复选框中使用 v-model='tenants' (负责添加/删除所选租户数组),并将租户(数组)映射到 vuex。摆脱 cb 上的 @change,摆脱对 vuex 的调度并摆脱 mutators。另外,tenants 数组不应该同时需要 id 和 name,只有 id,name 是多余的。
  • @LesNightingill 听起来不错。你能提供一个工作的例子吗?问题表明他们希望复选框绑定到 Vuex 存储。同意这不是问题,如果存储在本地状态。另外,我现在可以看到“@change”可以移动到计算属性...但我不确定这会节省多少。
  • 大声笑@LesNightingill 如果你有这么好的解决方案,请展示你的工作;)
  • 非常感谢!
  • 这个answer在计算中使用get() {} set() {}实现了上述功能,并利用v-model
【解决方案3】:

好的,我被要求展示我的解决方案。这里是on jsfiddle

html 是:

<div id="app">
  <label v-for="brother in ['Harpo','Groucho','Beppo']">
    <input type='checkbox' v-model='theBrothers' v-bind:value='brother' />
      {{ brother }}
  </label>
  <div>
  You have checked: {{ theBrothers }}
  </div>
</div> 

而js是:

const store = new Vuex.Store({
  state: {
    theBrothers: []
  },
})

new Vue({
  el: "#app",
  store: store,
  computed: {
    theBrothers: {
      set(val){this.$store.state.theBrothers = val},
      get(){ return this.$store.state.theBrothers }
    }
 },
}) 

【讨论】:

  • 谢谢莱斯。我认为this.$store.state.theBrothers = val 应该是一个 Vuex 突变,否则我认为这可行吗?
  • [vuex] do not mutate vuex store state outside mutation handlers.
  • 你不应该直接分配给状态。使用突变。
  • 我认为这行不通。我已经尝试过这个答案,但我没有直接修改状态,而是使用了一个像其他人建议的那样提交突变的动作。我可能做错了什么,但我相信 Vue 是直接修改状态而不是在 setter 中调度动作。我在操作中添加了 console.log 语句,但它从不记录。我还在 vuex 中添加了一个 Logger,每当我通过这些复选框更改状态时,它都不会写入控制台,但适用于我不使用复选框来更新状态的其他组件。只是我的 2 美分。
  • 这不适用于复选框。我为 vuex 开启了strict 模式,但我收到错误声明不直接改变状态(即使使用调用动作/变异的设置器)
【解决方案4】:

2021 - 简单、易读并利用 Vue/Vuex 的强大功能...

一个简单的问题有很多复杂的答案。运行下面的 sn-p 以查看它的实际效果。

长话短说,您需要做的就是获取一个状态(下面的names),创建一个突变(下面的setNames)来设置它,然后将v-model绑定到computedselectedNames 下面)有一个 getter 和 setter,getter 获得状态片段names,setter 调用突变setNames

在我看来,这是解决这个问题最干净的方法,因为它遵循 Vue/Vuex 的自然模式以及复选框的典型实现方式。

这里的其他答案试图直接改变状态而不发生突变,而其他一些答案避免使用v-model,这会出现具有预选值的问题并且需要更多代码,最后接受的答案甚至没有显示任何关于如何实现它的 HTML 模板代码。

这是一个解决所有这些问题的有效解决方案:

const store = new Vuex.Store({
  state: {
    names: ['Max'],
  },
  mutations: {
    setNames(state, names) {
      state.names = names;
    }
  }
});

new Vue({
  el: '#app',
  store,
  computed: {
    selectedNames: {
      get: function() {
        return this.$store.state.names;
      },
      set: function(val) {
      console.log(val);
        this.$store.commit('setNames', val);
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>

<div id="app">
  <div>
    <input type="checkbox" v-model="selectedNames" :value="'John'" id="checkbox-1" />
    <label for="checkbox-1">Click me to add my value to the state</label>

    <br />

    <input type="checkbox" v-model="selectedNames" :value="'Max'" id="checkbox-2" />
    <label for="checkbox-2">I am preselected since my value already exists in the state <code>names</code> array</label>

    <div>State: <strong>{{ names }}</strong></div>
  </div>
</div>

【讨论】:

  • 让我看看我是否理解正确:v-model 是一个计算属性,所以当我们将复选框绑定到它时,首先调用 getter,返回一个数组。当我们勾选一个框时,是修改了原始数组,还是创建了修改后的副本?无论哪种方式,setter 都会使用修改后的数组调用,并将其传递给突变。那是对的吗? (如果是这样,突变中的name 参数是否应该是names?)
  • @DavidMoles 是的,你是对的,我更新了我的 sn-p 中的命名。很好的收获,谢谢!
【解决方案5】:

根据需要使用@change 更新 Vuex:

HTML:

<input
  v-for='item in items'
  @change='update_checkboxes'
  v-model='selected_checkboxes'
  :value='item.id'
  type='checkbox
/>
<label>{{item.name}}</label>

JS:

data: function(){ 
  return {
    selected_checkboxes: [] // or set initial state from Vuex with a prop passed in
  }
},
methods: {
  update_checkboxes: function(){
    this.$store.commit('update_checkboxes', this.selected_checkboxes)
  }
}

【讨论】:

    【解决方案6】:

    基于@Saurabh 的解决方案 - 重要的是使用 actionsgetters 而不是直接访问 vuex 状态 - 这将确保整个应用程序的一致性。

    <p>Mega test: <input type="checkbox" v-model="mega" /></p>
    
    computed: {
      mega: {
        get () {
          return this.$store.getters.mega
        },
        set (value) {
          this.$store.dispatch('updateMega', value)
        }
      }
    }
    
    const store = new Vuex.Store({
      state: {
        mega: false
      },
      getters: {
        mega (state) {
          return state.mega
        }
      },
      mutations: {
        updateMega (state, value) {
          state.mega = value
        }
      },
      actions: {
        updateMega (context, value) {
          context.commit('updateMega', value)
        }
      }
    })
    

    【讨论】:

      【解决方案7】:

      您应该删除数据中的颜色 = []。

      【讨论】:

        猜你喜欢
        • 2018-02-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-26
        • 1970-01-01
        • 2022-01-03
        • 1970-01-01
        • 2021-04-23
        • 2018-07-17
        相关资源
        最近更新 更多