事件分为两类事件: DOM事件,自定义事件
一、DOM事件
(一)、定义
v-on指令(通常缩写为@符号)来监听Dom事件,触发事件时执行一些JavaScript接收调用的方法名称。
-
单事件
<view @click="clickEvent(‘参数1’)">clickEvent</view>
clickEvent(){
console.log("clickEvent:1")
},
clickEvent(e){
console.log("clickEvent:2")
},
clickEvent(e1,e2){
console.log("clickEvent:3")
},
结果:
clickEvent:3
//执行最后一个方法
②多事件
<view @click="one($event),two($event)">多事件</view>
// 多事件执行
one(){
console.log("one")
},
two(){
console.log("two")
}
结果:
one
two
(二)、事件修饰符
.stop 阻止冒泡事件继续往下传播(应用于一个局部响应点击事件),但是在有默认的事件的标签无法阻止,a[href="#"],button[type="submit"]
.prevent 用于阻止默认事件event.preventdefault(),点击 a 标签本质上市调用了preventdefault默认事件然后发生了超链接跳转,那么给事件加
上self关键字,就不会进行跳转了,所以在点击超链接时可以做一些自己想要操作了
.capture 冒泡顺序,先冒泡有修饰符的由外层往里,再由无修饰的由里到顺序进行
.self 只有点击自己才会响应事件,不会受到冒泡事件的影响,由里到外事件传递过来会忽略.self修饰的事件
.once 点击事件只会执行一次
.passive 拦截默认事件,a[href="#"],button[type="submit"]
.passive 不拦截默认事件,事先告诉浏览器不用查了,没有阻止默认事件,提升性能
.native 原生点击事件
.prevent 提交事件不再重载页面
.target 是当前元素自身时触发处理函数
.left - 左键事件
.right - 右键事件
.middle - 中间滚轮事件
对应按键的别名
.enter
.tab
.delete (捕获 "删除" 和 "退格" 键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
3.冒泡顺序以及实例
(1)、冒泡事件顺序:由里往外冒(无修饰符capture)
<view @click="log(1)" style="width: 100%;height: 500px;background: #007AFF;">
one
<view @click="log(2)" style="width: 100%;height: 400px;background: #4CD964;">
two
<view @click="log(3)" style="width: 100%;height: 300px;background: #F0AD4E;">
three
<view @click="log(4)" style="width: 100%;height:200px;background: #DD524D;">
four
</view>
</view>
</view>
</view>
执行结果如下:
4
3
2
1
(2)、带capture修饰符的实例
<view @click.capture="log(1)" style="width: 100%;height: 500px;background: #007AFF;">
one
<view @click.capture="log(2)" style="width: 100%;height: 400px;background: #4CD964;">
two
<view @click="log(3)" style="width: 100%;height: 300px;background: #F0AD4E;">
three
<view @click="log(4)" style="width: 100%;height: 200px;background: #DD524D;">
four
</view>
</view>
</view>
</view>
执行结果如下:
1
2
4
3
二、自定义事件
主要提供了四个自定义事件$on $once $off $emit
(一)、$on 事件
监听当前自定义的事件接收触发事件传递过来的数据
参数:
{string | Array<string>} event (数组只在 2.2.0+ 中支持)
{Function} callback
源码:
Vue.prototype.$on = function (event, fn) {
const vm: Component = this
if (Array.isArray(event)) {
// 传入的是数组就遍历每个事件监听
for (let i = 0, l = event.length; i < l; i++) {
this.$on(event[i], fn)
}
} else {
// 传入的是字符串就只监听该事件
(vm._events[event] || (vm._events[event] = [])).push(fn)
}
return vm
}
当传入的监听的事件是个数组就遍历整个数组执行单个的订阅事件,当只有一个的时候就把监听放在_eventss事件中心执行
uni.$on("setIndexValue",res=>{
console.log("$on:res===>",res);
})
uni.$emit(setIndexValue,1);
每执行一次emit就会调用一次on方法,不移除把on监听移除的话,下次执行on方法,又会增加一次执行,调用emit就会调用on方法两次,所以要及时移除不需要监听的,
如果只需要执行一次的话就用once方法
(二)、$emit事件
触发事件自定义的事件 触发事件给监听的方法传递数据
参数:
{string} eventName 触发的事件名
[...args] 传递给事件的参数
源码:
Vue.prototype.$emit = function (event: string): Component {
const vm: Component = this
let cbs = vm._events[event] // 事件中心获取到回调函数
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
try {
cbs[i].apply(vm, args) // 遍历回调事件,然后调用每个监听的回调方法
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
}
}
从事件中心获取监听的方法,参数,然后执行回调函数
$off 移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
this.$off() 就会移除所有事件
如果只提供了事件,则移除该事件所有的监听器;
如果同时提供了事件与回调,则只移除这个回调的监听器。
(三)、$once事件
自定义事件只会触发一次,触发之后就会被移除
参数:
{string} event
{Function} callback
源码:
Vue.prototype.$once = function (event, fn) {
const vm: Component = this
function on () {
vm.$off(event, on) // 监听事件触发就执行移除监听器
fn.apply(vm, arguments)
}
on.fn = fn
vm.$on(event, on)
return vm
}
底层原理就是只要触发了on方法,就开始执行移除on方法的监听
执行$off时报错,因为已经移除了on监听,子函数on替换了原本订阅事件的回调fn
(四)、$off事件
参数:
{string | Array<string>} event (只在 2.2.2+ 支持数组)
{Function} [callback]
源码:
Vue.prototype.$off = function (event, fn) {
const vm: Component = this
// all 没有参数就移除所有监听事件
if (!arguments.length) {
vm._events = Object.create(null)
return vm
}
// array of events 如果是数组则遍历数据分别移除监听事件
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$off(event[i], fn)
}
return vm
}
// specific event
const cbs = vm._events[event]
if (!cbs) {
// 没有回调函数直接忽略
return vm
}
if (!fn) {
// 没有传回调函数,那就直接移除该事件的监听,也就是所有的回调函数也移除
vm._events[event] = null
return vm
}
if (fn) {
// specific handler 有回调函数的,找到相应的回调函数移除即可,监听事件还在,仅仅移除这个回调函数的监听
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
}
return vm
}