学习VUE

开课吧VUE体验课笔记


<div id="app">
    <h3>{{title}}</h3>
    <h3>{{state.title}}</h3>
</div>

<script>
    // 接收obj,代理它,使他成为响应式的
    // 替换Object.defineProperty()
    function reactive(obj) {
        // vue3中基于Proxy
        return new Proxy(obj, {
            get(target, key) {
                console.log('get', key)
                // 依赖收集
                track(target, key)

                return target[key]
            },
            set(target, key, val) {
                console.log('set', key)
                target[key] = val
                // update()
                // app.update()
                // 触发依赖
                trigger(target, key)
            },
        })
    }

    // 添加副作用函数
    const effectStack = []  // 临时存储fn
    function effect(fn) {
        // 如果fn中用到了响应式数据,当他们发生变化,fn会再次执行,称为副作用函数
        const eff = function() {
            try {
                effectStack.push(eff)
                fn()
            } finally {
                effectStack.pop()
            }
        }

        // 执行一次,出发依赖收集
        eff()

        return eff
    }

    // 依赖收集函数track
    // {target: {key: [eff]}}
    const targetMap = {}
    function track(target, key) {
        // 获取副作用函数
        const effect = effectStack[effectStack.length - 1]
        if (effect) {
            let map = targetMap[target]
            if (!map) {
                map = targetMap[target] = {}
            }

            let deps = map[key]
            if (!deps) {
                deps = map[key] = []
            }

            // 将副作用函数放入deps
            if (deps.indexOf(effect) === -1) {
                deps.push(effect)
            }
        }
    }

    function trigger(target, key) {
        const map = targetMap[target]
        if (map) {
            const deps = map[key]
            if (deps) {
                deps.forEach(dep => dep())
            }
        }
    }

    function h(tag, props, children) {
        return {tag, props, children}
    }

    // createApp返回应用程序实例是什么样子
    const Vue = {
        createApp(options) {
            // 暴露给浏览器平台
            const renderer = Vue.createRenderer({
                querySelector(selector) {
                    return document.querySelector(selector)
                },
                insert(child, parent, anchor) {
                    parent.insertBefore(child, anchor || null)
                },
                createElement(tag) {
                    return document.createElement(tag)
                }
            })
            return renderer.createApp(options)
        },
        createRenderer({ querySelector, insert, createElement }) {
            // 返回自定义的渲染器
            return {
                createApp(options) {
                    // 返回的就是app实例
                    return {
                        mount(selector) {
                            // mount的目标是什么?
                            const parent = querySelector(selector)
                           
                            // 需要将组件配置解析为dom
                            //通过render函数实现
                            if (!options.render) {
                                options.render = this.compile(parent.innerHTML)
                            }
        
                            // 兼容options api
                            if (options.setup) {
                                // setupState已经是一个代理对象
                                this.setupState = options.setup()
                            } else {
                                this.data = options.data()
                            }
                            
                            // Proxy
                            // 确定render中数据从哪获取
                            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, val) {
                                    if (key in target.setupState) {
                                        target.setupState[key] = val
                                    } else {
                                        target.data[key] = val
                                    }
                                }
                            })

                            // app实例上加了一个更新函数
                            this.update = effect(() => {
                                // const el = options.render.call(this.proxy)

                                // // 追加到宿主元素上去
                                // parent.innerHTML = ''
                                // // parent.appendChild(el)
                                // insert(el, parent)

                                // 获取虚拟dom
                                const vnode = options.render.call(this.proxy)
                                // mounted
                                if (!this.isMounted) {
                                    // mounted
                                    // vnode => dom
                                    const el = this.createElm(vnode)
                                    parent.innerHTML = ''
                                    insert(el, parent)

                                    this.isMounted = true
                                } else {
                                    // update
                                    // diff
                                    this.patch(this._vnode, vnode)
                                }

                                this._vnode = vnode
                            })
                            
                            // 初始化
                            this.update()
                        },
                        createElm(vnode) {
                            // 创建根节点
                            const el = createElement(vnode.tag)
                            // todo props
                            // children
                            if (typeof vnode.children === 'string') {
                                el.textContent = vnode.children
                            } else {
                                // 递归
                                vnode.children.forEach(child => {
                                    insert(this.createElm(child), el)
                                })
                            }
                            vnode.el = el
                            return el
                        },
                        // n1: 老节点
                        // n2: 新节点
                        patch(n1, n2) {
                            const el = n2.el = n1.el
                            // 判断双方是否是相同节点
                            if (n1.tag === n2.tag) {
                                // tots props
                                // children
                                const oldCh = n1.children
                                const newCh = n2.children

                                if (typeof oldCh === 'string') {
                                    if (typeof newCh === 'string') {
                                        // text
                                        if (oldCh !== newCh) {
                                            el.textContent = newCh
                                        }
                                    } else {
                                        // replace text with elements
                                        el.textContent = ''
                                        newCh.forEach(child => insert(this.createElm(child), el))
                                    }
                                } else {
                                    if (typeof newCh === 'string') {
                                        // replace elements with text
                                        el.textContent = newCh
                                    } else {
                                        // children
                                        
                                    }
                                }
                            }
                        },
                        compile(template) {
                            // 没有用到template
                            return function render() {
                                // const h3 = document.createElement('h3')
                                // h3.textContent = this.title
                                // return h3

                                // 返回vnode
                                return h('h3', null, this.title)
                                // return h('h3', null, [
                                //     h('p', null, this.title),
                                // ])
                            }
                        }
                    }
                }
            }
        }
    }
</script>
<script>
    // 1. 函数式
    // 2. 标准化、简化、一致性:render函数,sync修饰符删除,指令定义,v-model调整
    // 3. tree-shaking(摇树优化)
    // 4. 复用性:composition api
    // 5. 性能优化:响应式、编译期优化
    // 6. 扩展性:自定义渲染器
    const { createApp } = Vue
    const app = createApp({
        data() {
            return {
                title: 'hello vue3!'
            }
        },
        setup() {
            // 调函数等等
            // 规避this
            const state = reactive({
                title: 'hello vue3!!!!!!'
            })
            setTimeout(() => {
                state.title = 'vue3, hello!!!!!!'
            }, 2000)
            return state
        },
    })
    // app.component()
    // app.directive('focus', {})
    app.mount('#app')
</script>

版权

本作品采用 CC BY-NC-ND 4.0 授权。