vue 父子组件双向数据绑定是否有更优雅的方式?

vue 使用 v-model 双向绑定父子组件的值

场景

今天在使用 v-model 进行组件双向数据绑定的时候遇到了一个奇怪的问题,网页本身运行正常,浏览器一直出现警告信息。

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

引发这个警告的是一个自定义组件 RxSelect

Vue.component('RxSelect', {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: [Number, String],
    map: Map,
  },
  template: `
        <select
          v-model="value"
          @change="$emit('change', value)"
        >
          <option
            v-for="[k,v] in map"
            :value="k"
            :key="k"
          >{{v}}</option>
        </select>
        `,
})

吾辈使用的代码看起来代码貌似没什么问题?

<main id="app">
  当前选择的性别是: {{map.get(sex)}}
  <div>
    <rx-select :map="map" v-model="sex" />
  </div>
</main>

JavaScript 代码

new Vue({
  el: '#app',
  data: {
    map: new Map()
      .set(1, '保密')
      .set(2, '男')
      .set(3, '女'),
    sex: '',
  },
})

经测试,程序本身运行正常,父子组件的传值也没什么问题,双向数据绑定确实生效了,然而浏览器就是一直报错。

尝试解决

吾辈找到一种方式

  1. 为需要双向绑定的变量在组件内部 data 声明一个变量 innerValue,并初始化为 value
  2. select 上使用 v-model 绑定这个变量 innerValue
  3. 监听 value 的变化,在父组件中 value 变化时修改 innerValue 的值
  4. 监听 innerValue 的变化,在变化时使用 this.$emit('change', val) 告诉父组件需要更新 value 的值
Vue.component('RxSelect', {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: [Number, String],
    map: Map,
  },
  data() {
    return {
      innerValue: this.value,
    }
  },
  watch: {
    value(val) {
      this.innerValue = val
    },
    innerValue(val) {
      this.$emit('change', val)
    },
  },
  template: `
  <select v-model="innerValue">
    <option
      v-for="[k,v] in map"
      :value="k"
      :key="k"
    >{{v}}</option>
  </select>
  `,
})

使用代码完全一样,然而组件 RxSelect 的代码却多了许多。。。有什么更优雅的方式么?

阅读 2.1k
1 个回答
computed: {
  innerValue:{
    get(){
      return this.value
    },
    set(val){
      this.$emit('change', val)
    }
  }
},

直接用计算属性即可

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题