【问题标题】:Set same value for sibling component's select为同级组件的选择设置相同的值
【发布时间】:2017-08-12 04:00:55
【问题描述】:

使用 v-for,我正在循环一个组件。该组件适用于每个客户。在这个组件中,我对每个客户端都有相同的表单,当为第一个组件(客户端 1)选择一个选择值时,我想为每个客户端选择这个值。

我是否需要将数据传递到根并创建一个单一的真实变量源?

我尝试设置一个基本版本:

<div id="app">
  <my-comp v-for="x in 2" v-bind:val="x"></my-comp>
</div>


Vue.component('my-comp', {
   props: ['val'],

   template: `
    <div>
        <div>
          <label>Status</label>
          <select :data-client="val" @change="statusChanged">
              <option selected="" disabled="" value="0"></option>
              <option value="xxx">Xxx</option>
              <option value="yyy">Yyy</option>
              <option value="zzz">Zzz</option>
           </select>
        </div>
    </div>
    `,

   methods: {
     statusChanged(e) {
          var client = e.target.getAttribute('data-client')
          if (client == 1) {
            alert('set same value for client 2')
          }
     }
   }
})

new Vue({
  el: '#app',
})

这是一个小提琴:https://jsfiddle.net/w53164t2/

【问题讨论】:

    标签: vue.js vuejs2 vue-component


    【解决方案1】:

    在我的原始答案之后我考虑了一点,并提出了一些我认为比原始问题中提供的示例小提琴更真实的世界;具体来说,如果所有选择都使用相同的源值,则很容易使所有选择反映相同的值,但是我希望在现实世界的场景中,每个组件都将独立绑定到单个客户端。每个客户端都希望自己的值发生变化,但需要注意的是,如果“主”客户端发生更改,则所有非主客户端都应更改为主客户端的值。

    为此,这可能是我认为适合组件特定总线的情况。当 它的 值发生变化时,主服务器会发出一个事件,而其他客户端将根据主服务器设置它们的值。

    console.clear()
    
    const MyCompBus = new Vue()
    
    Vue.component('my-comp', {
      props: ['val', 'master'],
      computed:{
        selected:{
          get(){return this.val},
          set(v){
          	this.$emit('update:val', v)
         		if (this.master)
            	MyCompBus.$emit("master-updated", v)
         }
        }
      },
      methods:{
      	onMasterUpdated(newMasterValue){
          if (this.master) return
          this.selected = newMasterValue
        }
      },
      created(){
      	MyCompBus.$on('master-updated', this.onMasterUpdated)
      },
      beforeDestroy(){
      	MyCompBus.$off('master-updated', this.onMasterUpdated)
      },
      template: `
    		<div>
          <div>
            <label>Status</label>
            <select v-model="selected">
              <option selected="" disabled="" value="0"></option>
              <option value="xxx">Xxx</option>
              <option value="yyy">Yyy</option>
              <option value="zzz">Zzz</option>
            </select>
          </div>
        </div>
      `,
    })
    
    new Vue({
      el: '#app',
      data:{
        masterValue: null,
        clients:[
          {id: 1, selectedValue: null, master: true},
          {id: 2, selectedValue: null},
          {id: 3, selectedValue: null},
          {id: 4, selectedValue: null},
        ]
      }
    })
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app">
      <my-comp v-for="client in clients" 
               :val.sync="client.selectedValue" 
               :master="client.master" 
               :key="client.id">
      </my-comp>
      {{clients}}
    </div>

    原答案

    使用v-model将它们全部绑定到相同的值。

    Vue.component('my-comp', {
      props: ['value'],
      computed:{
        selected:{
          get(){return this.value},
          set(v){this.$emit('input', v)}
        }
      },
      template: `
        <div>
          <div>
            <label>Status</label>
            <select v-model="selected">
              <option selected="" disabled="" value="0"></option>
              <option value="xxx">Xxx</option>
              <option value="yyy">Yyy</option>
              <option value="zzz">Zzz</option>
            </select>
          </div>
        </div>
      `,
    })
    

    在模板中:

    <my-comp v-for="x in 2" v-model="selectedValue" :key="x"></my-comp>
    

    这里是updated fiddle

    如果您想坚持使用val 作为属性,您可以改用.sync

    Vue.component('my-comp', {
      props: ['val'],
      computed:{
        selected:{
          get(){return this.val},
          set(v){this.$emit('update:val', v)}
        }
      },
      template: `
        <div>
          <div>
            <label>Status</label>
            <select v-model="selected">
              <option selected="" disabled="" value="0"></option>
              <option value="xxx">Xxx</option>
              <option value="yyy">Yyy</option>
              <option value="zzz">Zzz</option>
            </select>
          </div>
        </div>
      `,
    })
    

    在模板中:

    <my-comp v-for="x in 2" :val.sync="selectedValue" :key="x"></my-comp>
    

    例如fiddle

    如果您只想将其中一个指定为“主”选择,请添加一个这样做的属性。

    Vue.component('my-comp', {
      props: ['val', 'master'],
      computed:{
        selected:{
          get(){return this.val},
          set(v){if (this.master) this.$emit('update:val', v)}
        }
      },
      template: `
        <div>
          <div>
            <label>Status</label>
            <select v-model="selected">
              <option selected="" disabled="" value="0"></option>
              <option value="xxx">Xxx</option>
              <option value="yyy">Yyy</option>
              <option value="zzz">Zzz</option>
            </select>
          </div>
        </div>
      `,
    })
    

    在模板中:

    <my-comp v-for="x in 5" :val.sync="selectedValue" :master="1 == x" :key="x"></my-comp>
    

    例如fiddle

    【讨论】:

    • 谢谢。但我想要一些不同的东西。我只希望第一个设置其他,当第二个更改时不会发生任何事情。所以不完全是它们都链接在一起,但客户端 1 更改为客户端 2
    • @senty 然后使用 Bert 的第二个示例,但只在第一个组件上使用 .syncjsfiddle.net/w53164t2/5
    • @senty 我还添加了另一个可能的解决方案。
    • 非常感谢各种答案!不过我有一个问题,如果我想在:val.sync 中使用多个单词而不是val,例如:hello-world:sync,该怎么办?
    • @senty 组件可以根据需要同步任意数量的属性。但是,如果您最终得到大量对象,则可能需要考虑使用对象。
    猜你喜欢
    • 2013-01-11
    • 1970-01-01
    • 2018-08-20
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    相关资源
    最近更新 更多