Vue2 和 Vue3 双向数据流

656 阅读1分钟

双向数据绑定指父组件数据更新可以自动同步到子组件上,同时,子组件也可以修改数据,通知到父组件上,从而实现数据的双向绑定。如下图,父组件通过 props 将数据传递给子组件,子组件 emit 事件将要修改的数据通知到父组件。

image.png

vue2

v-model

表单输入可以通过 v-model 实现数据的双向绑定,如 input 输入框:

<template>
  <div id="app">
    <div><input v-model="inputValue"></div>
    <div>inputValue: {{inputValue}}</div>
  </div>
</template>

v-model 本质是 v-bind:value@input="value=$event" 的语法糖。即:子组件绑定的 propsvalue ,父组件要监听 input 事件。知道原理后,我们可以自己实现双向数据流。

自己实现

使用 v-model 语法糖

如果想使用 v-model 语法糖的话,子组件 AComponent 中 props 使用 value,通过 emit('input') 来通知父组件修改数据。

<template>
  <div>
    <span>{{value}}</span>
    <button @click="changeValue">change</button>
  </div>
</template>

<script>
export default {
  name: 'AComponent',
  props: {
    value: String,
  },
  methods: {
    changeValue
      this.$emit('input', "new value")
    },
  }
}
</script>

父组件使用:

<AComponent v-model="aValue"></AComponent>

如果想要更改 prop 或事件名称,则需要在 AComponent 组件中添加 model 选项。

<template>
  <div>
    <span>{{title}}</span>
    <button @click="changeValue">change</button>
  </div>
</template>
export default {
   model: {
      prop: 'title',
      event: 'change',
   },
   methods: {
    changeValue
      this.$emit('change', "new value")
    },
  }
}
不使用 v-model

子组件 AComponent:

<template>
  <div>
    <span>{{title}}</span>
    <button @click="changeTitle">change title</button>
  </div>
</template>

<script>
export default {
  name: 'AComponent',
  props: {
    value: String,
  },
  methods: {
    changeTitle(){
      this.$emit('update:title', 'acomponent self change')
    }
  }
}
</script>

父组件使用:

<AComponent :title="aTitle" @update:title="updateTitle"></AComponent>

export default {
  name: 'App',
  components: {AComponent,},
  data(){
    return{
      aTitle: 'aTitle',
    }
  },
  methods: {
    updateTitle(val){
      this.aTitle = val
    }
  }
}

vue3

v-model 语法糖

v-model 语法糖与 vue2 不同,相当于绑定了 modelValue 属性和 update:modelValue 事件。

<input v-model="searchText">

相当于:

<input :modelValue="searchText" @update:modelValue="newVal => searchText=newVal">

同时,通过 v-model 可以绑定多个 v-model:

<template>
  <div>
    <span>{{modelValue}}</span>
    <div>{{title}}</div>
    <button @click="changeValue">change</button>
  </div>
</template>
<script setup>
import { defineProps, defineEmits, } from 'vue'
defineProps({
  modelValue: String,
  title: String
})
const emit = defineEmits(['update:modelValue', 'update:title'])
const changeValue = () => {
  emit('update:modelValue', 'new input value')
  emit('update:title', 'ttt')
}
</script>

父组件:

<template>
  <AComponent v-model="aVal" v-model:title="aTitle"/>
  <div>{{aVal}}</div>
</template>

<script setup>
import AComponent from './components/AComponent.vue'
import { ref } from 'vue'
const aVal = ref('a')
const aTitle= ref('title')
</script>

组件 valuetitle 两个 props 都是双向绑定的。

自己实现

如果不借用 v-model 语法糖的话,同 vue2 一样,可以实现双向数据流。

总结

vue2 和 vue3 中, v-model语法糖含义不同,同时,vue3 中,借用 v-model 可以绑定多个双向数据。