写文章不容易,点个赞呗兄弟 专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧 研究基于 Vue版本 【2.5.17】node
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧dom
【Vue原理】Event - 源码版 之 绑定标签DOM事件 函数
这里的绑定DOM事件,是指绑定原生标签的DOM 事件学习
由于组件也是能够绑定原生DOM事件的,不过并非在原生标签上绑定,而是直接在组件上绑定的,这部份内容会其余文章说明prototype
或者你能够看看白话版先了解下Event3d
【Vue原理】Event - 白话版 code
因为解析不是本内容的重点,因此在这里就不谈怎么解析的了,只说一个结果就行了blog
如今有这么一个模板递归
模板被解析成这样的渲染函数事件
渲染函数执行以后,获得这样的 VNode
你能够看到,事件被存放到了 vnode.data 上
Vnode 有疑惑的能够看介里
既然模板已经被解析完成了,下一步就是开始绑定了
好的,继续来走流程
在 template 解析获得 Vnode 以后,下面就会进行DOM生成挂载
而绑定事件,就发生在开始挂载,建立DOM 以后 的阶段
挂载时从 Vue.prototype._update 这个函数开始的
挂载的流程,能够看看这篇文章
从模板到DOM的简要流程
VNode建立完毕,传入 Vue.prototype._update 这个方法中,进行比对新旧VNode
而后生成DOM挂载页面
其中须要生成DOM,调用的方法是 createElm
建立DOM,在Vue 中调用的是 createElm 这个方法
看过之前的文章的,都知道这个函数的做用是
根据 vnode 生成DOM,而且进行挂载
而在 createElm 中,会调用一个函数去 处理模板上相关的数据
好比处理属性,类名,style 之类的,其中DOM事件也是在这里处理的
这个函数就是 invokeCreateHooks,继续往下看
function createElm(vnode) { // ....处理组件 // ....生成标签对应dom // ....递归遍历子节点 invokeCreateHooks(vnode); // ....插入DOM 节点 }
上面源码中出现的 invokeCreateHooks 这个方法是用来处理数据的
每种数据(style,class等),都有一个专门的函数去进行处理
而 invokeCreateHooks,就是负责执行每种数据的处理函数,很简单,就是一个单纯遍历执行的过程
其中就包括处理 DOM 事件的函数,即是 updateDOMListeners
function invokeCreateHooks( vnode ) { /** * 执行的函数包括下面这么多 * cbs = [ * create:[ * updateAttrs, updateClass, * updateDOMListeners, updateDOMProps, * updateStyle, create, updateDirectives * ] * ] **/ for (var b = 0; b < cbs.create.length; ++b) { // 其中会调用 updateDOMListeners // emptyNode 是空节点,由于这里是初始化才会调用的 // 因此旧节点是空节点 cbs.create[b](emptyNode, vnode); } .... }
下面看下 处理DOM 事件的函数
简化的源码,看起来顺眼多了,主要逻辑一清二楚,主要就是绑定事件和解绑事件,你看下喽,挺简单的
function updateDOMListeners(oldVnode, vnode) { var on = vnode.data.on || {}; var oldOn = oldVnode.data.on || {}; var target = vnode.elm; // 遍历绑定的事件 for (name in on) { newHandler = on[name]; oldHandler = oldOn[name]; // 没有旧事件,就直接添加新事件 if (typeof oldHandler === "undefined") { // 给事件回调包装一层 target.addEventListener(name, function(){ on[name]() // 执行保存在vnode的事件 }); } // 新事件和旧事件不同,替换旧事件 else if (newHandler !== oldHandler) { on[name] = newHandler; } } // 移除旧事件 for (name in oldOn) { // 旧事件不存在新事件中,直接移除 if (typeof on[name] === "undefined") { target.removeEventListener( name, oldOn[name] ); } } }
看看绑定函数和 移除函数,就只是简单使用 addEventListener 和 removeEventListener,我没看以前还觉得 Vue 写了不少兼容,没想到就是这么简单完成这个功能
有点惊讶,反正简单也好吧,哈哈哈,简单看着就是苏胡啊~~
一、新旧事件相同,替换旧事件
二、新事件不存在旧事件中,绑定新事件
三、旧事件不存在新事件中,解绑旧事件
其中会给回调事件函数包装一层函数,而后在内部执行绑定的回调,包装一层的缘由是,为了在回调中作点其余操做(好比宏微任务的处理等,这里为了简单去掉了)
而且旧事件回调改了的时候,就更加方便了,不用解绑再绑定,直接把执行的事件回调 on[name]替换掉就ok了
好的,原生标签绑定DOM 事件到这里就完成了,但愿对你们有所帮助