VUE-简单Click事件过程

VUE的点击事件我们都用过,我们来看一下最简单的click底层是如何实现的。

click1

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/
【总监】十二春秋之,[email protected]
【Master】zelo,[email protected]
【运营】狼行天下,[email protected]
【产品设计】流浪猫,[email protected]
【体验设计】兜兜,[email protected]
【iOS】淘码小工,[email protected];iMcG33K,[email protected]
【Android】人猿居士,[email protected];思路的顿悟,[email protected]
【java】首席工程师MR_W,[email protected]
【测试】土镜问道,[email protected]
【数据】喜乐多,[email protected]
【安全】保密,你懂的。

你可能感兴趣的:(VUE-简单Click事件过程)