Vue3
通过v-model
封装第三方组件
实际场景:
页面上点击一个按钮使用第三方库弹出一个模态框(如element-plus
的<el-dialog></el-dialog>
),模态框中有复杂的业务逻辑,于是你想把模态框封装成一个新的组件。
v-model
在
Vue3.x
中,自定义组件上的v-model
相当于传递了modelValue
prop
并接收抛出的update:modelValue
事件。
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event" />
下面是带参数的:
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 是以下的简写: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" :content="pageContent" @update:content="pageContent = $event" />
子组件:
<template>
<input type="text" :value="modelValue" @input="handleInput" />
</template>
<script>
export default defineComponent({
props: {
modelValue: String,
},
emits: ["update:modelValue"],
methods: {
handleInput(xxx) {
this.$emit("update:modelValue", xxx.target.value);
},
},
});
</script>
父组件不是默认的,带参数的子组件:
<template>
<input type="text" :value="pageTitle" @input="handleInput" />
</template>
<script>
export default defineComponent({
props: {
pageTitle: String,
},
emits: ["update:pageTitle"],
methods: {
handleInput(xxx) {
this.$emit("update:pageTitle", xxx.target.value);
},
},
});
</script>
使用第三方组件
父组件:
<template>
<Test :modelValue="testVal" @update:modelValue="testVal = $event">
<!-- 简写 -->
<Test v-model="testVal" />
</template>
子组件: 问题版
<template>
<!-- 会有问题: -->
<!-- modelValue是往下传给el-input组件的prop值,handler是el-input组件modelValue值更新触发的钩子 -->
<el-input :modelValue="modelValue" @update:modelValue="handler" @input="handleElInput"></el-input>
<!-- 简写: -->
<el-input v-model="modelValue" @input="handleElInput"></el-input>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
props: ["modelValue"],
emits: ["update:modelValue"],
methods: {
handler(a) {
// 此处的a就是el-input组件emit('update:modelValue',b)返回的参数b,它返回的是input输入的value值
this.modelValue = a; //此处会报错,prop是readonly
},
handleElInput(a) {
// 此处的a就是el-input组件emit('input',b)返回的参数b,它返回的是input输入的value值
this.$emit("update:modelValue", a); // 把a返回给父组件,input时通过触发update:modelValue更新输入的内容
},
},
});
</script>
正确做法:
<template>
<!-- 正确做法:通过一个计算属性 myValue 中转一下 -->
<el-input :modelValue="myValue" @update:modelValue="handler" @input="handleElInput"> </el-input>
<!-- 简写 -->
<el-input v-model="myValue" @input="handleElInput"></el-input>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
props: ["modelValue"],
emits: ["update:modelValue", "myInput"],
methods: {
handler(a) {
// 此处的a就是el-input组件emit('update:modelValue',b)返回的参数b,它返回的是input输入的value值
// 此处我们把el-input返回的a赋值给myValue
this.myValue = a;
},
handleElInput(a) {
// 此处的a就是el-input组件emit('input',b)返回的参数b,它返回的是input输入的value值
this.$emit("myInput", a); //触发父组件myInput事件,把a返回给父组件。(所以父组件可以写 @myInput = "xxx")
},
},
computed: {
myValue: {
get() {
return this.modelValue;
},
set(v) {
// 此处的v就是 handler 函数中设置的值a
this.$emit("update:modelValue", v);
},
},
},
});
</script>