Vue 中addEventListener事件回调函数this的指向[通俗易懂]

Vue 中addEventListener事件回调函数this的指向[通俗易懂]在Vue中调用document.addEventListener添加事件回调函数,在回调函数中调用this对象时,通过调试发现,this指向的是之前调用document.addEventListener的Vue对象或者Vue组件示例代码如下:<!DOCTYPEhtml><htmllang=”en”><head><metacharset=”UTF-8″><title>Title</title>&l

Vue中调用document.addEventListener添加事件回调函数时,在回调函数中调用this对象时,通过调试发现,this指向的是之前调用document.addEventListenerVue对象或者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;

如果当前在Functionprototype上存在bind属性,也就是函数支持bind方法绑定新的作用域,就直接调用bind将当前vue对象绑定到函数的作用域上,如果不支持就用applycall来代替实现,通过bind创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind 的第一个参数,即传递的Vue对象,其中nativeBindpolyfillBind代码如下:

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>

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/10101.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注