全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

深入理解Vue transition源码分析

这两天学习了Vue transition感觉这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记。

本来打算自己造一个transition的轮子,所以决定先看看源码,理清思路。Vue的transition组件提供了一系列钩子函数,并且具有良好可扩展性。

了解构建过程

既然要看源码,就先让Vue在开发环境跑起来,首先从GitHub clone下来整个项目,在文件./github/CONTRIBUTING.md中看到了如下备注,需要强调一下的是,npm run dev构建的是runtime + compiler版本的Vue。

# watch and auto re-build dist/vue.js
$ npm run dev

紧接着在package.json中找到dev对应的shell语句,就是下面这句

"scripts": {
  "dev": "rollup -w -c build/config.js --environment TARGET:web-full-dev",
  ...
}

Vue2使用rollup打包,-c 后面跟的是打包的配置文件(build/config.js),执行的同时传入了一个TARGET参数,web-full-dev。打开配置文件继续往里找。

...
const builds = {
 ...
 'web-full-dev': {
   entry: resolve('web/entry-runtime-with-compiler.js'),
   dest: resolve('dist/vue.js'),
   format: 'umd',
   env: 'development',
   alias: { he: './entity-decoder' },
   banner
 },
 ...
}

从上面的构建配置中,找到构建入口为web/entry-runtime-with-compiler.js,它也就是umd版本vue的入口了。 我们发现在Vue的根目录下并没有web这个文件夹,实际上是因为Vue给path.resolve这个方法加了个alias, alias的配置在/build/alias.js中

module.exports = {
 vue: path.resolve(__dirname, '../src/platforms/web/entry-runtime-with-compiler'),
 compiler: path.resolve(__dirname, '../src/compiler'),
 core: path.resolve(__dirname, '../src/core'),
 shared: path.resolve(__dirname, '../src/shared'),
 web: path.resolve(__dirname, '../src/platforms/web'),
 weex: path.resolve(__dirname, '../src/platforms/weex'),
 server: path.resolve(__dirname, '../src/server'),
 entries: path.resolve(__dirname, '../src/entries'),
 sfc: path.resolve(__dirname, '../src/sfc')
}

web对应的目录为'../src/platforms/web',也就是src/platforms/web,顺着这个文件继续往下找。查看src/platforms/web/entry-runtime-with-compiler.js的代码,这里主要是处理将Vue实例挂载到真实dom时的一些异常操作提示, ,比如不要把vue实例挂载在body或html标签上等。但是对于要找的transition,这些都不重要,重要的是

import Vue from './runtime/index'

Vue对象是从当前目录的runtime文件夹引入的。打开./runtime/index.js,先查看引入了哪些模块, 发现Vue是从src/core/index引入的,并看到platformDirectives和platformComponents,官方的指令和组件八九不离十就在这了。

import Vue from 'core/index'
...
...
import platformDirectives from './directives/index'
import platformComponents from './components/index'

...
// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop

在platformComponents中发现transtion.js,它export了一个对象,这个对象有name,props和rander方法,一个标准的Vue组件。至此算是找到了源码位置。

export default {
 name: 'transition',
 props: transitionProps,
 abstract: true,

 render (h: Function) {
  ...
 }
}

transition实现分析

从上一节的代码中,可以看到directives和components是保存在Vue.options里面的, 还需要注意一下后面的Vue.prototype.patch,因为transtion并不单单是以一个组件来实现的,还需要在Vue构造函数上打一些patch。

rander当中的参数h方法,就是Vue用来创建虚拟DOM的createElement方法,但在此组件中,并没有发现处理过度动画相关的逻辑,主要是集中处理props和虚拟DOM参数。因为transtion并不单单是以一个组件来实现的,它需要操作真实dom(未插入文档流)和虚拟dom,所以只能在Vue的构造函数上打一些patch了。

往回看了下代码,之前有一句Vue.prototype.__patch__ = inBrowser ? patch : noop,在patch相关的代码中找到了transition相关的实现。modules/transtion.js

这就是过渡动画效果相关的patch的源码位置。

export function enter (vnode: VNodeWithData, toggleDisplay: ?() => void) {
 ...
}
export function leave (vnode: VNodeWithData, rm: Function) {
 ...
}

export default inBrowser ? {
 create: _enter,
 activate: _enter,
 remove (vnode: VNode, rm: Function) {
  /* istanbul ignore else */
  if (vnode.data.show !== true) {
   leave(vnode, rm)
  } else {
   rm()
  }
 }
} : {}

这个模块默认export的对象包括了三个生命周期函数create,activate,remove,这应该是Vue没有对外暴露的生命周期函数,create和activate直接运行的就是上面的enter方法,而remove执行了leave方法。

继续看最重要的是两个方法,enter和leave。通过在这两个方法上打断点得知,执行这两个方法的之前,vnode已经创建了真实dom, 并挂载到了vnode.elm上。其中这段代码比较关键

// el就是真实dom节点
beforeEnterHook && beforeEnterHook(el)
if (expectsCSS) {
 addTransitionClass(el, startClass)
 addTransitionClass(el, activeClass)
 nextFrame(() => {
  addTransitionClass(el, toClass)
  removeTransitionClass(el, startClass)
  if (!cb.cancelled && !userWantsControl) {
   if (isValidDuration(explicitEnterDuration)) {
    setTimeout(cb, explicitEnterDuration)
   } else {
    whenTransitionEnds(el, type, cb)
   }
  }
 })
}

首先给el添加了startClass和activeClass, 此时dom节点还未插入到文档流,推测应该是在create或activate勾子执行完以后,该节点被插入文档流的。nextFrame方法的实现如下, 如requestAnimationFrame不存在,用setTimeout代替

const raf = inBrowser && window.requestAnimationFrame
 ? window.requestAnimationFrame.bind(window)
 : setTimeout

export function nextFrame (fn: Function) {
 raf(() => {
  raf(fn)
 })
}

这种方式的nextFrame实现,正如官方文档中所说的在下一帧添加了toClass,并remove掉startClass,最后在过渡效果结束以后,remove掉了所有的过渡相关class。至此‘进入过渡'的部分完毕。

再来看‘离开过渡'的方法leave,在leave方法中打断点,发现html标签的状态如下

<p>xxx</p>
<!---->

<!----> 为vue的占位符,当元素通过v-if隐藏后,会在原来位置留下占位符。那就说明,当leave方法被触发时,原本的真实dom元素已经隐藏掉了(从vnode中被移除),而正在显示的元素,只是一个真实dom的副本。

leave方法关键代码其实和enter基本一致,只不过是将startClass换为了leaveClass等,还有处理一些动画生命周期的勾子函数。在动画结束后,调用了由组件生命周期remove传入的rm方法,把这个dom元素的副本移出了文档流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Vue  # transition  # transition源码  # vue2.0 中使用transition实现动画效果使用心得  # Vue-router结合transition实现app前进后退动画切换效果的实例  # Vue Transition实现类原生组件跳转过渡动画的示例  # 详解vue2.0 transition 多个元素嵌套使用过渡  # Vue 过渡(动画)transition组件案例详解  # Vue运用transition实现过渡动画  # 的是  # 文档  # 周期函数  # 是从  # 掉了  # 来实现  # 还需  # 配置文件  # 主要是  # 是在  # 是因为  # 就在  # 看了  # 都不  # 那就  # 一句  # 在这  # 在此  # 这就是  # 会在 


相关文章: 微信小程序 五星评分(包括半颗星评分)实例代码  建站之星会员如何解锁更多建站功能?  建站之星如何优化SEO以实现高效排名?  网站制作公司广州有几家,广州尚艺美发学校网站是多少?  mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?  网站制作说明怎么写,简述网页设计的流程并说明原因?  如何高效配置香港服务器实现快速建站?  制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?  如何在IIS中新建站点并配置端口与IP地址?  如何在云主机上快速搭建多站点网站?  如何生成腾讯云建站专用兑换码?  如何设置并定期更换建站之星安全管理员密码?  如何在阿里云购买域名并搭建网站?  高防服务器租用指南:配置选择与快速部署攻略  建站IDE高效指南:快速搭建+SEO优化+自适应模板全解析  移民网站制作流程,怎么看加拿大移民官网?  建站之星代理商如何保障技术支持与售后服务?  如何用wdcp快速搭建高效网站?  如何使用Golang安装API文档生成工具_快速生成接口文档  高性价比服务器租赁——企业级配置与24小时运维服务  如何通过IIS搭建网站并配置访问权限?  制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?  如何在局域网内绑定自建网站域名?  高防服务器:AI智能防御DDoS攻击与数据安全保障  制作网站外包平台,自动化接单网站有哪些?  学校免费自助建站系统:智能生成+拖拽设计+多端适配  电商平台网站制作流程,电商网站如何制作?  实例解析angularjs的filter过滤器  教程网站设计制作软件,怎么创建自己的一个网站?  广州顶尖建站服务:企业官网建设与SEO优化一体化方案  网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  如何通过二级域名建站提升品牌影响力?  网站专业制作公司有哪些,做一个公司网站要多少钱?  Android自定义listview布局实现上拉加载下拉刷新功能  建站主机选哪种环境更利于SEO优化?  微课制作网站有哪些,微课网怎么进?  简单实现Android验证码  如何快速查询域名建站关键信息?  宝塔建站后网页无法访问如何解决?  微网站制作教程,我微信里的网站怎么才能复制到浏览器里?  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  如何制作网站标识牌,动态网站如何制作(教程)?  c# Task.ConfigureAwait(true) 在什么场景下是必须的  如何在橙子建站中快速调整背景颜色?  建站三合一如何选?哪家性价比更高?  C++如何将C风格字符串(char*)转换为std::string?(代码示例)  企业网站制作费用多少,企业网站空间一般需要多大,费用是多少?  电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。