v-model是表单组件里面的核心知识点,这个指令给我们写表单业务带来了很大的方便。
-
元素标签上的
v-model
指令用于双向绑定数据,它是一个语法糖,可以用于代替v-bind:value
和@input
- 例如:
<input v-model="message" placeholder="edit me">
- 相当于:
<input :value="message" @input="message = $event.target.value">
- 例如:
-
组件上的
v-model
指令默认会使用value
属性与组件数据双向绑定,可以通过model
选项来更改
一般使用
js
const inputTemplate = `
<input :placeholder="message" v-bind:value="value" @input="updateValue" />`;
Vue.component("custom-input", {
template: inputTemplate,
props: ["value", "message"],
methods: {
updateValue(e) {
this.$emit("input", e.target.value);
},
},
});
var app = new Vue({
el: "#app",
data() {
return {
message: "",
username: "",
};
},
methods: {
onFocus() {
this.message = "输入框被点击了";
},
onBlur() {
this.message = "";
},
},
});
html
<div id="app">
<h3>{{username}}</h3>
<custom-input v-model="username" :placeholder="message" />
</div>
自定义组件绑定原生事件
根据 vue 的设计理念,自定义组件上的属性和事件,会默认绑定到组件的根元素上,如果想要绑定到组件的原生事件上,需要使用 .native
修饰符。
也就是我们在组件内部不使用 props 进行显示的接受,这些属性和事件会默认的绑定到组件的根元素上。 @focus.native="onFocus"
@blur.native="onBlur"
class="custom-input"
这三个属性我在组件内部没有使用 props 进行接受,但是却可以正常的使用。
html
<div id="app">
<h3>{{username}}</h3>
<custom-input
class="custom-input"
v-model="username"
:placeholder="message"
@focus.native="onFocus"
@blur.native="onBlur"
/>
</div>
js
const inputTemplate = `
<input :placeholder="message" v-bind:value="value" @input="updateValue" />`;
Vue.component("custom-input", {
template: inputTemplate,
props: ["value", "message"],
methods: {
updateValue(e) {
this.$emit("input", e.target.value);
},
},
});
var app = new Vue({
el: "#app",
data() {
return {
message: "请输入要显示的文字",
username: "",
};
},
methods: {
onFocus() {
this.message = "输入框被点击了";
},
onBlur() {
this.message = "";
},
},
});
关于inheritAttrs
在 vue2.4 版本中,新增了 inheritAttrs
选项,默认情况下,组件上没有在 props 中声明的属性会被添加到组件的根元素上。
有时候,我们不希望这些属性添加到组件的根元素上,可以通过设置 inheritAttrs: false
来关闭这个功能。
同时,改造下inputTemplate
这时候,我们发现focus
和blur
事件失效了,没有报错,就是没有触发。
这种情况,就需要我们手动来处理了,原因就是上面的原理
js
const inputTemplate = `
<label>{{label}}
<input :placeholder="placeholder" :value="value" @input="updateValue" v-on="customListeners"/>
</label>`;
Vue.component("custom-input", {
inheritAttrs: false,
template: inputTemplate,
props: ["value", "placeholder", "label"],
methods: {
updateValue(e) {
this.$emit("input", e.target.value);
},
},
computed: {
customListeners() {
var vm = this;
console.log("🚀 ~ customListeners ~ this.$listeners:", this.$listeners);
return Object.assign({}, this.$listeners, {
input: (e) => {
vm.$emit("input", e.target.value);
},
});
},
},
});
var app = new Vue({
el: "#app",
data() {
return {
message: "请输入要显示的文字",
username: "",
label: "账号:",
};
},
methods: {
onFocus() {
this.message = "输入框被点击了";
},
onBlur() {
this.message = "";
},
},
});
html
<div id="app">
<h3> {{username}}</h3>
<custom-input class="custom-input" v-model="username" :placeholder="message" @focus="onFocus" @blur="onBlur" :label="label"/>
</div>
注意这里@focus="onFocus" @blur="onBlur"
,要去掉.native
,不然也不生效