vue2实现
在实现父子组件通信的时候我们一般是用emit抛出事件来实现,用vue2举个例子
vue create vue2-app //创建一个简单的vue2项目
cd vue2-app
npm run serve // 启动项目
在项目的components文件夹下新建score.vue
<template>
<div class="welcome">
<input v-model="count" />
<button @click="handleClick">plus</button>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Score',
props:{
start:{
type: Number,
default: 0
}
},
data(){
return{
// 在 子组件 中不能直接修改 props 里面的内容,所以需要维护一个count,start作为默认值传入
count: this.$props.start
}
},
methods:{
handleClick(){
this.count++;
this.$emit('onChange',this.count)
}
}
}
</script>
在HelloWorld.vue文件引入子组件count.vue,删除掉多余的内容
<template>
<div class="hello">
result: {{ count }}
<score @onChange="onChange" :start="count" />
</div>
</template>
<script>
import Score from './score.vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
components:{
Score
},
data(){
return{
count: 10
}
},
methods:{
onChange(e){
this.count = e
}
}
}
</script>
start是Score组件的一个属性,父组件调用的时候可以通过start给Score设置个起始值,每次点击加1的时候都抛出事件,在父组件里面更改count值。有没有办法让父子组件之间传值像input那么方便呢,答案是有的。
v-model是一个语法糖,v-model 相当于 :value="value" @input="getInput",它做了如下事情
- 绑定数据value
- 触发输入事件input,然后emit抛出事件
- data更新触发重新渲染
可以通过model属性自定义value和getInput
model:{
prop: 'myValue',// 自定义传入的值
event: 'myInput'// 自定义emit抛出事件
}
Score.vue修改成
<template>
<div class="welcome">
<input v-model="count" />
<button @click="handleClick">plus</button>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Score',
props:{
myStart: Number
},
model:{
prop: 'myStart',
event: 'myInput'
},
data(){
return{
count: this.$props.myStart
}
},
methods:{
handleClick(){
this.count++;
this.$emit('myInput',this.count)
}
}
}
</script>
HelloWorld.vue简写为:
<template>
<div class="hello">
result: {{ count }}
<score v-model="count" />
</div>
</template>
<script>
import Score from './score.vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
components:{
Score
},
data(){
return{
count: 10
}
}
}
</script>
父组件在引用子组件的时候使用了v-model指令,并且不需要再写onChange方法维护count值,count会自动加1。子组件的v-model指令极大方便了父组件的调用。
vue3实现
vue3中没有了vue2的model属性,v-model默认的props属性名称是modelValue,绑定的事件是update:modelValue。以下用vue3实现一遍。
npm create vue@latest //创建一个简单的项目
cd vue3-app
npm install
npm run dev // 启动项目
子组件Score.vue
<template>
<div>
<input v-model="count" />
<button @click="handleClick">plus</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { defineProps } from 'vue';
const emits = defineEmits(['update:modelValue'])
const props = defineProps({
modelValue:{// 默认的名称modelValue
type: Number,
default: 0
}
})
const count = ref(props.modelValue)
const handleClick = () =>{
count.value++
emits('update:modelValue',count.value)// 默认的事件名称
}
</script>
父组件App.vue
<script setup>
import { ref } from 'vue';
import Score from './components/Score.vue';
const count = ref(0)
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div>result: {{ count }}</div>
<score v-model="count" />
</header>
</template>
如果要自定义双向绑定的model名称也可以。例如在Score.vue中双向绑定的model名称改为myValue,对应事件名称也改为update:myValue
<template>
<div>
<input v-model="count" />
<button @click="handleClick">plus</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { defineProps } from 'vue';
const emits = defineEmits(['update:myValue'])
const props = defineProps({
myValue:{
type: Number,
default: 0
}
})
const count = ref(props.myValue)
const handleClick = () =>{
count.value++
emits('update:myValue',count.value)
}
</script>
父组件使用的时候就要指定model名称,这种方式可以实现多个数据的双向绑定,vue2也可以实现。
<score v-model:my-value="count" />