model
选项和v-bind:value.sync
修饰符被移除,统一为v-model
的参数形式
- 这里说一下v-model的一个隐蔽特性,当我们组件的props只有一个属性时,默认会被当作
modelValue
传入,所以我们父组件中使用:v-model="xxx"
,子组件:props:{modelValue:String}
直接接收就可以。
//父组件
<template>
<v-model-test v-model="counter"></v-model-test>
//相当于
<v-model-test :modelValue="counter" @update="counter = $event"></v-model-test>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import VModelTest from "@/components/VModelTest.vue";
export default defineComponent({
components: {
VModelTest,
},
data() {
return {counter:20};
},
});
</script>
//子组件
<template>
<p>{{modelValue}}</p> //modelValue:20
<button @click="handleClick">修改<button>
</template>
<script lang="ts">
import {defineComponent} from "vue";
export default defineComponent({
props:{
modelValue:Number
},
methods:{
handleClick(){
this.$emit("update:modelValue",100)
}
}
});
</script>
下面是我对vue2.0中model选项
、.sync操作符
的示例,大家可以回顾一下,方便对比上面vue3.0的v-model
vue2.0 model选项
//子组件VModel.vue
我们可以自定义组件的v-model
<template>
<div>VModel值:{{ text }} <button @click="updateValue">修改值</button></div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
props: {
text: {
type: String,
default: "初始值",
},
},
model: {
prop: "text",
event: "setText",
},
data() {
return {};
},
methods: {
updateValue() {
this.$emit("setText", "456");
},
},
});
</script>
//父组件Home.vue
<template>
<div class="about">
<VModel v-model="text"></VModel>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import VModel from "../components/VModel.vue";
export default Vue.extend({
components: {
VModel,
},
data() {
return {
text: "123",
};
},
});
</script>
vue2.3.0 新增.sync修饰符
背景:在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。
这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
//子组件VUpdate.vue中
<template>
<div>VModel值:{{ text }} <button @click="updateValue">修改值</button></div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
props: {
text: {
type: String,
default: "初始值",
},
},
data() {
return {};
},
methods: {
updateValue() {
this.$emit("update:text", "456");
},
},
});
</script>
//父组件Home.vue中
<template>
<div class="about">
<VUpdate :text.sync="text" />
</div>
</template>
<script lang="ts">
import Vue from "vue";
import VModel from "../components/VModel.vue";
import VUpdate from "../components/VUpdate.vue";
export default Vue.extend({
components: {
VUpdate,
},
data() {
return {
text: "123",
};
},
});
</script>
拓展
- vue3.0装饰器的简单应用,自定义装饰器,多个v-model同时绑定,
- 官方文档传送门我这边只是进行一个总结,想看详细文档的同学可以点击这个链接跳转
先看下基本用法
//子组件test.vue中
<template>
<div>{{ name }}属性</div>
<button @click="update">修改</button>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
props: {name},
methods: {
update() {
this.$emit("update:name", "李四");
},
},
});
</script>
//父组件Home.vue中
<template>
<Text v-model:name="propsText"></Text>
</template>
<script lang="ts">
import {defineComponent, ref} from "vue";
import Text from "@/components/test.vue";
export default defineComponent({
components: {
Text,
},
data() {
return {
propsText: "张三"
};
},
});
</script>
自定义装饰器
- vue3.0之前v-model有三个装饰器
lazy
,number
,trim
,这三个装饰器的用法在这里不多做描述,官方文档自己可以查一下,很详细。现在我们看一下在vue3.0中的装饰器的用法
看一个例子,比如我们设计了一个组件,这个组件里面v-model只绑定了一个prop,并且没有明确指定名字,这个值那么这个值会当成modelValue Prop传给子组件,同样,装饰器也一样,如果父组件是v-model.customModifier="text",子组件就可以用this.modelModifiers来接收,看不懂这句话不要紧,下面有示例:
//子组件
<template>
<div>
propValue:{{ modelValue }} <button @click="updateValue">修改</button>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
props: ["modelValue", "modelModifiers"],
created() {
console.log("modelValue-------------", this.modelValue);
console.log("modelModifiers-------------", this.modelModifiers);
},
methods: {
updateValue() {
let value;
if (this.modelModifiers.customModifier) {
value = "更改为" + this.modelValue;
} else {
value = this.modelValue;
}
this.$emit("update:modelValue", value);
},
},
});
</script>
//父组件
<template>
<div class="register-page">
<Component1 v-model.customModifier="oneProp" />
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Component1 from "@/components/component1.vue";
export default defineComponent({
components: {
Component1,
},
data() {
return {
oneProp: "one string",
};
},
});
</script>
看一下输出
总结:当你使用v-model时,没有明确指定prop的名字时,在子组件内部可以使用modelValue接收,自定义装饰器也一样,所以当this.modelModifiers[your Modifiers Name]为true或者false时,你可以决定是否处理这个数据,整个过程就是自定义装饰器。
多个自定义装饰器
那么问题来了,实际开发中一个组件可能有好几个prop,每个prop都有各自的自定义装饰器,那么又该怎么写呢,别急,上代码!!
v-model:name.formatName会变成attr+Modifiers这样的prop传给子组件,也就是nameModifiers
v-model.customModifier会变成modelModifiers
//子组件
<template>
<div>name:{{ name }}</div>
<div>sex:{{ sex }}</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
props: ["name", "sex", "nameModifiers", "sexModifiers"],
created() {
console.log("name------------", this.name);
console.log("nameModifiers----------", this.nameModifiers);
console.log("sex-------------", this.sex);
console.log("sexModifiers-----------", this.sexModifiers);
},
});
</script>
//父组件
<template>
<div class="register-page">
<Component2 v-model:name.formatName="name" v-model:sex.formatSex="sex" />
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Component2 from "@/components/component2.vue";
export default defineComponent({
components: {
Component2,
},
data() {
return {
name: "杨志强",
sex: "23",
};
},
});
</script>
看一下结果
总结:子组件共接受俩个prop,name 和 sex,这俩个prop分别带有自定义的装饰器,在vue3.0中,绑定的值和自定义装饰器都存在时,在子组件里面接受装饰器的名字规则就是[attr] + Modifiers,所以我们子组件里面用nameModifiers和sexModifiers来接收,之后进行相应的逻辑处理