vue常见指令以及语法,vue的指令及用法

  vue常见指令以及语法,vue的指令及用法

  自定义指令是vue中第二常用的指令,它包含五个生命周期挂钩:绑定、插入、更新、组件更新和解除绑定。本文将介绍vue指令的工作原理。

  

目录

  一、基本用法二。指导工作原理2.1。初始化2.2。模板编译2.3。生成渲染方法2.4。生成VNode2.5 .生成real DOM III。通知四。摘要

  

一、基本使用

  官网案例:

  div id=应用程序

  输入类型=文本 v-模型=输入值 v-焦点

  /div

  脚本

  Vue.directive(focus ,{

  //第一次绑定元素时调用

  bind () {

  console . log(“bind”)

  },

  //当绑定元素插入DOM时.

  插入:函数(el) {

  console.log(inserted )

  焦点()

  },

  //当其组件的VNode更新时调用

  update () {

  console.log(更新)

  },

  //指令所在组件的VNode及其子VNode都被更新调用。

  componentUpdated () {

  console . log(“component updated”)

  },

  //当指令从元素解除绑定时,只调用一次

  unbind () {

  console.log(unbind )

  }

  })

  新Vue({

  数据:{

  输入值:“”

  }

  }).$ mount(“# app”)

  /脚本

  

二、指令工作原理

  

2.1、初始化

  在初始化全局API时,在platforms/web下,调用createPatchFunction生成一个patch方法,将VNode转换成真正的DOM。初始化的一个重要步骤是定义对应于DOM节点的hooks方法。在创建、激活、更新、删除和销毁DOM的过程中,通过轮询调用相应的钩子方法,这些钩子有的是指令声明循环的入口。

  //src/core/vdom/patch.js

  const hooks=[create , activate , update , remove , destroy]

  导出函数createPatchFunction(后端){

  让我,j

  const cbs={}

  const { modules,nodeOps }=后端

  for(I=0;I挂钩.长度;i) {

  cbs[hooks[i]]=[]

  //模块对应vue中的模块,包括class、style、domlistener、domprops、attrs、directive、ref和transition。

  for(j=0;j模块.长度;j) {

  if(isDef(modules[j][hooks[I]]){

  //最后,钩子被转换成{hookEvent: [cb1,cb2.],}

  cbs[hooks[i]]。push(模块[j][挂钩[i]])

  }

  }

  }

  //.

  返回功能补丁(oldVnode,Vnode,hydrating,removeOnly) {

  //.

  }

  }

  

2.2、模板编译

  编译模板是为了解析指令参数,具体解构的ASTElement如下:

  {

  标签:“输入”,

  父元素:ASTElement,

  指令:[

  {

  Arg: null,//参数

  End: 56,//指令的结束字符位置

  IsdDynamicArg: false,//动态参数,以v-xxx[dynamicParams]=xxx 的形式调用

  修饰符:未定义,//指令修饰符

  名称:型号,

  RawName: v-model ,//命令名

  Start: 36,//指令起始字符位置

  值:输入值//模板

  },

  {

  arg: null,

  end: 67,

  isDynamicArg:假,

  修饰符:未定义,

  名称:“焦点”,

  raw name:“v焦点”,

  开始:57,

  值:“”

  }

  ],

  //.

  }

  

2.3、生成渲染方法

  Vue推荐使用指令操作DOM。由于自定义指令可能会修改DOM或属性,因此有必要避免指令对模板解析的影响。在生成渲染方法的时候,首先要处理的就是指令,比如v-model,本质上就是一个语法糖。拼接渲染函数时,元素会加入值属性和输入事件(以输入为例,这个也可以自定义)。

  用(这个){

  return _c(div ,{

  属性:{

  id :应用程序

  }

  },[_c(输入,{

  指令:[{

  名称:型号,

  原始名称:“v型”,

  值:(inputValue),

  表达式:“输入值”

  }, {

  名称:“焦点”,

  raw name:“v焦点”

  }],

  属性:{

  键入:文本

  },

  domProps: {

  值:(输入值)//处理v型车指令时添加的属性

  },

  开:{

  输入:函数($event) { //处理v型车指令时添加的自定义事件

  if(event。目标。合成)

  返回;

  输入值=$event.target.value

  }

  }

  })])

  }

  

2.4、生成VNode

  某视频剪辑软件的指令设计是方便我们操作多姆,在生成虚拟节点时,指令并没有做额外处理。

  

2.5、生成真实DOM

  在某视频剪辑软件初始化过程中,我们需要记住两点:

  状态的初始化是父-子,如创建前、创建后、安装前,调用顺序是父-子

  真实数字正射影像图挂载顺序是子-父,如安装,这是因为在生成真实数字正射影像图过程中,如果遇到组件,会走组件创建的过程,真实数字正射影像图的生成是从子到父一级级拼接。

  在修补过程中,每此调用createElm生成真实数字正射影像图时,都会检测当前虚拟节点是否存在数据属性,存在,则会调用invokeCreateHooks,走初创建的钩子函数,核心代码如下:

  //src/core/vdom/patch.js

  函数createElm(

  vnode,

  insertedVnodeQueue,

  parentElm,

  雷菲尔姆,

  嵌套,

  ownerArray,

  指数

  ) {

  //.

  //createComponent有返回值,是创建组件的方法,没有返回值,则继续走下面的方法

  if (createComponent(vnode,insertedVnodeQueue,parentElm,refElm)) {

  返回

  }

  常数数据=vnode.data

  //.

  if (isDef(data)) {

  //真实节点创建之后,更新节点属性,包括指令

  //指令首次会调用约束方法,然后会初始化指令后续钩住方法

  invokeCreateHooks(vnode,insertedVnodeQueue)

  }

  //从底向上,依次插入

  insert(parentElm,vnode.elm,refElm)

  //.

  }

  以上是指令钩子方法的第一个入口,是时候揭露directive.js神秘的面纱了,核心代码如下:

  //src/core/vdom/modules/directions。射流研究…

  //默认抛出的都是更新指令方法

  导出默认值{

  创建:更新指令,

  更新:更新指令,

  销毁:函数解除绑定指令(vnode:VNodeWithData){

  //销毁时,vnode===emptyNode

  更新指令(vnode,emptyNode)

  }

  }

  函数更新指令(旧的vnode:VNodeWithData,vnode: VNodeWithData) {

  if(旧vnode。数据。指令 vnode。数据。指令){

  _update(oldVnode,Vnode)

  }

  }

  function _update (oldVnode,vnode) {

  const is create=old vnode===空节点

  const is destroy=vnode===空节点

  const old dirs=规范化指令(旧vnode。数据。指令,oldVnode.context)

  const new dirs=规范化指令(vnode。数据。指令,vnode.context)

  //插入后的回调

  const dirsWithInsert=[

  //更新完成后回调

  const dirsWithPostpatch=[]

  字母键,旧目录,目录

  对于(键入新目录){

  oldDir=oldDirs[key]

  方向=新目录[答案]

  //新元素指令,会执行一次插入的钩子方法

  如果(!旧目录){

  //新指令,绑定

  callHook(dir, bind ,vnode,oldVnode)

  如果(目录定义目录定义插入){

  dirsWithInsert.push(dir)

  }

  }否则{

  //现有指令,更新

  //已经存在元素,会执行一次组件更新钩子方法

  目录。旧值=旧目录。值

  dir.oldArg=oldDir.arg

  呼叫挂钩(目录,更新,虚拟节点,旧虚拟节点)

  如果(目录定义目录定义组件更新){

  dirsWithPostpatch.push(dir)

  }

  }

  }

  if (dirsWithInsert.length) {

  //真实数字正射影像图插入到页面中,会调用此回调方法

  const callInsert=()={

  对于(设I=0;i dirsWithInsert.lengthi ) {

  callHook(dirsWithInsert[i], inserted ,vnode,oldVnode)

  }

  }

  //VNode合并插入挂钩

  如果(isCreate) {

  mergeVNodeHook(vnode, insert ,callInsert)

  }否则{

  callInsert()

  }

  }

  if (dirsWithPostpatch.length) {

  mergeVNodeHook(vnode, postpatch ,()={

  对于(设I=0;i dirsWithPostpatch.lengthi ) {

  callHook(dirsWithPostpatch[i], componentUpdated ,vnode,oldVnode)

  }

  })

  }

  如果(!isCreate) {

  对于(键入旧目录){

  如果(!newDirs[key]) {

  //不再存在,解除绑定

  callHook(oldDirs[key], unbind ,oldVnode,oldVnode,isDestroy)

  }

  }

  }

  }

  对于第一次创建,执行过程如下:

  1.oldVnode===emptyNode,isCreate为真,调用当前元素中的所有绑定钩子方法。

  2.检查指令中是否存在插入的钩子,如果存在,将插入的钩子合并到VNode.data.hooks属性中。

  3.3之后。DOM挂载,将执行invokeInsertHook,所有挂载的节点,如果VNode.data.hooks中有insert钩子被调用,触发指令绑定的insert方法。

  一般来说,第一次创建只使用bind和inserted方法,而update和componentUpdated对应于bind和inserted。当组件依赖状态发生变化时,会使用VNode diff算法对节点进行补丁更新,其调用过程如下:

  1.当响应数据改变时,调用dep.notify通知数据更新。

  2.调用patchVNode,有区别地更新新旧VNode,完整更新当前VNode属性(包括指令,将进入updateDirectives方法)。

  3.如果指令中存在update hook方法,则调用update hook方法,并初始化componentUpdated回调以将postpatch挂钩挂载到VNode.data.hooks中

  4.当前节点和子节点更新后,会触发postpatch钩子,也就是指令的componentUpdated方法。

  核心代码如下:

  //src/core/vdom/patch.js

  函数patchVnode(

  奥尔德夫诺德,

  vnode,

  insertedVnodeQueue,

  ownerArray,

  索引,

  仅移除

  ) {

  //.

  const oldCh=oldVnode.children

  const ch=vnode.children

  //完全更新节点的属性。

  if(isDef(data)is patchable(vnode)){

  for(I=0;I CBS . update . length;cbs.update[i](oldVnode,Vnode)

  if(isDef(I=data . hook)isDef(I=I . update))I(old Vnode,vnode)

  }

  //.

  if (isDef(data)) {

  //调用postpatch挂钩

  if(isDef(I=data . hook)isDef(I=I . post patch))I(old Vnode,vnode)

  }

  }

  Unbind方法是在节点销毁时调用invokeDestroyHook,这里不做描述。

  

三、注意事项

  使用自定义指令时,v-model和通用模板数据绑定还是有一些区别的。例如,虽然我传递的参数(v-xxx=param )是一个引用类型,但当数据发生变化时,它不能触发指令的bind或inserted。这是因为在指令的声明期间,bind和inserted在初始化期间只调用一次,后面只会跟着update和componentUpdated。

  指令的声明循环按照绑定-插入-更新-组件更新的顺序执行。如果指令需要依赖子组件的内容,建议在组件更新中编写相应的业务逻辑。

  在vue中,很多方法都是循环调用,比如hooks方法,事件回调等。通常,调用被包装在try catch中。这样做的目的是防止一个处理方法报错导致整个程序崩溃,可以供我们开发过程借鉴。

  

四、小结

  当我开始看整个vue源代码的时候,我对很多细节都不太了解。通过梳理每个具体功能的实现,我可以逐渐看到整个vue,同时也可以避免开发和使用中的一些坑。

  以上是分析Vue指令实现原理的详细内容。更多关于Vue指令原理的信息,请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: