美文网首页Vue.js专区程序员
开始解析 vue 的源码(3) 虚拟 dom

开始解析 vue 的源码(3) 虚拟 dom

作者: zidea | 来源:发表于2019-03-28 17:57 被阅读61次

    先发一个临时版,内容会更新,随后可以引用一个 vdom 库来实现虚拟 dom 功能。


    vuejs.png
    <div id="app-2">
        <span z-bind:title="message">
            Hover your mouse over me for a few seconds
            to see my dynamically bound title!
        </span>
    </div>
    
    var app2 = new Zi({
        el: '#app-2',
        data: {
            message: 'You loaded this page on ' + new Date().toLocaleString()
        }
    })
    

    需要读取标签的 z-bind:title 然后进行操作,然后将属性解析为一个函数 zbind 接收 title, message 和一个 context 做为参数。然后将 message 变量内容进行替换后更新 span 属性 title 为 message 的值。

    上一次我们简单实现如何替换{{}}的占位变量,我们今天继续向下看 vue API,要实现下面的效果,替换掉z-bind:title="message"中 message 内容,想起来很简单,不过弄来弄去还是不太理想,还得弄虚拟dom,整理一下思路

    • 根据 el 指向 dom 生成一颗虚拟dom,简单定义一下结构,
    interface VAttr{
        attrName:string;
        attrVal:string;
    }
    interface VMNode{
        tagName:string;
        attrs?:VAttr[];
        children?:VMNode[];
    }
    
    interface renderVMNode{
        (vMNode:VMNode):HTMLElement
    }
    
    class VMEngine {
        constructor(){
    
        }
    
        generator(dom:HTMLElement):any{
            
        }
    }
    

    写一个生产虚拟dom方法,就是遍历节点生成虚拟 dom 的结构。

    generator(dom:HTMLElement):any{
            let rootVMNode:VMNode = {tagName:"root"};
            if(dom != null){
                rootVMNode.tagName = dom.nodeName;
                if(dom.hasAttributes()){
                    let vAttrs:VAttr[] = [];
                    let attrs = dom.attributes;
                    
                    for(let i = 0; i < attrs.length; i++){
                        
                        let attrName:string  = attrs[i].name;
                        let attrVal:string |null = dom.getAttribute(attrName);
                        let vAttr:VAttr = {
                            attrName:"",
                            attrVal:""
                        };
                        vAttr.attrName = attrName;
                        
                        if(attrVal == null){
                            vAttr.attrVal = "";
                        }else{
                            vAttr.attrVal = attrVal
                        }
    
                        vAttrs[i] = vAttr
                        
                    }
                    rootVMNode.attrs = vAttrs;
                }
    
                if(dom.hasChildNodes()){
                    let childhtmlDoms = dom.childNodes;
                    rootVMNode.children = [];
                    if(childhtmlDoms.length > 0){
                        for(let i = 0; i < childhtmlDoms.length; i++){
                            let childDom:HTMLElement | null = <HTMLElement>childhtmlDoms[i];
                            if( childDom instanceof HTMLElement){
                                let childVMNode:VMNode = this.generator(childDom)
                                if(childVMNode != null){
                                    rootVMNode.children[i] = childVMNode; 
                                }
                            }
                        }
                    }
                }
            }
            return rootVMNode;
        }
    

    为了规范我们看给函数定义类型,通过 interface 对函数进行限制的接口,我们处理 dom 元素上自定义标签

    然后用 context 中内容替换掉 虚拟dom 节点中属性值为 context 的对应值。

    walkVMNode(node:VMNode,context:Dictionary<string>):VMNode{
            console.log("====================== warlking ===============================")
            if(node != null){
                console.log("v node name = " + node.tagName);
                if(node.attrs != undefined){
                    for( let attr of node.attrs){
                        console.log("====================== arrt warlking ===============================")
                        
                        if()
    
                        var obj:Dictionary<string> = context;
                        Object.keys(obj)
                            .forEach(function(item){
                                console.log(item);
                                if(attr.attrVal == item){
                                    attr.attrVal = obj[item]
                                }
                            })
                       console.log(attr);
                       
                        console.log("====================== attr warlking ===============================")
    
    
                    }
                }
                
                if(node.children != undefined && node.children.length  > 0){
                    for(let child of node.children){
                        this.walkVMNode(child,context);
                    }
                }
            }
    
            return node;
            console.log("====================== warlking ===============================")
        }
    
    

    通过遍历 Dom 找出我们自定义属性,v-(.)* ,然后在处理及进行一些操作

     if(/^z-(.)+/.test(attr.attrName) ){
        attr.attrName = attr.attrName.split(":")[1];
    }
    

    随后得加强一下,

    • 正则表达式

    • 函数式编程

    • 递归


      typescript.jpg
    • typescript


      Vtrual-Healing-In-Line.jpg

    相关文章

      网友评论

        本文标题:开始解析 vue 的源码(3) 虚拟 dom

        本文链接:https://www.haomeiwen.com/subject/njrcbqtx.html