VUE的点击事件我们都用过,我们来看一下最简单的click底层是如何实现的。
<div id="test1" @click="click1">click1</div>
vue初始化的时候,将method中的方法代理到vue[key]的同时修饰了事件的回调函数。绑定了作用域。
function initState (vm) {
vm._watchers = [];
var opts = vm.$options;
if (opts.props) { initProps(vm, opts.props); }
if (opts.methods) { initMethods(vm, opts.methods); }//1.在此初始化
if (opts.data) {
initData(vm);
} else {
observe(vm._data = {}, true /* asRootData */);
}
if (opts.computed) { initComputed(vm, opts.computed); }
if (opts.watch) { initWatch(vm, opts.watch); }
}
我们再去看一下initMethods方法
function initMethods (vm, methods) {
var props = vm.$options.props;
for (var key in methods) {
vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
{
if (methods[key] == null) {
warn(
"method \"" + key + "\" has an undefined value 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
);
}
}
}
}
看一下bind方法通过返回函数修饰了事件的回调函数。绑定了事件回调函数的this。并且让参数自定义
function bind (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
}
当VUE运行编译时会把div等原始元素变成ast并通过函数genHandler进行处理
当 事件函数有修饰符,处理修饰符并添加修饰符对应的函数语句
function genHandler (
name,
handler
) {
if (!handler) {
return 'function(){}'
}
if (Array.isArray(handler)) {
return ("[" + (handler.map(function (handler) { return genHandler(name, handler); }).join(',')) + "]")
}
var isMethodPath = simplePathRE.test(handler.value);
var isFunctionExpression = fnExpRE.test(handler.value);
if (!handler.modifiers) {
//返回没有修饰符的回调函数
return isMethodPath || isFunctionExpression
? handler.value
: ("function($event){" + (handler.value) + "}") // inline statement
} else {
//含有修饰符
var code = '';
var genModifierCode = '';
var keys = [];
for (var key in handler.modifiers) {
if (modifierCode[key]) {
//处理修饰符数组
genModifierCode += modifierCode[key];
if (keyCodes[key]) {
keys.push(key);
}
} else {
keys.push(key);
}
}
if (keys.length) {
code += genKeyFilter(keys);
}
// Make sure modifiers like prevent and stop get executed after key filtering
if (genModifierCode) {
code += genModifierCode;
}
var handlerCode = isMethodPath
? handler.value + '($event)'
: isFunctionExpression
? ("(" + (handler.value) + ")($event)")
: handler.value;
return ("function($event){" + code + handlerCode + "}")
}
}
我们看看render函数div的代码
_c('div',{attrs:{"id":"test1"},on:{"click":click1}},[_v("click1")]),_v(" ")
在浏览器渲染成最终dom时会调用核心函数
function add$1 (
event,
handler,
once$$1,
capture,
passive
) {
if (once$$1) {
var oldHandler = handler;
var _target = target$1; // save current target element in closure
handler = function (ev) {
var res = arguments.length === 1
? oldHandler(ev)
: oldHandler.apply(null, arguments);
if (res !== null) {
remove$2(event, handler, capture, _target);
}
};
}
target$1.addEventListener(
event,
handler,
supportsPassive
? { capture: capture, passive: passive }//此处绑定点击事件
: capture
);
}
总结:div元素元素添加了.native修饰符的事件。最终EventTarget.addEventListener() 挂载事件
知行办公,专业移动办公平台 https://zx.naton.cn/
【总监】十二春秋之,3483099@qq.com;
【Master】zelo,616701261@qq.com;
【运营】狼行天下,897221533@qq.com;
【产品设计】流浪猫,364994559@qq.com;
【体验设计】兜兜,2435632247@qq.com;
【iOS】淘码小工,492395860@qq.com;iMcG33K,imcg33k@gmail.com;
【Android】人猿居士,1059604515@qq.com;思路的顿悟,1217022114@qq.com;
【java】首席工程师MR_W,feixue300@qq.com;
【测试】土镜问道,847071279@qq.com;
【数据】喜乐多,42151960@qq.com;
【安全】保密,你懂的。