Deep understanding of Vue transition Source code analysis, vuetransition
After learning Vue transition over the past two days, I feel that there are a lot of knowledge points in this area, and it is very important. So I want to add some notes today.
I was planning to build a transition wheel by myself, so I decided to first look at the source code and clarify the ideas. The transition component of Vue provides a series of hook functions and is highly scalable.
Understand the Build Process
Now that you have to look at the source code, let the Vue run in the development environment. First, clone the entire project from GitHub, in the file. /github/CONTRIBUTING. md saw the following remarks. It should be emphasized that npm run dev builds a Vue of runtime + compiler.
# watch and auto re-build dist/vue.js$ npm run dev
Find the shell statement corresponding to dev in package. json.
"scripts": { "dev": "rollup -w -c build/config.js --environment TARGET:web-full-dev", ...}
Vue2 uses rollup for packaging.-c is followed by the package configuration file (build/config. js). During execution, a TARGET parameter, web-full-dev, is input. Open the configuration file and continue searching.
...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 }, ...}
From the above build configuration, find the build entry to web/entry-runtime-with-compiler.js, which is the entry to umd vue. We found that there is no web folder under the root directory of Vue, because Vue adds an alias to path. resolve, and the alias configuration is in/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')}
The directory corresponding to the web is '../src/platforms/web', that is, src/platforms/web. Follow this file to continue searching. View the src/platforms/web/entry-runtime-with-compiler.js code, here is mainly to handle some of the exception operation prompts when the Vue instance is mounted to the real dom ,, for example, do not mount a vue instance to a body or html Tag. However, for the transition to be found, these are not important. What is important is
import Vue from './runtime/index'
The Vue object is introduced from the runtime folder of the current directory. Open. /runtime/index. js, first check which modules are introduced, and find that Vue is introduced from src/core/index, and see platformDirectives and platformComponents. The official commands and components are exactly the same.
import Vue from 'core/index'......import platformDirectives from './directives/index'import platformComponents from './components/index'...// install platform runtime directives & componentsextend(Vue.options.directives, platformDirectives)extend(Vue.options.components, platformComponents)// install platform patch functionVue.prototype.__patch__ = inBrowser ? patch : noop
In platformComponents, we found transtion. js, which export an object, including the name, props, and rander methods, and a standard Vue component. So far, the source code is found.
export default { name: 'transition', props: transitionProps, abstract: true, render (h: Function) { ... }}
Transition Implementation Analysis
From the code in the previous section, we can see that direves ves and components are stored in Vue. in options, pay attention to the Vue. prototype. patch, because transtion is not only implemented by a component, but also requires some patches on the Vue constructor.
The parameter h method in rander is the createElement method used by Vue to create virtual DOM. However, no logic is found in this component for processing excessive animations, it mainly processes props and virtual DOM parameters in a centralized manner. Because transtion is not implemented by a single component, it needs to operate the real dom (without inserting the Document Stream) and virtual dom, so it can only make some patches on the Vue constructor.
I looked back at the Code. There was a previous example of Vue. prototype. _ patch _ = inBrowser? Patch: noop. The transition-related implementation is found in patch-related code. Modules/transtion. js
This is the source code position of the patch related to the transition animation effect.
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() } }} : {}
By default, the export object in this module includes three life cycle functions: create, activate, and remove. This should be because Vue has no life cycle function exposed externally, create and activate directly run the above enter method, while remove executes the leave method.
The two most important methods are enter and leave. By hitting a breakpoint on the two methods, we know that before the two methods are executed, vnode has created a real dom and mounted it to vnode. elm. This code is critical.
// El is the real dom node beforeEnterHook & beforeEnterHook (el) if (expectsCSS) {addTransitionClass (el, startClass) addTransitionClass (el, activeClass) nextFrame (() ==>{ addTransitionClass (el, toClass) removeTransitionClass (el, startClass) if (! Cb. canceled &&! UserWantsControl) {if (isValidDuration (explicitEnterDuration) {setTimeout (cb, explicitEnterDuration)} else {whenTransitionEnds (el, type, cb )}}})}
First, startClass and activeClass are added to el. At this time, the dom node is not inserted into the document stream. It is assumed that the node is inserted into the document stream after the create or activate hooks are executed. The nextFrame method is implemented as follows. If requestAnimationFrame does not exist, use setTimeout instead.
const raf = inBrowser && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : setTimeoutexport function nextFrame (fn: Function) { raf(() => { raf(fn) })}
In this way, nextFrame is implemented. As mentioned in the official document, toClass is added to the next frame, startClass is removed, and all transition-related classes are removed after the transition effect ends. So far, the section "Enter transition" is complete.
Let's take a look at the leave method of the 'exit transition 'method and break a breakpoint in the leave method. We can find that the status of the html Tag is as follows:
<p>xxx</p><!---->
<! ----> It is a placeholder for vue. When the element is hidden through v-if, a placeholder is left in the original position. It means that when the leave method is triggered, the original real dom element has been hidden (removed from vnode), and the element being displayed, it is just a copy of The Real dom.
The key code of the leave method is basically the same as that of enter, except that startClass is changed to leaveClass, and there are some animation lifecycle hooks. After the animation ends, the rm method passed in by the component lifecycle remove is called to remove the copy of the dom element from the document stream.
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.