模板编译 processAttrs

对于ast attributes处理(v-on/@)

利用onRE与dirRE来捕获事件

这里最重要的就是dynamic的判断,vue中可以用动态参数来命名事件名称,如@[prop],prop为data中的值。不过通常都是一个静态的事件名称如 @click

另一个核心方法就是addHandler

addHandler 往AST上添加events属性

1. 这里会对动态事件名称进行一些处理,也会对right,middle修饰符处理,另外对capture, passive, once的事件名称做了标记。分别添加 !, ~, # 符号。然后删除了对应属性值

2. 参数value为@click="handler"例子中的handler,在此处还在编译阶段handler本质上是一个string。然后对value做了处理,记录了模板解析event时候start和end的位置。

3. 对于单个事件有多回调函数绑定的情况,添加了一个important参数,以此来提前触发当前回调函数的执行

4. 另外,这里对鼠标的right和middle做了处理,在处理只有删除了对应属性值。对于键盘的事件没有做处理

AST -> code

修饰符:modifierCode

上面已经提到过了,本质上模板编译的时候会利用正则处理各种修饰符,然后根据对应关键词的生成代码。如常用的stop,prevent。

核心方法就是src/compiler/codegen/events.js的genHandler方法,以下是分析:

1. genHandlers

该方法就是简单的遍历events对象的键值对然后,对有无native修饰符与是否为dynamic事件做一个处理,其核心方法就是调用genHandler

genHandler

一些参数判断

事件函数的多种写法

在官方文档中演示了事件回调函数的多种写法,这些写法都在模板编译过程中进行了识别

下方三个正则表达式是模板编译时对event写法的判断依据,下面会有更详细的注释

1. 路径类写法

2. 箭头函数,匿名函数

3. 表达式 handler($event), a = 1

在vue中通常通过@click="handle($event)"来获取event对象,其实这里是vue在模板中做了一层包裹,将function($event){}套在handle($event)外部。

有修饰符的情况

修饰符在ast生成的过程中就已经捕获了,vue中对event事件的修饰符处理如下

先对修饰符做一个处理

最后座一层包裹,因为这里对键盘事件也做了处理,因此一定要拿到event对象

genCode

在处理完这些之后会生成字符串on:"…"/nativeOn:"…",最后生成render函数

组件初始化

组件初始化简单地说就是先对options做各种处理,最后执行渲染watcher,生成页面。

对native events的处理:

platforms/web/runtime/patch.js中有

const patch = createPatchFunction({nodeOps, modules})

modules源自:web/runtime/modules/index,导出含生命周期的对象**(非created周期)**

createPatchFunction

createPatchFunction往hooks内添加了updateDOMListeners,hooks为**并非是**组件的生命周期函数。在组件create与updated的时候就会触发updateDOMListeners函数。注册事件。

注意点: 这里create并非是组件created的**周期函数。**是在真实节点创建之后才会触发钩子,因此是可以拿到真实节点的。

updateDOMListeners

在调用modules.create的hook的时候触发了updateDOMListeners

其作用就是给用addEventListeners与removeEventListeners方法给真实dom节点添加事件。

updateListeners

将新旧事件进行对比更新。这里的add和remove可以给真实dom注册事件,也可以给组价注册事件。

占位符$vnode的真实dom事件:createComponent(部分)

对于组件而言,data.on赋值给listeners,把data.nativeOn赋值给data.on

data.on里面存放着的都是原生dom事件,组件内部的listeners都是用户自定义的事件。

因此,在组件patch过程中,创建组件的根节点的时候,就会把data.on内部的原生dom事件注册在dom上。

因此如果在h5元素使用native如 ,vue就会报错。这正是因为在这里做了处理,只有占位符vnode才可以有data.nativeOn的属性。是h5标签的节点不会调用createComponent方法,其data.on在创建节点的时候会绑定到节点上。

自定义事件(只针对组件间)

由createComponent函数可知,listeners存放了自定义事件。

在父子通讯的时候父组件只要v-on/@eventName,就可以监听到子组件emit出来的事件。

_init: initInternalComponent

创建子组件的时候会把占位符$vnode的$listeners传递给子组件的$options**(此时data.on已经是data.nativeOn,原始的data.on赋值给变量listeners)**

_init: initEvents

调用updateComponentListeners方法,最后还是调用了updateListeners方法(见前面文章注释)。

但是这里不同的是add和remove方法并非是document.addEventListener和document.removeEventListener

add/remove(vue中的发布订阅模式):

其实发布订阅模式比较简单,就不详细说明了,主要是add/remove方法。

小结

其实本质上,还是将父组件注册的回调函数传给了子组件的_events对象(让该函数存在于子组件中),但是看起来像是子组件调用了父组件的方法

eventBus

对于跨组件的组件通信,利用了vue实例可以有自身的_events对象,因此在Vue原型上创建一个空的vue实例,然后将vue所有组件上的函数都注册在这个实例对象的_events对象上,一次达到跨组件通信的目的

Vue.prototype.$bus=new Vue()

第三种情况:v-on="$listeners"

$listeners就是vnode.data.on的别称,因此通过$listeners就可以拿到父组件注册的非native事件。在爷孙组件通信的是可以使用$listeners通过父级组件将爷孙组件关联。

grand组件:

father组件:  // 此处是grand的事件

son组件:this.$emit(“test”) // 将father的$listeners传入son,而father的$listeners包含grand的事件,因此就将grand的事件传入了son中。

AST解析

在模板解析的时候会用正则匹配v-on,对于v-on="$listeners",vue将这种写法视为指令(directive),有不同的策略

on指令

_g

这里将$listeners对象与data.on进行合并,通过v-on指令我们可以一次性对组件注册多个事件。

最后

vue的事件基本上就是这样,其实这里面牵扯到了最核心的组件初始化和更新流程,关于此部分在本文中并没有明确说明,只是大概提了一下,一是要单纯靠文字说明费时费力(代码含有大量递归),而是本文重点是关注vue中的事件,在后面的更深入了解整个机制后会尝试说明写一篇vue组件初始化及更新的文章。

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

作者: Simplyme0823

原文链接:https://juejin.im/post/6861206075744452622

vue中 点击事件的写法_vue中的事件:原生事件与自定义事件__Vue.js相关推荐

  1. vue中 点击事件的写法_vue实现绑定事件的方法实例代码详解

    一.前言 vuejs中的事件绑定,使用来完成的,这里函数名是定义在Vue实例中的methods对象中的,Vue实例可以直接访问其中的方法. 二.事件绑定方式 1. 直接在标签中写js方法 执行方法的第 ...

  2. vue 点击div 获取位置_Vue中组件之间8种通信方式,值得收藏

    之前写了一篇关于vue面试总结的文章, 有不少网友提出组件之间通信方式还有很多, 这篇文章便是专门总结组件之间通信的 vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么 ...

  3. vue点击网页全屏_vue中实现点击变成全屏的多种方法

    项目中有点击按钮实现全屏功能 方式一:js实现全屏 全屏 data: data() { return { fullscreen: false }; }, methods: screen() { let ...

  4. vue中 点击事件的写法_vue基础之事件v-onclick=函数用法示例

    本文实例讲述了vue基础之事件v-οnclick=函数用法.分享给大家供大家参考,具体如下: v-on:click/mouseout/mouseover/dblclick/mousedown..... ...

  5. vue点击改变data值_vue 中自定义指令改变data中的值

    通过局部自定义指令实现了一个拖动的指令 html: script: methods:{ set(x,y){ this.data.x=x; this.data.y=y; } }, directives: ...

  6. vue中进度条写法_vue中自制进度条

    订单已提交,正在出票... :cell-style="{textAlign:'center'}" :data="tableData" border style= ...

  7. vue 关闭弹如何销毁子组件_vue中的eventBus会产生内存泄漏吗

    eventBus是在vue中经常用来解决跨组件消息传递的问题,但对它的使用要特别注意,否则会产生很严重的后果. 引入 本文介绍了eventBus的实现原理,并介绍它如何在vue中使用,并举了一个具体的 ...

  8. props写法_Vue中props的用法知识点

    Vue中props的详解 看一下官方文档: 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据.父组件的数据需要通过 prop 才能下发到子组件中. 也就是pr ...

  9. 前端vue里面点击加载更多_vue 原生添加滚动加载更多

    vue中添加滚动加载更多,因为是单页面所以需要在跳出页面时候销毁滚动,要不会出现错乱.我们在mounted建立滚动,destroyed销毁滚动. mounted () { window.addEven ...

最新文章

  1. 再也不怕复现论文!arXiv携手Papers with Code,提交论文+上传代码一步到位
  2. 2018-2019-1 20165226 《信息安全系统设计基础》第4周学习总结
  3. css实现页面文字不换行、自动换行、强制换行
  4. python standardscaler_Python快速实战机器学习之数据预处理
  5. 实战演练!CISCO交换机端口安全一点通 (
  6. 浅谈:云桌面在我国高校的应用前景
  7. 计算机继续教育笔记,《继续教育中的学习技术》读书笔记
  8. git reset简介
  9. PHP数组常用方法(优化版)
  10. ANSI SQL标准和准则
  11. mac+python3+selenium做pc的界面自动化测试
  12. 访问学者博士后面签后的几种情况?
  13. session是什么?
  14. java url生成二维码
  15. mysql函数循环查询的数据_MySQL 查询树结构、循环查询、查看函数、视图、存储过程...
  16. Matlab产生正交矩阵
  17. 对于后台站点的用户活跃度统计 除了记录用户登陆时间进行筛选,还有没有别的方法
  18. GPS卫星同步时钟在超高压变电站中应用
  19. 边缘云平台架构及商用实践(联通)
  20. 深入浅出pytorch笔记——第三章,第四章

热门文章

  1. linux线程同步教程,多线程同步
  2. jmeter连接mysql数据库驱动_十八、JMeter实战-JDBC连接MySQL数据库
  3. 集成 websocket 的四种方案
  4. fastjson为什么默认是无序的
  5. springboot的thymeleaf一个页面中引入其它页面
  6. 华为鸿蒙热水器,美的华为跨界联合!搭载鸿蒙OS的美的产品双11上市
  7. java ssh 那一层应该捕获异常_ssh经典异常!
  8. linux时间跳变影响,MONGO 集群 修改linux主机时间后的影响
  9. 商城系统php功能模块,yershop商城系统的支付模块问题
  10. Spring Boot————Web应用启动时自动执行ApplicationListener用法