vue自定义组件实现v-model双向数据绑定

一、Vue2 实现自定义组件双向数据绑定

v-model 实现双向数据绑定

  在vue2中,子组件上使用v-model的值默认绑定到子组件的props.value属性上,由于子组件不能改变父组件传来的属性,所以需要通过$emit触发事件使得父组件中数据的变化,然后再同步到子组件。vue2默认触发v-model数据变化的事件为input

使用如下:

子组件MySon

<template>
  <div>
    <div>双向数据绑定:{{$props.value}}</div>
    <div><button @click="addValue">点击++</button></div>
  </div>
</template>
​
<script>
export default {
  name: "MySon",
  props: ['value'],
  methods: {
    addValue() {
      //  触发父组件中v-model绑定数据的变化,由于不能改变props数据中的值,所以不要写this.$props.value++这样的操作
      this.$emit('input', this.$props.value + 1)
    }
  }
}
</script>

如果希望改变接收v-model的属性或改变触发v-model数据变化的事件,可通过model:{}配置实现,如:

<template>
  <div>
    <div>双向数据绑定:{{$props.value666}}</div>
    <div><button @click="addValue666">点击++</button></div>
  </div>
</template>
​
<script>
export default {
  name: "MySon",
  props: ['value666'],
  // --> 配置接收v-model数据的属性以及改变数据的事件 <--
  model: {
    prop: 'value666',
    event: 'updateValue666'
  },
  methods: {
    addValue666() {
      this.$emit('updateValue666', this.$props.value666 + 1)
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <MySon v-model="num"></MySon>
  </div>
</template>
​
<script>
import MySon from "@/components/MySon.vue";
export default {
  name: 'App',
  components: {
    //注册子组件
    MySon
  },
  watch: {
    //  监视num数据的变化  
    num(newValue, oldValue) {
      console.log('num: ' + oldValue + ' -> ' + newValue)
    },
  },
  data() {
    return {
      num: 10,
    }
  },
}
</script>

.sync 实现子组件多个数据双向绑定

Vue2中使用v-model只能使用一次,如果要实现多个双向数据绑定,可以借助.sync修饰,使用语法为 :属性.sync="数据" ,用这种绑定代替v-model,触发数据改变的事件为update:属性名

使用如下:

子组件

<template>
  <div>
    <div>sync双向数据绑定:{{$props.data}}</div>
    <div><button @click="addData">点击++</button></div>
  </div>
</template>
​
<script>
export default {
  name: "MySon",
  //    用props.data属性接收双向绑定的数据  
  props: ['data'],
  methods: {
    addData() {
      //    触发 update:data 事件改变父组件中绑定的值   
      this.$emit('update:data', this.$props.data + 1)
    }
  }
}
</script>

父组件

<template>
  <div id="app">
    <!-- 用 :data.sync 将数据双向绑定到子组件的data属性上 -->  
    <MySon :data.sync="num"></MySon>
  </div>
</template>
​
<script>
import MySon from "@/components/MySon.vue";
export default {
  name: 'App',
  components: {
    MySon
  },
  watch: {
    num(newValue, oldValue) {
      console.log('num: ' + oldValue + ' -> ' + newValue)
    }
  },
  data() {
    return {
      num: 10
    }
  },
}
</script>

至于为什么子组件要通过$emit('update:属性名', 数据);来触发父组件数据变化,原因如下:

<MySon :data.sync="num"></MySon>
          ||
          \/
        等价于
<MySon :data="num" @update:data="(newData) => {num = newData}"></MySon>

二、Vue3 实现双向数据绑定

在Vue3中,v-model可以实现多个数据双向数据绑定,同时.sync修饰符已经不再生效。

v-model 实现双向数据绑定

vue3中子组件上使用v-model绑定的数据默认传到子组件的props.modelValue属性上(vue2是props.value属性),并且默认触发数据变化的事件为update:modelValuevue2为input

使用如下:

子组件

<template>
  <div>
    <div>双向数据绑定modelValue:{{props.modelValue}}</div>
    <div><button @click="addModelValue">点击++</button></div>
  </div>
</template>
<script setup>
  //    props.modelValue接收v-model绑定的数据
  const props = defineProps(['modelValue'])
  const emit = defineEmits(['update:modelValue'])
  function addModelValue(){
    //  触发父组件中双向绑定数据的变化
    emit('update:modelValue', props.modelValue + 1)
  }
</script>

父组件

<template>
  <Son v-model="num"></Son>
</template>
​
<script setup>
  import {ref, watch} from "vue";
  import Son from "@/components/Son.vue";  
    
  const num = ref(0)
  //    监视num数据变化
  watch(num, (newValue, oldValue) => {
    console.log('num: ' + oldValue + '->' + newValue)
  })
</script>

v-model: 属性 实现多个数据双向绑定

数据绑定语法:v-model:属性="数据"

触发数据变化的事件:update:属性

使用如下:

子组件

<template>
  <div>
    <div>双向数据绑定data:{{props.data}}</div>
    <div><button @click="addData">点击++</button></div>
  </div>
</template>
​
<script setup>
  const props = defineProps(['data'])
  const emit = defineEmits(['update:data'])
  const addData = () => {
    emit('update:data', props.data + 1)
  }
</script>

父组件

<template>
  <!-- 将num数据绑定到子组件的data属性上 -->
  <Son v-model:data="num"></Son>
</template>
<script setup>
  import {ref, watch} from "vue";
  import Son from "@/components/Son.vue";
  const num = ref(0)
  watch(num, (newValue, oldValue) => {
    console.log('num: ' + oldValue + '->' + newValue)
  })
</script>

### Vue2 中动态绑定 `v-model` 的实现方法 在 Vue2 中,可以通过动态绑定的方式让多个表单项共享同一个模型值或者根据不同条件切换绑定的目标。以下是具体的实现方式: #### 使用计算属性实现动态绑定 当需要根据某些逻辑动态改变 `v-model` 绑定的变量时,可以借助 **计算属性** 和其 setter/getter 方法来完成。 ```javascript new Vue({ el: '#app', data() { return { selectedModel: 'modelA', // 控制哪个 model 被绑定 modelA: '', modelB: '' }; }, computed: { dynamicModel: { // 计算属性用于动态绑定 get() { return this[this.selectedModel]; }, set(value) { this[this.selectedModel] = value; } } } }); ``` 模板部分如下所示: ```html <div id="app"> <select v-model="selectedModel"> <!-- 切换绑定目标 --> <option value="modelA">Model A</option> <option value="modelB">Model B</option> </select> <input type="text" v-model="dynamicModel"> <!-- 动态绑定 input 值 --> <p>Model A Value: {{ modelA }}</p> <p>Model B Value: {{ modelB }}</p> </div> ``` 此代码片段展示了如何通过更改下拉菜单中的选项来动态调整被绑定的数据源[^1]。 #### 自定义组件中动态绑定 `v-model` 如果是在自定义组件内部实现动态绑定,则需手动处理 `value` 属性以及 `$emit('input')` 来同步父级传递过来的数据。 假设有一个名为 `<custom-input>` 的子组件,它支持接收不同的字段名作为参数并将其映射到自身的 `v-model` 上: ```javascript // 子组件 customInput.vue 定义 export default { props: ['field'], // 接收外部指定的 field 名称 data() { return {}; }, methods: { updateValue(event) { const newValue = event.target.value; // 获取新的输入值 this.$emit(`update:${this.field}`, newValue); // 发送更新事件给父组件 } }, template: ` <input :value="$attrs[this.field]" @input="updateValue"/> ` }; ``` 而在父组件中这样调用该子组件即可达到效果: ```html <template> <div> <custom-input field="firstName"></custom-input> <custom-input field="lastName"></custom-input> FirstName: {{ firstName }}<br/> LastName: {{ lastName }} </div> </template> <script> import CustomInput from './CustomInput'; export default { components: { CustomInput }, data() { return { firstName: "", lastName: "" }; } } </script> ``` 这里利用了 `.sync` 修饰符简化父子间通信过程,并且允许开发者灵活配置具体要操作的那个数据项[^2]。 #### 总结 无论是简单的场景还是复杂的业务需求,都可以基于以上两种思路去构建适合自己的解决方案。对于简单情况可以直接采用计算属性配合 getter/setter;而对于更复杂的情形则推荐使用自定义组件加特定字段名称的方式来增强可维护性和扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值