preface
XDM, hello, everyone, I am Panda Little brother, a relatively Buddha program ape, shame to say, Vue3 has been released for about a year, I just learn Vue3, recently through reading Vue3 source code simply write about Vue3 how to initialize, how to achieve responsive, how to update and diff virtual DOM, share personal shallow cognition, If you write badly, please spray lightly.
implementation
Initialize (mount)
const Vue = { // Multi-platform compatibility only requires the features of the passed platform createRenderer({ querySelector }) { return { Create createApp, which returns an instance of Vue createApp(options) { // 2. Return to mount return { // The mount method converts the data state to a DOM and appends it to the host element mount(selector) { // 1. Get the host element const parent = querySelector(selector) // 1.1 Save setup and data instances if (options.setup) { this.setupState = options.setup() } if (options.data) { this.data = options.data() } // 1.2 Determine the priority of setup and data by proxy method this.proxy = new Proxy(this, { get(target, key) { if (key in target.setupState) { return target.setupState[key] } else { return target.data[key] } }, set(target, key, value) { if (key in target.setupState) { target.setupState[key] = value } else { target.data[key] = value } }, }) / / 2. The rendering // compile template > render, if the user writes render, the template will be compiled internally if(! options.render) { options.render =this.compile(parent.innerHTML) } this.update = effect(() = > { const el = options.render.call(this.proxy) // 3. Empty and mount parent.innerHTML = ' ' parent.appendChild(el) }) this.update() }, // The simple compiler method low compile(template) { return function render() { const h3 = document.createElement('h3') h3.textContent = this.title1 return h3 } }, } }, } }, createApp(options) { const renderer = this.createRenderer({ querySelector(selector) { return document.querySelector(selector) }, }) return renderer.createApp(options) }, } Copy the code
The reactive update for Vue3.0 takes a different approach, using side effect dependency
new Proxy
Perform data proxy, collect dependencies and place them in the queue of side effects when getting the value, and update the side effects corresponding to the value when setting the value in the queue of side effects, so that accurate update can be achieved.Reactive
/ / implementation reactive function reactive(obj) { return new Proxy(obj, { get(target, key) { const res = Reflect.get(target, key) return res }, set(target, key, value) { const res = Reflect.set(target, key, value) return res }, }) } Copy the code
update
1. Implement side effects
// Implement side effects const effectStack = [] function effect(fn) { const eff = function () { try { effectStack.push(fn) fn() } finally { effectStack.pop() } } eff() return eff } Copy the code
2. Collect dependencies
/ / implementation reactive function reactive(obj) { return new Proxy(obj, { get(target, key) { const res = Reflect.get(target, key) // Rely on collection track(target, key) return res }, set(target, key, value) { const res = Reflect.set(target, key, value) // Notification update trigger(target, key) return res }, }) } Copy the code
3. Make connections
// Collect dependent data structures // targetMap : { // target : { // deps: [eff, eff1, eff2] / /} // } const targetMap = new WeakMap(a)// Collect dependencies function track(target, key) { // 1. Take the last side effect const effect = effectStack[effectStack.length - 1] if (effect) { // 2. Get target and check whether it exists. If not, create target let depMap = targetMap.get(target) if(! depMap) { depMap =new Map() targetMap.set(target, depMap) } // 3. Get the deps and check if it exists let deps = depMap.get(key) if(! deps) { deps =new Set() depMap.set(key, deps) } // 4. Add side effects deps.add(effect) } } Copy the code
4. Notification updates
// Find the corresponding side effect and execute it function trigger(target, key) { // 1. Obtain the dependent Map const depMap = targetMap.get(target) if(! depMap)return const deps = depMap.get(key) if (deps) { deps.forEach((dep) = > dep()) } } Copy the code
5. diff
this.update = effect(() = > { // const el = options.render.call(this.proxy) // // 3. Clear and mount the vm // parent.innerHTML = '' // parent.appendChild(el) // Get the virtual node const vnode = options.render.call(this.proxy) // this.isMounted Determines whether the initialization or update phase is in progress if (!this.isMounted) { // Initialize fetch element empty please mount const el = this.createElm(vnode) parent.innerHTML = ' ' insert(el, parent) this.isMounted = true } else { / / update this.patch(this._vnode, vnode) } this._vnode = vnode }) // diff patch(n1, n2) { // Get the node const el = (n2.el = n1.el) // n1 old node // n2 new node // Only the same nodes are compared if (n1.tag === n2.tag) { const oldCh = n1.children const newCh = n2.children /** * The old node is a string, and the new node has children. The children of the new node are inserted into the corresponding node. * the old node has children, and the new node has children. The old node is a string, compare the new and old nodes are different in the update */ if (typeof oldCh === 'string') { if (typeof newCh === 'string') { if(oldCh ! == newCh) { el.textContent = newCh } }else { el.innerHTML = ' ' insert(this.createElm(newCh), el) } } else { if (typeof newCh === 'string') { el.textContent = newCh } else { // Update the child operation -- first compare the header, then at the end of the comparison, if none is found, traverse all byte points using the longest increasing subsequence quicksort this.updatedChildren(oldCh, newCh) } } } } Copy the code
conclusion
XDM simply realizes the basic functions of Vue3, Vue3 is more than these contents, Vue3 also designed algorithm thinking, compilation principle and many other knowledge. Moreover, Vue3 has also made a lot of optimization in static node improvement, cache black, PatchFlag judgment and compatible Vue2. X version. We’ll share it later.
Finally, if the article is useful to you, please help to like, follow + comment.