vue-learning:28 - component - 组件事件的修饰符`.native / .sync`,以及组件属性`model`
组件事件的修饰符.native / .sync
,以及组件属性model
.native 原生事件修饰符
- 在一个组件中,如果我们为其绑定一个原生的点击事件
@click
,基本是无效的。 - 在
vue
中对组件绑定原生事件需要带上原生事件修饰符.native
。 - 在组件中同时存在原生事件和自定义事件,组件自定义事件先于原来事件执行
<div id="app">
<p>this is event example for .native/@<p>
<com-child @click="handleNativeClick">按钮@click</com-child>
<com-child @click="handleNativeClick" @child-btn-click="handelChildBtnClick">按钮@click 和自定义事件@child-btn-click</com-child>
<com-child @click.native="handleNativeClick">按钮@click.native</com-child>
<com-child @click.native="handleNativeClick" @child-btn-click="handelChildBtnClick">按钮@click.native 和自定义事件@child-btn-click</com-child>
</div>
const comChild = Vue.extend({
template: `<div>
<button @click="handleBtnClick" >
<slot></slot>
</button>
</div>`,
methods: {
handleBtnClick() {
this.$emit('child-btn-click')
},
},
})
const vm = new Vue({
el: "#app",
components: {
comChild,
},
methods: {
handelChildBtnClick() {
alert("v-on绑定组件自定义事件")
},
handleNativeClick() {
alert('native click')
}
}
})
.sync 双向数据绑定
在前面讲解porp
时,明确了prop
是数据单向下行的绑定,父组件通过porp
向子组件传值。
在v-on / $emit
中,可以在子组件中触发父组件的事件监听器,以达到子组件向父母组件传值或通信的需要,可视为子组件向父组件的数据单向上行绑定。
所以常常将两者结合起来使用。那这里就会产生一个特殊的情况:父组件通过某个prop
向子组件传值,而子组件通过 v-on / $emit
触发父组件监听器修改的是正是父组件中的这个porp
值。
<div id="app">
<p>this is event example for prop and $emit<p>
<P>父组件中的num:{{ num }}</P>
<button-counter :count='num' @child-btn-click="handelChildBtnClick"></button-counter>
</div>
const buttonCounter = Vue.extend({
template: `<div>
<button @click="handelIncrease" >子组件点击次数:{{ count }}</button>
</div>`,
props: {
count: Number
},
methods: {
handelIncrease() {
this.$emit('child-btn-click', this.count+1)
},
},
})
const vm = new Vue({
el: "#app",
data: {
num: 0,
},
components: {
buttonCounter,
},
methods: {
handelChildBtnClick(val) {
this.num = val;
},
}
})
父子通信传递和修改的都是同一个prop
时,Vue
提供一个语法糖.sync
,可以进行简写:
<div id="app">
<p>this is event example for .sync<p>
<P>父组件中的num:{{ num }}</P>
<!-- <button-counter :count='num' @child-btn-click="handelChildBtnClick"></button-counter> -->
<button-counter :count.sync='num'></button-counter>
</div>
const buttonCounter = Vue.extend({
template: `<div>
<button @click="handleIncrease">子组件点击次数:{{ count }}</button>
</div>`,
props: {
count: Number
},
methods: {
handleIncrease() {
// this.$emit('child-btn-click', this.count+1)
this.$emit('update:count', this.count+1)
}
}
})
const vm = new Vue({
el: "#app",
data: {
num: 0,
},
components: {
buttonCounter,
},
methods: {
// handelChildBtnClick(val) {
// this.num = val;
// },
}
})
上面注释的内容就是省略的内容,可以看到.sync
语法糖就是对父组件绑定自定义事件那部分代码进行了简略,并指定$emit
触发的父组件监听事件名必须为update:count
的写法。
实际上完全还原.sync
的写法是:
<div id="app">
<p>this is event example for .sync update:count<p>
<P>父组件中的num:{{ num }}</P>
<!-- <button-counter :count='num' @child-btn-click="handelChildBtnClick"></button-counter> -->
<button-counter :count='num' @update:count="handelChildBtnClick"></button-counter>
</div>
const buttonCounter = Vue.extend({
template: `<div>
<button @click="handleIncrease">子组件点击次数:{{ count }}</button>
</div>`,
props: {
count: Number
},
methods: {
handleIncrease() {
// this.$emit('child-btn-click', this.count+1)
this.$emit('update:count', this.count+1)
}
}
})
const vm = new Vue({
el: "#app",
data: {
num: 0,
},
components: {
buttonCounter,
},
methods: {
handelChildBtnClick(val) {
this.num = val
}
}
})
对于v-bind='object
形式传入一个对象时,实现对象某个属性值的双向绑定,可以简写改成这样:v-bind.sync='object'
对prop各种类型传递写法还不清楚的可以点击查看vue-26-component-prop
<div id="app">
<p>this is event example for .sync object.lnag<p>
<!-- <button-counter v-bind='frontend' @child-change-lang="handleChildChangeLang"></button-counter> -->
<button-counter v-bind.sync='frontend'></button-counter>
</div>
const buttonCounter = Vue.extend({
template: `<div>
<p>前端语言:{{ lang }}</p>
<p>前端框架:{{ framework }}</p>
<p>前端编辑器:{{ editor }}</p>
<button @click="handleChangeLang">子组件内点击改变前端语言</button>
</div>`,
props: {
lang: String,
framework: String,
editor: String,
},
methods: {
handleChangeLang() {
this.$emit('update:lang', 'HTML')
}
}
})
const vm = new Vue({
el: "#app",
data: {
num: 0,
frontend: {
lang: "javascript",
framework: "vue",
editor: "vscode",
}
},
components: {
buttonCounter,
},
methods: {
// handleChildChangeLang(val) {
// console.log(val)
// this.frontend.lang = val
// }
}
})
v-model自定义组件的双向输入绑定
在上面.sync
实现双向数据绑定时,概念上有一些熟悉,因为之前在基础指令学习时,有一个用于表单元素输入的双向数据绑定指令v-model
,总结的时候,提到过这也是一个语法糖而已。
在.sync
实现时说过,$emit
触发的事件名必须按要求写法update:prop
的形式才行。同样的,v-model
语法糖实现的前提也必须存在指定的值,默认是特性值是value
,绑定的事件名是input
。
v-model
在绑定原生的表单元素时,会根据表单元素的类型不同,选择对应的特性和事件来实现双向绑定。
- text 和 textarea 元素使用 value 属性和 input 事件,值为字符串文本;
- checkbox 和 radio 使用 checked 属性和 change 事件,checkbox为单个时绑定值为布尔值,多选为数组,radio绑定依value值类型;
- select 字段将 value 作为 prop ,并将 change 作为事件。多选时为数组
那把v-model
用在自定义的组件中时,v-model 默认会查找组件中名为 value 的 prop 和名为 input的事件。如果有一个不存在,则无法实现v-model
双向绑定的效果。
<!-- 原生表单输入框元素直接用v-model -->
<div id="native-test">
<p>data中iptValue的值是: {{ iptValue }}</p>
<input type="text" v-model="iptValue">
</div>
const vm = new Vue({
el: "#native-test",
data: {
iptValue: ''
},
})
那如果现在有一个自定义的输入组件,根元素就是一个input
元素,在组件在直接绑定v-model
是否有效呢?
<div id="app">
<p>显示iptValue的值:{{ iptValue }}</p>
<!-- <input type="text" v-model="iptValue"> -->
<com-input v-model="iptValue"></com-input>
</div>
const comInput = Vue.extend({
template: `<input type="text"></div>`,
})
const vm = new Vue({
el: "#app",
data: {
iptValue: '初始值'
},
components: {
comInput,
},
})
结果是无效,因为在模板编辑阶段子组件com-input
上用v-model
时没有在组件身上找到value
和input
事件。也不会找到内部原生的input
。
自定义组件v-model指令
所以根据v-model
绑定原生表单组件时的原理,手写一个组件双向输入绑定
<div id="app">
<p>显示iptValue的值:{{ iptValue }}</p>
<!-- <input type="text" v-model="iptValue"> -->
<com-input :value='iptValue' @input="handleComInput"></com-input>
</div>
const comInput = Vue.extend({
template: `<input type="text" :value="value" @input="handleInnerIput"></div>`,
props: ['value'],
methods: {
handleInnerIput(e) {
this.$emit('input', e.target.value)
}
}
})
const vm = new Vue({
el: "#app",
data: {
iptValue: '初始值'
},
components: {
comInput,
},
methods: {
handleComInput(val) {
this.iptValue = val
}
}
})
这样我们就让组件com-input
有了value
属性和input
事件,此时满足v-model
有实现条件。我们就可以在组件上直接使用v-model
绑定了
<div id="app">
<p>显示iptValue的值:{{ iptValue }}</p>
<!-- <input type="text" v-model="iptValue"> -->
<!-- <com-input :value='iptValue' @input="handleComInput"></com-input> -->
<com-input v-model="iptValue"></com-input>
</div>
所以说,只要我们封装的组件能提供value属性和input事件,就可以对该组件使用v-model指令。而不需要组件内部一定是表单元素。
<div id="app">
<p>显示iptValue的值:{{ iptValue }}</p>
<!-- <input type="text" v-model="iptValue"> -->
<!-- <com-input v-model="iptValue"></com-input> -->
<com-div v-model='iptValue'></com-div>
</div>
const comDiv = Vue.extend({
// template: `<input type="text" :value="value" @input="handleInnerIput"></div>`,
template: `<div>
<span @click="handleClick" style="border: 1px solid #000;">点击改变值的显示 {{ value }}</span>
</div>`,
props: ['value'],
methods: {
handleClick(e) {
this.$emit('input', this.value+1)
}
}
})
const vm = new Vue({
el: "#app",
data: {
iptValue: 0
},
components: {
comDiv,
},
})
组件的model属性
再进一步讲,v-model指令默认情况下是选择value属性和input事件,那是否像checkbox一样让v-model绑定其它属性和对应的事件呢。
vue 2.2.0以上版本为组件增加一个model
对象属性,用来指定v-model绑定自定义的prop和event事件。
<div id="app">
<p>显示iptValue的值:{{ iptValue }}</p>
<!-- <input type="text" v-model="iptValue"> -->
<com-input v-model="iptValue"></com-input>
<com-div v-model='iptValue'></com-div>
</div>
const comDiv = Vue.extend({
// template: `<input type="text" :value="value" @input="handleInnerIput"></div>`,
template: `<div>
<span @click="handleClick" style="border: 1px solid #000;">点击改变值的显示 {{ otherName }}</span>
</div>`,
model: {
prop: 'otherName',
event: 'some-event'
},
props: ['otherName'],
methods: {
handleClick(e) {
this.$emit('some-event', this.otherName+1)
}
}
})
const vm = new Vue({
el: "#app",
data: {
iptValue: 0
},
components: {
comDiv,
},
})
.sync 和 v-model 区别
从上面分析的组件.sync和v-model实现的原理上看,一个组件只能定义一个model属性用业指定prop和event。所以:
- v-model在组件中只能实现一个prop的双向数据绑定,并且较适合用于绑定的prop类型为基本类型。
- .sync可以在组件中指定多个prop的双向数据绑定,绑定的prop类型较宽,对象类型的绑定更方便。
比如当v-bind.sync='obj'
时,就会把obj对象中的每一个属性 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器,实现对象中每个属性的双向绑定。
vue-learning:28 - component - 组件事件的修饰符`.native / .sync`,以及组件属性`model`的更多相关文章
- Vue中监听 键盘事件及修饰符
键盘事件: keyCode 实际值 48到57 0 - 9 65到90 a - z ( A-Z ) 112到135 F1 - F24 8 ...
- Vue.js学习笔记(三) - 修饰符
本篇将简单介绍常用的修饰符. 在上一篇中,介绍了 v-model 和 v-on 简单用法.除了常规用法,这些指令也支持特殊方式绑定方法,以修饰符的方式实现.通常都是在指令后面用小数点“.”连接修饰符名 ...
- vue中.sync修饰符,实现子组件实时更新父组件的值
vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定. 不过它有一个前身,先来看看.sync出现之前是如何实现的 父组件中(传递给子组件一个值:p ...
- 第六十一篇:Vue的绑定事件和修饰符
好家伙,补基础加实践 1.绑定事件 我们使用v-on(简写为@)来绑定事件 写个例子, 按钮绑定数字加一(太tm经典了) 在<button>元素中使用@点击事件绑定方法"的&qu ...
- Vue.js-06:第六章 - 按键修饰符的使用
一.前言 上周末的时候,准备试试将 ASP.NET Core 的项目部署到 CentOS 服务器上,结果在一个接一个坑里面跳,最后 Supervisor 守护程序还是有问题,于是,采用重装系统大招, ...
- Vue学习笔记【13】——键盘修饰符以及自定义键盘修饰符
1.x版本中自定义键盘修饰符[了解] Vue.directive('on').keyCodes.f2 = 113; 2.x版本中自定义键盘修饰符 通过Vue.config.keyCodes.名称 = ...
- 29.VUE学习之--键盘事件.键盘修饰符的实例讲解
键盘事件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- Vue基础知识之常用属性和事件修饰符(二)
Vue中的常用选项 1.计算属性 computed为可以计算的属性,由get方法和set方法组成,默认调用的是get方法.里面的 计算属性简单来说,就是根据数据推算出来的值,当给这个值赋值时可以影响其 ...
- vue中的事件修饰符
vue提倡的是在方法中只有对数据的处理,所以提供了事件修饰符用于DOM的事件处理,常用的事件修饰符有以下几个: (1). stop:阻止冒泡(通俗讲就是阻止事件向上级DOM元素传递) 点击内层div的 ...
随机推荐
- JMeter与LoadRunner的对比
1. 界面.安装.协议支持.函数库.成本.开源 2. 都可以实现分布式负载,相对来说LoadRunner更强大一些 3. 都支持在windows和linux环境的负载生成器.控制台方面,Jmeter跨 ...
- javascript如何将时间戳转为24小时制
var now = new Date(parseInt(1446634507) * 1000);console.log(now.toLocaleString('chinese',{hour12:fal ...
- 【To Read】Shortest Palindrome(KMP)
题意:Given a string S, you are allowed to convert it to a palindrome by adding characters in front of ...
- AtCoder Regular Contest 090 D - People on a Line
D - People on a Line Problem Statement There are N people standing on the x-axis. Let the coordinate ...
- Codeforces Round #323 (Div. 2) Once Again... CodeForces - 582B 最长非下降子序列【dp】(不明白)
B. Once Again... time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- github怎样改动源代码并进行提交方法小结
/********************************************************************* * Author : Samson * Date ...
- PyTorch代码调试利器: 自动print每行代码的Tensor信息
本文介绍一个用于 PyTorch 代码的实用工具 TorchSnooper.作者是TorchSnooper的作者,也是PyTorch开发者之一. GitHub 项目地址: https://github ...
- oracle选择最有效率的表名顺序
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条 ...
- oracle函数 RTRIM(c1,[,c2])
[功能]删除右边出现的字符串 [参数]C1 字符串 c2 追加字符串,默认为空格 [返回]字符型 [示例] SQL> select RTRIM('gao qian jingXXXX','X') ...
- 在web.xml中配置SpringMVC
代码如下 <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.spr ...