初試Vue3-手動實現render掛載


初試Vue3-手動實現render掛載
只實現了最簡單的render新增節點掛載到指定dom上,數據響應式沒實現,一點一點的研究吧

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
    <script>
        // const {createApp} = Vue;
        const createAppAPI = (render) => {
            return function createApp(rootComponent) {
                // 返回真正的應用程序實例,執行mount方法
                const app = {

                    // 將傳入的容器選擇器 把vnode轉變成dom 並掛載到容器
                    mount(rootContainer) {
                        // rootContainer 就是#app
                        // rootComponent 是傳進來的 {data(){return{}},render(){tag:"h2",children:this.foo}}
                        // v3里面虛擬dom的變化
                        const vnode = {
                            tag: rootComponent
                        }

                        // 這一步非常重要哦,執行渲染
                        render(vnode, rootContainer)
                    }
                }


                return app
            }
        }

        // 2.實現renderer工廠函數
        const createRenderer = options => {
            const patch = (n1, n2, container) => {
                /**
                 * n1 舊的虛擬節點
                 * n2 新的虛擬節點 根組件的配置在這里
                 * container 容器掛載
                 * */

                const rootComponent = n2.tag; //為啥是n2.tag 可以往上找,createAppAPI里面定義的,當然也可以不叫tag

                // 數據的上下文,要指向data的執行結果
                const ctx = {...rootComponent.data()
                    }
                    /*
                     *ctx 的值是{foot:'hellov3'}
                     **/

                // 執行render獲取vnode
                const vnode = rootComponent.render.call(ctx);
                /**
                    執行實例里面render方法,拿到data里面的數據
                **/

                // 轉換vnode dom 拿到要掛載的節點dom
                const parent = options.querySelector(container);

                // render里要添加的tagname,創建新節點
                const child = options.createElement(vnode.tag);

                //這里只判斷了最簡單的情況,其他類型還得再去源碼中好好看
                if (typeof vnode.children === 'string') {
                    child.textContent = vnode.children;
                    // textContent 文本內容
                }
                // 最后一步將虛擬dom轉完的真實dom掛載到指定元素上
                options.insert(child, parent)
            }
            const render = (vnode, container) => {
                // 把虛擬dom變成真實dom並添加到container里

                // 判斷container上有沒有虛擬dom
                patch(container._vode || null, vnode, container);

                container._vode = vnode;
            }

            // 該對象就是renderer
            return {
                render,
                createApp: createAppAPI(render)
            }
        }


        // 1.createApp  runtimedom->index.js createApp ensureRender  createRenderer
        const Vue = {
            createApp(options) {
                // 執行的實際是renderer.createApp()
                return renderer.createApp(options)
            }
        }
        const renderer = createRenderer({
            querySelector(sel) {
                return document.querySelector(sel)
            },
            createElement(tag) {
                return document.createElement(tag)
            },
            insert(child, parent) {
                parent.appendChild(child)
            }
        })
        const {
            createApp
        } = Vue;
        createApp({
            data() {
                return {
                    foo: "hello,vue3!"
                }
            },
            render() {
                return {
                    tag: "h2",
                    children: this.foo
                }
            }
        }).mount('#app');
    </script>
</body>

</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM