事件修饰符
使用v-on, 表示即将发生的事件, 例如点击事件click, 下面是一个例子:
<div id="app"> <h5 v-on:click="showInfo">点击我</h5> <a href="https://www.baidu.com" v-on:click="showInfo">点我</a> </div>
v-on 可以简写为: @
<div id="app"> <h5 @click="showInfo">点击我</h5> <a href="https://www.baidu.com" @click="showInfo">点我</a> </div>
阻止默认事件
点击a标签, 会执行click中的showInfo方法, 随后还会执行a中的默认跳转行为, 如果不想这类行为事件发生, 可以使用事件修饰符prevent来阻止进行:
<a href="https://www.baidu.com" @click.prevent="showInfo">点我</a>
当然可以在Vue实例中定义方法的时候, 传入event, 然后调用event的preventDefault方法:
new Vue({ el : '#app', data : { name : '王者荣耀' }, methods : { showInfo(e) { e.preventDefault() alert('你好') } } })
阻止冒泡
既然是点击, 那么如果一个区域里面存在两个点击事件. 例如:
<body> <div id="app"> <div @click="testDiv" id="out"> <a href="https://www.baidu.com" @click.prevent="showInfo">点我</a> </div> </div> <style> #out { width: 200px; height: 200px; border: solid blue 1px; } </style> </body> <script> new Vue({ el : '#app', data : { name : '王者荣耀' }, methods : { showInfo(e) { e.preventDefault() alert('你好') }, testDiv() { alert('这是最外层的div') } } }) </script>
点击a标签那么就会出现:
首先出现:
然后出现:
发现, 本来我的本意只想点击这个a标签, 但是因为层叠关系(冒泡), 就导致点击了a的同时, 也点击了div标签, 所以为了阻止这种情况, 使用event方法: event.stopPropagation() >>>
new Vue({ el : '#app', data : { name : '王者荣耀' }, methods : { showInfo(e) { e.preventDefault() e.stopPropagation(); alert('你好') }, testDiv(e) { alert('这是最外层的div') } } })
简写, 在事件后面添加事件修饰符stop, 例如:
<a href="https://www.baidu.com" @click.prevent.stop="showInfo">点我</a>
允许触发一次
使用修饰符once :
<a href="https://www.baidu.com" @click.once="showInfo">点我</a>
事件只触发一次
捕获模式
事件执行, 先开始捕获, 由外到内, 捕获完之后开始执行, 从内到外执行, 也就是冒泡, 现在更改为捕获状态就执行, 也就是添加.capture, 例如@click.capture = "xxx"
self
@click.self, 只有在event.target 是本身的时候, 才会触发点击事件
passive
事件立即执行, 无序等待前置条件: .passive
键盘事件
keyup & keydown
- @keyup
- @keydown
这里使用keyup作为案例:
<body> <div id="app"> <p>欢迎来到{{name}}</p> <input type="text" placeholder="按下回车提示输入" @keyup="showInfo"> </div> </body> <script> new Vue({ el :'#app', data : { name : 'world' }, methods : { showInfo(e) { console.log(e.target.value); } } }) </script>
按下a建., 输入一个a, 这个时候控制台还没有输入, 但是松开a键之后, 控制台输出:
再按下一个a, 松开之后, 控制台输出 两个a :
keydown的用法类似, 这里不一一列举
相同的keyup和keydown都有事件修饰符:
- enter, 键盘输入之后并不会触发事件, 只有在键入的值是enter(回车)的时候, 才会触发事件, 例如:
<div id="app"> <p>欢迎来到{{name}}</p> <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo"> </div> new Vue({ el :'#app', data : { name : 'world' }, methods : { showInfo(e) { console.log(e.target.value); } } })
- 输入一个a并不会触发事件showInfo, 但是在输入a后,再按一个回车, 控制台就输出了一个a :
按键别名
- 相同的还有很多其他的键盘事件修饰符, 这些别的修饰符是我们vue中常用的按键的别名:
- 回车 : enter
- 删除 : delete
- 空格 : space
- 退出 : esc
- 换行 : tab
- 上 : up
- 下 : down
- 左 : left
- 右 : right
vue暂时没有提供别的按键别名, 可以使用按键原始的key进行绑定
系统按键修饰符:
- ctrl
- alt
- shift
- meta (win)
系统修饰键配合keyup使用, 按下修饰键的同时, 再按下其他键, 随后释放其他键, 事件才被触发 : 解释 >> 因为同时按下之后, keyup是属于松开才触发事件, 但是现在除了ctrl等键之外, 其他的一些按键同样被按下了, 那么他们之间就有一个释放的顺序, 所以现在只有其他键先释放, 这个keyup状态才结束, 事件执行
配合keydown使用, 直接按下之后就可以正常触发事件
注意tab
有下面的例子:
<body> <div id="app"> <p>欢迎来到{{name}}</p> <input type="text" placeholder="按下回车提示输入" @keyup.tab="showInfo"> </div> </body> <script> new Vue({ el :'#app', data : { name : 'world' }, methods : { showInfo(e) { console.log(e.target.value); } } }) </script>
这是一个使用键盘事件, 并且使用tab修饰这个键盘事件 :
我们输入aaa, 然后按下tab:
发现这个玩意没有输出到控制台:
多按几次就会发现, 他并不是没有作用, 反而像是被什么锁定了一样, 不能在input中输入, :
多按下几次就会发现, 他会在浏览器上切换焦点
这个焦点被切走了. 那为什么没有触发事件??
分析: 细心的你一定会发现, 这个tab是按下立即就生效的, 但是我们定义的键盘事件是keyup, 按下tab之后, 焦点立即调走, 还没来得及松开焦点就已经从输入框中切走, 那么vm也就无法捕捉到这个键入tab的行为, 更加捕获不到tab松开.
改进 : 所以这个时候, 我们就可以使用keydown事件
注意系统按键
同按键别名中的说明, 如果直接使用@keyup.ctrl .....
比如同时按下ctrl + y, 然后松开y之后, 触发事件
还有一个需要注意的是, 你可以指定松开哪一个键执行事件:
@keyup.ctrl.y, 这个时候, 只有同时按下ctrl + y, 然后松开y才有用, 按下ctrl + z或者是其他的除y之外的按键都是没有用的.
自定义按键
Vue.config.keyCodes.huiche = 13; <input type="text" placeholder="按下回车提示输入" @keyup.huihce="showInfo">
鼠标事件
简介
除了键盘事件, 那么肯定有鼠标事件的啦, 看看下面这几个鼠标事件的例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js"></script> </head> <body> <div id="app"> <div id="testDiv" @click="testClick" @dblclick="testDBClick" @mouseenter="testMouseEnter" @mouseleave="testMouseLeave" @mousedown="testMouseDown" @mouseup="testMouseUp" @mousemove="testMouseMove" > {{content}} </div> <br> <hr> </div> </body> <script> var vue = new Vue({ el : '#app', data : { content: '', value : null }, methods : { testClick() { // 单机 this.content = '鼠标单击'; }, testDBClick() { // 鼠标双击 this.content = '鼠标双击'; }, testMouseEnter() { // 鼠标进入事件 this.content = '鼠标进入'; }, testMouseLeave() { // 鼠标离开事件 this.content = '鼠标离开'; }, testMouseDown() { // 鼠标按下事件 this.content = '鼠标按下'; }, testMouseUp() { this.content = '鼠标弹起'; }, testMouseMove(event) { // 任何事件都可以添加事件event对象 this.content = event.offsetX + '---' + event.offsetY; // 只要是@的事件都可以使用event }, testFocus() { this.value ='获得焦点' } , testBlur() { this.value = '失去焦点' } } }); </script> <style> #testDiv { width: 150px; height: 150px; border: 2px solid green; text-align: center; line-height: 100%; } </style> </html>
单击
双击
离开div
这里不一一展示
总结鼠标点击事件 :
鼠标事件 | 所表示触发的前置条件 |
@click | 鼠标单机触发 |
@dblclick | 鼠标双击 |
@mouseenter | 鼠标进入 |
@mouseleave | 鼠标离开 |
@mousedown | 鼠标按下 |
@mouseup | 鼠标弹起 |
@mousemove | 鼠标移动 |
鼠标焦点事件
- @focus : 鼠标聚焦目标以触发事件
- @blur : 鼠标聚焦跳出目标, 触发事件
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js"></script> </head> <body> <div id="app"> <input type="text" @focus="testFocus" @blur="testBlur" v-model="value"> </div> </body> <script> var vue = new Vue({ el : '#app', data : { content: '', value : null }, methods : { testFocus() { this.value ='获得焦点' } , testBlur() { this.value = '失去焦点' } } }); </script> </html>
首先不进行任何操作:
点击这个输入框, 触发聚焦事件 :
鼠标点击输入框之外的内容:
单词解释:
blur也就是鼠标模糊不清, 也就是失去焦点.
计算属性
差值语法实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js"></script> </head> <body> <div id="root"> 姓 : <input type="text" v-model="firstName"><br> 名 : <input type="text" v-model="lastName"> <br> 姓名 : <span>{{firstName}}{{lastName}}</span> </div> </body> <script> new Vue({ el :'#root', data : { firstName : '张', lastName : '三' } }) </script> </html>
methods实现
{{}}的里面写的是差值表达式, 所以这里直接使用方法名 + ()的形式, 表示调用这个函数的返回值
<body> <div id="root"> 姓 : <input type="text" v-model="firstName"><br> 名 : <input type="text" v-model="lastName"> <br> 姓名 : <span>{{fullName()}}</span> </div> </body> <script> new Vue({ el: '#root', data: { firstName: '张', lastName: '三' },methods :{ fullName() { return '博子妹妹'; } } }) </script>
这里将'博子妹妹' 修改为 this.firstName + '-' + lastName的形式, 即可联动显示, 因为是双向绑定, 修改 姓 之后, 就会修改data中的值, 然后vm捕捉到这个修改, 然后用到这个name的地方就会更新 . 以后任何修改data的数据操作之后, vm都会重新解析一次.
computed实现
get()
不用方法, 也不使用插值语法来表示, 那么就使用vm实例中的computed字段来实现,
computed, 本就有计算的意思:
在computed的字段中定义fullName, 然后使用这个fullName去计算出 全名, 使用的时候, 可以像data中的数据那样去访问这个fullName, 例如: {{fullName}}, 访问这个fullName, vm会调用computed中的fullName的get()方法, 然后将其返回值最为fullName的值.
new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed : { fullName : { // 这个fullName依然在vm身上 // get() : 当有人读取fullName的时候, 就会调用get方法, 返回值就会被当做fullName的值 get() { return this.firstName + this.lastName; } } } })
但是这个get方法中不能直接 return firstName + lastName,因为他访问不到data中的数据,但是可以通过vm实例对象来访问.
<body> <div id="root"> 姓 : <input type="text" v-model="firstName"><br> 名 : <input type="text" v-model="lastName"> <br> 姓名 : <span>{{fullName}}</span> </div> </body> <script> new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed : { fullName : { // 这个fullName依然在vm身上 // get() : 当有人读取fullName的时候, 就会调用get方法, 返回值就会被当做fullName的值 get() { return this.firstName + this.lastName; } } } }) </script>
思考> computed中的属性的get 会被调用??
解释: 初次读取computed中的属性的时候,对应的get方法会被调用, 由于调用之后, 其返回值被缓存, 下次读取就不会调用get方法, 其次就是所依赖的数据被修改的时候, 就上面例子而言, 如果输入框中的姓被修改的时候, get方法就会被重新调用.
fullName虽然是个对象, 但是不能直接使用: {{fullName.get()}}.
set()
有get, 那么必然有set() :
computed : { fullName : { // 这个fullName依然在vm身上 // get() : 当有人读取fullName的时候, 就会调用get方法, 返回值就会被当做fullName的值 get() { return this.firstName + this.lastName; }, set (value) { const arr = value.split('-'); this.firstName = arr[0]; this.lastName = arr[1]; } } }
我们讲到, 如果调用了set方法, 那么就会修改firstName和lastName属性, 那么vm就会捕获到这个修改, 从而重新更新使用到这两个属性的地方, 同时set方法也捕获到了这个修改, 然后将引用这个fullName的地方进行更新:
总结
计算属性:
1.定义:要用的属性不存在,要通过已有属性计算得来。
如果计算属性中存在在vm外部定义的变量, 那么确实是可以像已有的属性那样显示出来, 但是vm无法捕捉到这个外部定义的变量的变化.
2.原理: 底层借助了objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制 (复用) ,效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化
计算属性简写
计算属性中的每一个属性都是当做对象处理:
对象中的每个方法使用逗号分割, 但是实际上这个set方法一般都用不到, 所以直接将这个fullName定义为一个方法 :
const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed : { fullName : function(){ // 这个fullName依然在vm身上 return this.firstName + this.lastName; } } })
更甚将其改为:
fullName(){ // 这个fullName依然在vm身上 return this.firstName + this.lastName; }
注意这里简写的前置条件是, 我不会去调用set方法, 如果调用set方法:
[vue警告]:计算属性, “FulName”分配给了它,但它没有set方法.