1. 重点提炼
- 事件
- v-on
- 简写:@
- 绑定格式:v-on:click=“函数/表达式”
- this 对象
- 事件对象
2. 事件
在 vue
中,事件通过指令 v-on
进行绑定,v-on
缩写 @
<组件 v-on:事件名称="表达式" />
<组件 @事件名称="表达式" />
2.1 example01
2.1.1 example01-1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.43
Branch: branch01commit description:a0.43(example01-1——事件的简单使用)
tag:a0.43
2.1.2 example01-2
以上是简单形式,但通常是需要绑定函数的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
</div>
<script src="./js/vue.js"></script>
<script>
function fn() {
console.log(1);
}
let app = new Vue({
el: '#app',
data: {
v1: 1
}
});
</script>
</body>
</html>
但是报错了。没有找到fn
,因此不要觉得是全局数据就直接可以在vue中使用了。
如定义全局变量,也是找不到的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
</div>
<script src="./js/vue.js"></script>
<script>
function fn() {
console.log(1);
}
let v2 = 100;
let app = new Vue({
el: '#app',
data: {
v1: 1
}
});
</script>
</body>
</html>
全局变量,vue
也是拿不到的,会报错。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.44
Branch: branch01commit description:a0.44(example01-2——事件的注意事项)
tag:a0.44
2.1.3 example01-3
全局函数式不能直接绑定,但是针对一些特殊内置函数和对象是可以的
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
{{Math.random()}}
数据都需要挂载Vue
对象下的,不是全局的变量或者函数就可以直接使用的,但是针对系统的函数(如:math
下的函数)除外。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.45
Branch: branch01commit description:a0.45(example01-3——事件的可绑定内置函数)
tag:a0.45
3. 组件的 methods
选项
在组件选项中,提供了一个 methods
选项,用来存放组件中使用的函数方法,且存放在 methods
中的函数方法可以通过组件实例(this
)进行访问。
3.1 example02
3.1.1 example02-1
vue
对象下得函数不能随便放到data
中,应该放methods
属性中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
{{Math.random()}}
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1
},
methods: {
fn(e) {
this.v2++;
},
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.46
Branch: branch01commit description:a0.46(example02-1——事件正确的方式绑定函数)
tag:a0.46
3.1.2 example02-2
为啥点击事件触发Math.random()
呢?
这样的改变是vue
所期望的。这大概是因为vue2
中是用 render(){}
方法,当你用vue
的{{Math.random()}}
或其他的vue
指令绑定时,包括v-if
,当template
改变时都会被调用,当用vue
的click
改变 template
时,整个template
的DOM
将重新计算,所以就又调用了Math.random()
重新得到新的值,如果你用data
中 msg: Math.random()
这样是不会重新计算的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
{{msg}}
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1,
msg: Math.random()
},
methods: {
fn(e) {
this.v2++;
},
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.47
Branch: branch01commit description:a0.47(example02-2——解决触发Math.random函数的问题和原理)
tag:a0.47
4. 通过内联方式绑定事件处理函数
<组件 @事件名称="fn" />
<script>
new Vue({
...,
methods: {
fn() {
//...
}
}
})
</script>
- 事件绑定函数中的
this
指向组件实例 - 事件绑定函数中的第一个参数默认为
event
对象
<组件 @事件名称="fn('kaikeba', $event)" />
<script>
new Vue({
...,
methods: {
fn(name, ev) {
//...
}
}
})
</script>
也可以在事件绑定中直接调用函数(并不会立即执行,也是通过事件触发执行的)
- 事件对象需要手动传入,名称为
$event
4.1 example03
4.1.1 example03-1
vue
中事件函数的this
指向该组件实例 => app
,不是绑定的元素,主要方便调用组件里其他的东西,如数据,一些其他的特性等。
默认情况下,函数的第一个参数是事件对象:event
,方便获取事件绑定的元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1
},
methods: {
fn(e) {
this.v2++;
console.log(e);
},
}
});
</script>
</body>
</html>
以上是火狐,我们看一下谷歌:
小结:
vue 中事件函数的this指向该组件实例 : app
默认情况下,函数的第一个参数是事件对象:event
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.48
Branch: branch01commit description:a0.48(example03-1——事件绑定函数的事件对象)
tag:a0.48
4.1.2 example03-2
通过:style
设置列表样式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
<hr>
<ul>
<li v-for="user in users" :style="{color: user.checked ? 'red':''}">{{user.username}}</li>
</ul>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1,
users: [
{id: 1, username: 'zs', checked: true},
{id: 2, username: 'ls', checked: false},
{id: 3, username: 'ww', checked: false}
]
},
methods: {
fn(e) {
this.v2++;
console.log(e);
},
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.49
Branch: branch01commit description:a0.49(example03-2——通过
:style
设置列表样式。)tag:a0.49
4.1.3 example03-3
也可利用class属性和样式表进行修改。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.checked {
background: red;
color: white;
}
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
<hr>
<ul>
<li v-for="user in users" :class="{'checked': user.checked}">{{user.username}}</li>
</ul>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1,
users: [
{id: 1, username: 'zs', checked: true},
{id: 2, username: 'ls', checked: false},
{id: 3, username: 'ww', checked: false}
]
},
methods: {
fn(e) {
this.v2++;
console.log(e);
},
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.50
Branch: branch01commit description:a0.50(example03-3——利用class属性和样式表进行修改。)
tag:a0.50
4.1.4 example03-4
但是,如果该函数不是直接被事件调用,而是被间接调用,需要传参数,看列表例子。
实现点击哪个,哪个就高亮。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.checked {
background: red;
color: white;
}
</style>
</head>
<body>
<div id="app">
<!-- @click="..." 里不要写if,它不支持 -->
<button @click="v1++">按钮</button>
{{v1}}
<hr>
<button @click="fn">按钮</button>
{{v2}}
<hr>
<ul>
<li
v-for="user in users"
:class="{'checked': user.checked}"
@click="doCheck(user, $event)"
>
<!-- 注意调用事件函数,事件对象需要手动传,并且$event是固定写法 -->
{{user.username}}
</li>
</ul>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
v1: 1,
v2: 1,
users: [
{id: 1, username: 'zs', checked: true},
{id: 2, username: 'ls', checked: false},
{id: 3, username: 'ww', checked: false}
]
},
methods: {
fn(e) {
this.v2++;
console.log(e);
},
doCheck(user, e) {
console.log(e)
user.checked = !user.checked;
}
}
});
</script>
</body>
</html>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.51
Branch: branch01commit description:a0.51(example03-4——实现点击哪个,哪个就高亮。)
tag:a0.51
5. 事件修饰符
在事件函数中,我们可以通过 ev.preventDefault()
、ev.stopPropagation()
来阻止默认行为,阻止冒泡,但是中 vue 中提供一些更加方便的方式来处理这些问题,这就是事件修饰符。
5.1 .stop
阻止事件冒泡
5.1.1 example04
5.1.1.1 example04-1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div style="padding: 50px; background: red" @click="fn1">
<button @click="fn2">按钮</button>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
},
methods: {
fn1() {
console.log('1111')
},
fn2(e) {
console.log('2222')
}
}
});
</script>
</body>
</html>
点击div
,正常触发事件。
但是点击按钮
会触发父级事件,按钮事件冒泡了。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.52
Branch: branch01commit description:a0.52(example04-1——按钮事件冒泡)
tag:a0.52
5.1.1.2 example04-2
原生代码解决:e.stopPropagation()
=> 原生js
禁止事件冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div style="padding: 50px; background: red" @click="fn1">
<button @click="fn2">按钮</button>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
},
methods: {
fn1() {
console.log('1111');
},
fn2(e) {
console.log('2222');
e.stopPropagation();
}
}
});
</script>
</body>
</html>
但是可能fn2
被用到其他事件,那里不需要禁止冒泡,这不就冲突了吗?
这种写法不太好。我们看看vue
提供的便捷方式:
<div id="app">
<div style="padding: 50px; background: red" @click="fn1">
<button @click.stop="fn2">按钮</button>
</div>
</div>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.53
Branch: branch01commit description:a0.53(example04-2——按钮事件VUE阻止事件冒泡)
tag:a0.53
5.2 .prevent
阻止默认行为
5.2.1 example05
禁止右键默认菜单
<div style="padding: 50px; background: red" @click="fn1" @contextmenu.prevent>
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.54
Branch: branch01commit description:a0.54(example05——按钮事件VUE阻止默认行为)
tag:a0.54
5.3 .self
只当事件是从侦听器绑定的元素本身触发时才触发回调。
只有自己才这么做,即仅限自己执行。
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
5.3.1 example06
5.3.1.1 example06-1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div style="padding: 50px; background: red" @click="fn1" @contextmenu.prevent>
<button @click.stop="fn2">按钮</button>
<button>111</button>
<button>222</button>
<button>333</button>
</div>
</div>
<script src="./js/vue.js"></script>
<script>
let app = new Vue({
el: '#app',
data: {
},
methods: {
fn1() {
console.log('1111')
},
fn2(e) {
console.log('2222')
}
}
});
</script>
</body>
</html>
第一个按钮
阻止了冒泡,但其余按钮未阻止冒泡。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.55
Branch: branch01commit description:a0.55(example06-1——多个按钮冒泡)
tag:a0.55
5.3.1.2 example06-2
.stop
是针对某个不想冒泡的元素,而这里想子元素都禁止冒泡!全加.stop
累死你!
<div style="padding: 50px; background: red" @click.self="fn1" @contextmenu.prevent>
<button @click="fn2">按钮</button>
<button>111</button>
<button>222</button>
<button>333</button>
</div>
原理其实就是判断一下当前的this
和事件源(event.target
)是不是同一个,是的话就自己触发。
参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a0.56
Branch: branch01commit description:a0.56(example06-2——.self的使用)
tag:a0.56
5.4 .capture
捕获
添加事件侦听器时使用 capture
模式。
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
5.5 .once
vue 2.1.4 新增
一次绑定,只触发一次回调。
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
不像其它只能对原生的 DOM 事件起作用的修饰符,.once
修饰符还能被用到自定义的组件事件上。
5.6 .passive
(vue2.3.0 新增
) 以 { passive: true }
模式添加侦听器
是否允许调用stop
、prevent
Vue 还对应 addEventListener
中的 passive
选项提供了 .passive
修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
这个 .passive
修饰符尤其能够提升移动端的性能。
不要把 .passive
和 .prevent
一起使用,因为 .prevent
将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive
会告诉浏览器你不想阻止事件的默认行为。
5.7 注意事项
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
6. 按键修饰符
vue
还提供了许多按键修饰符
6.1 .keyCode
只当事件是从特定键触发时才触发回调。
按哪个键盘,才触发事件
<组件 @keyup.13="fn" />
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
你可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。
keyCode
的事件用法已经被废弃了并可能不会被最新的浏览器支持。
使用 keyCode
attribute 也是允许的:
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
6.2 .enter
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
6.3 .down
6.4 .exact
vue2.5.0 新增
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
7. 原生事件
自定义组件中可以自定义一些事件,可以通过 .native
修饰符来指定监听原生中的事件,而不是组件自定义事件,我们后面说到组件再做说明。
(后续待补充)