美文网首页程序员
开始解析 vue 的源码(2) 单向绑定

开始解析 vue 的源码(2) 单向绑定

作者: zidea | 来源:发表于2019-03-27 19:41 被阅读11次
    engineering-pictures-12.jpg

    年初就有一个 idea 准备弄弄自己 javascript 框架,参考 vue 来做,Evan 也在开发者大会介绍 vue3.0 时候提到在新版 vue 中源码使用 typescript 编写,按模块划分,更适合开发者阅读源码。

    先不源码自己根据 Evan 的思路先自己弄一弄,然后在看源码,这样留给自己思考的空间。先看 vue

    目标: 进行不使用第三方库,不排除会使用 rxjs redux

    搭建简单环境,创建一个项目目录```npm init -init``

    在项目下
    创建 src 用于存放源码
    创建 examples 来测试框架小 demo
    准备用 typescript 来写,所以初始化,为什么用 Typescript 呢?不是为了方便,是这样大型项目必须要的用一个类型系统呀,开始想用 ocaml 写了,ocaml 还不算熟,随着可以写一个 ocaml 的版本。暂时先用 typescript 弄。

    tsc --init
    

    index.html 文件,我们目的就是用变量的值将占位符内容替换调达到单向绑定。看似简单。


    start.JPG
    <div id="app">
        {{ message }}
    </div>
    <script src="./dist/zi.js"></script>
    <script src="./app.js"></script>
    
    • zi.js 是编译后 zi 文件
    • app.js 开发应用文件
      我们一步一步地实现 vue 的功能,就是将 data 变量更新到html
    new Zi({
        el: '#app',
        data: {
            message: 'Hello Zi.js!'
        }
    })
    

    先配置 tsconfig 文件,配置 typescript 如何编译为 javascript
    tsconfig

    {
      "include": [
        "src/**/*"
      ],
      "exclude": [
        "node_modules",
        "**/*.spec.ts"
      ], 
      "compilerOptions": {
        "target": "es5", 
        "lib": ["es2015","dom"], 
        "module": "commonjs",
        "allowJs": true,
        "outDir": "./examples/dist/",
        "strict": true,
        "esModuleInterop": true,
        "experimentalDecorators": true, 
      }
    }
    
    app.js:1 Uncaught ReferenceError: Zi is not defined
        at app.js:1
    

    我们先解决 Zi 没定义问题,那么就创建一个 Zi 的类。

    class Zi{
        
    }
    

    这里是传入一个 option 对象参数(context),我们用 tyepscript 定义一个 Option 的类型

    new Zi({
        el: '#app',
        data: {
            message: 'Hello Zi.js!'
        }
    })
    
    interface Options {
        el:string,
        data:object
    }
    class Zi{
        constructor(opt:Options){
            console.log(opt)
        }
    }
    
    • el: 是选择器,确定应用作用的 dom 的范围
    • data: 是数据,需要 data 数据渲染上去

    如何将数据绑定到视图上,data binding,

    • el 属性读取该节点下 html 结构,然后生产一个虚拟节点树(vdom),这地方是重点,可以考虑先引进 handler 或者其他 vdom 的库
      1. 读取 html String template 返回一个方法,这里用的函数式编程 curry
    • 获取vmode 中数据绑定位置,然后将节点与vmode 对应上
    • 监控数据的属性,属性发生变化更新vmode对应节点进行局部渲染
    export default class ZiHtml{
        constructor(){
    
        }
        compile(){
            console.log(111)
        }
    }
    

    compile 方法需要返回一个函数```function(context)

    export default class ZiHtml{
        constructor(){
    
        }
        compile(htmlStr:string){
            console.log(111)
            return function(context:Object){
                //log
                let parser = new DOMParser()
                rootDom:HTMLDocument = parser.parseFromString(htmlStr, "text/xml");
                console.log(rootDom)
            }
        }
    }
    
    "module": "es2015", 
    
    class ZiHtml{
        parser:DOMParser
        constructor(){
            this.parser = new DOMParser();
        }
         compile(htmlStr:string){
             var self = this;
            return function(context:Object){
                console.log(htmlStr);
                var doc = self.parser.parseFromString(htmlStr, "application/xml");
                console.log(doc)
            }
        }
    }
    
    // import ZiHtml from './ZiHtml';
    class ZiHtml{
        parser:DOMParser
        constructor(){
            this.parser = new DOMParser();
        }
         compile(htmlStr:string,id:string){
             var self = this;
            return function(context: Dictionary<String>){
                console.log(htmlStr);
                var doc:HTMLDocument = self.parser.parseFromString(htmlStr, "application/xml");
                
                let str:string = doc.documentElement.innerHTML.trim();
                let replaceStr:string = "";
    
                Object.keys(context)
                    .map(function(item){
                        console.log(context[item])
                        replaceStr = str.replace(item ,context[item]+"");
                })
                replaceStr = replaceStr.replace(/\{|\}/g,"");
                console.log("html string",replaceStr);
                doc.documentElement.innerHTML = replaceStr;
                let TargetDom:HTMLElement | null = document.querySelector(id);
                if(TargetDom != null){
                    TargetDom.innerHTML = replaceStr;
                }
            }
        }
    }
    interface Dictionary<T>{
        [key: string]: T;
    }
    
    interface Binder {
        name:string,
        handler:Function
    }
    
    interface Options {
        el:string,
        data:Dictionary<string>
    }
    class Zi{
        html:ZiHtml;
        template:any;
        constructor(opt:Options){
            
            this.html = new ZiHtml()
            this.init(opt)
        }
    
        init(opt:Options){
            console.log(opt.el)
    
            let htmlDom:HTMLElement = <HTMLElement>document.querySelector(opt.el);
            let htmlStr:string = htmlDom.outerHTML;
            this.template = this.html.compile(htmlStr,opt.el);
            
            var obj:Dictionary<string> = opt.data;
            this.template(obj)
            Object.keys(obj)
                .map(function(item){
                    console.log(obj[item])
                
            })
    
            
        }
    }
    
    
    result.JPG

    扩展一下依旧有效,不错虽然粗糙但是方向应该是对的

     <div id="app">
            {{ message }}{{name}}
        </div>
    
    new Zi({
        el: '#app',
        data: {
            message: 'Hello Zi.js!',
            name:"zidea"
        }
    });
    
    test.JPG

    相关文章

      网友评论

        本文标题:开始解析 vue 的源码(2) 单向绑定

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