Vue 中addEventListener事件回调函数this的指向
在Vue中调用document.addEventListener添加事件回调函数,在回调函数中调用this对象时,通过调试发现,this指向的是之前调用document.addEventListener的Vue对象或者Vue组件示例代码如下:<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"
在Vue
中调用document.addEventListener
添加事件回调函数时,在回调函数中调用this
对象时,通过调试发现,this
指向的是之前调用document.addEventListener
的Vue
对象或者Vue
组件示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div style="width: 100px;height: 100px;background-color: #4CAF50" @mousedown="mouseDown($event)"></div>
</div>
</body>
<script>
new Vue({
el: "#app",
methods: {
mouseDown(event) {
document.addEventListener("mousemove", this.onmousemove);
},
onmousemove(event) {
console.log(this);
}
}
});
</script>
</html>
通过调试打印的日志:
但是如果将onmousemove
写在全局作用域呢?示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div style="width: 100px;height: 100px;background-color: #4CAF50" @mousedown="mouseDown($event)"></div>
</div>
</body>
<script>
function onmousemove(event) {
console.log(this);
}
new Vue({
el: "#app",
methods: {
mouseDown(event) {
document.addEventListener("mousemove", onmousemove);
},
}
});
</script>
</html>
打印结果如下:
发现this
指向变成了doucument
,即调用addEventListener
的对象。
为什么addEventListener
绑定的回调方法是Vue
对象内部的methods
方法时,this
指向的对象就是当前Vue
对象呢,通过查看源码发现Vue
在初始化methods
对象时,会将methods
里面的每个函数绑定到当前的Vue
对象,代码如下:
function initMethods (vm, methods) {
var props = vm.$options.props;
for (var key in methods) {
{
if (typeof methods[key] !== 'function') {
warn(
"Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " +
"Did you reference the function correctly?",
vm
);
}
if (props && hasOwn(props, key)) {
warn(
("Method \"" + key + "\" has already been defined as a prop."),
vm
);
}
if ((key in vm) && isReserved(key)) {
warn(
"Method \"" + key + "\" conflicts with an existing Vue instance method. " +
"Avoid defining component methods that start with _ or $."
);
}
}
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
}
}
上面最后一行的代码中调用的bind函数就是实现此功能的,代码如下:
var bind = Function.prototype.bind
? nativeBind
: polyfillBind;
如果当前在Function
的prototype
上存在bind
属性,也就是函数支持bind
方法绑定新的作用域,就直接调用bind
将当前vue
对象绑定到函数的作用域上,如果不支持就用apply
和call
来代替实现,通过bind
创建一个新函数,当这个新函数被调用时,它的 this
值是传递给 bind
的第一个参数,即传递的Vue
对象,其中nativeBind
和polyfillBind
代码如下:
function nativeBind(fn, ctx) {
return fn.bind(ctx)
}
function polyfillBind(fn, ctx) {
function boundFn(a) {
var l = arguments.length;
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
boundFn._length = fn.length;
return boundFn
}
上面的效果和下面一样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div style="width: 100px;height: 100px;background-color: #4CAF50" @mousedown="mouseDown($event)"></div>
</div>
</body>
<script>
function onmousemove(event) {
console.log(this);
}
let v=new Vue({
el: "#app",
methods: {
mouseDown(event) {
document.addEventListener("mousemove", onmousemove.bind(v));
},
}
});
</script>
</html>
更多推荐
所有评论(0)