Vue3throughv-modelEncapsulating third-party Components

Real scenario: clicking a button on a page using a third-party library brings up a modal box (such as Elemental-Plus’s < el-Dialog >
) that contains complex business logic and you want to encapsulate the modal box as a new component.

v-model

In Vue3.x, a V-Model on a custom component is equivalent to passing a modelValue prop and receiving an Update :modelValue event thrown.

<ChildComponent v-model="pageTitle" /> <! <ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle =" />Copy the code

Here are the ones with parameters:

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" /> <! -- is short for:  --> <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" :content="pageContent" @update:content="pageContent = $event" />Copy the code

Child components:

<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>Copy the code

The parent component is not the default, parameterized child component:

<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>Copy the code

Using third-party Components

The parent component:

<template> <Test :modelValue="testVal" @update:modelValue="testVal = $event"> <! --> <Test v-model="testVal" /> </template>Copy the code

Sub-component: Problem edition

<template> <! -- There will be problems: --> <! -- modelValue is the prop value passed down to the EL-Input component, < el-INPUT :modelValue="modelValue" @update:modelValue="handler" @input="handleElInput"></el-input> <! -- shorthand:  --> <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) {// emit('update:modelValue',b) from the EL-input component emit('update:modelValue',b). This. ModelValue = a; // An error is reported here, Prop is readonly}, $emit("update:modelValue", a) {// This.$emit("update:modelValue", a); Update :modelValue},},}); </script>Copy the code

Do it right:

<template> <! -- Correct Practices: < 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) {// Emit ('update:modelValue',b) returns a value from the el-input component emit('update:modelValue',b). // We assign a value from the el-input to myValue this.myValue = a; $emit("myInput", a);}, handleElInput(a) {// Emit ('input',b) emit('input',b); // Trigger the parent component myInput event to return a to the parent component. (so the parent component can write @myInput = "XXX")},}, computed: {myValue: {get() {return this.modelValue; $emit("update:modelValue", v);}, set(v) {a this.$emit("update:modelValue", v); }},}}); </script>Copy the code