• 浅析Vue原理(部分源码解析)


    响应式

    Object.defineProperty

    Object.defineProperty(obj, prop, descriptor)  // 对象、属性、描述符
    

      Object.defineProperty是es5新加的给对象属性设置描述符的方法,可以用来监听属性值的变化

     var obj ={};
        var _name ='张三'
        Object.defineProperty(obj,'name',{
            get:function () {
                return _name;
            },
            set:function (value) {
                _name=value;
            }
        })
    

      调用方式:

    obj.name ="里斯";
    alert(obj.name);
    

    模拟Vue响应式(data的属性代理到vm上)

     var vm= {};
        var data= {
            items: [
                { message: 'Foo' },
                { message: 'Bar' }
            ]
        };
        var i;
        for (i in data){
            if(data.hasOwnProperty(i)){
                (function(i){ // 独立函数作用域
                    Object.defineProperty(vm,i,{ //将data对象的属性代理到vm
                        get: function () {
                            return data[i];
                        },
                        set:function (newVal) {
                            data[i]=newVal;
                        }
                    })
                }(i))
            }
        }
        vm.items[0].message='张三'
        console.log(vm.items); 

    模板解析

    1. 本质:字符串
    2. 有逻辑: 例如v-if、v-for 等
    3. html模版是静态的,Vue模板是动态
    4. 模板必须转换成JS函数(render函数),进而转换成html渲染页面

    with

      //模板
        function UserInfo() {
            this.name = "kobe bryant";
            this.age = "28";
            this.gender = "boy";
        }
        var people=new UserInfo();
        function fn(){
            with(people)
            {
                var str = "姓名: " + name + "
    ";
                str += "年龄:" + age + "
    ";
                str += "性别:" + gender;
                alert(str);
            }
        }
        fn();
    

    render 函数

    <div class="main" :class="bindClass">
        <div>{{text}}</div>
        <div>hello world</div>
        <div v-for="(item, index) in arr">
            <p>{{item.name}}</p>
            <p>{{item.value}}</p>
            <p>{{index}}</p>
            <p>---</p>
        </div>
        <div v-if="text">
            {{text}}
        </div>
        <div v-else></div>
    </div>
    

    Vue 源码将HTML string 转换成AST

    模版转换成js

    with(this){
        return _c(  'div',
                    {
                        /*static class*/
                        staticClass:"main",
                        /*bind class*/
                        class:bindClass
                    },
                    [
                        _c( 'div', [_v(_s(text))]),
                        _c('div',[_v("hello world")]),
                        /*这是一个v-for循环*/
                        _l(
                            (arr),
                            function(item,index){
                                return _c(  'div', //_c创建标签
                                            [_c('p',[_v(_s(item.name))]), //_v 创建文本; _s 转换成字符串
                                            _c('p',[_v(_s(item.value))]),
                                            _c('p',[_v(_s(index))]),
                                            _c('p',[_v("---")])]
                                        )
                            }
                        ),
                        /*这是v-if*/
                        (text)?_c('div',[_v(_s(text))]):_c('div',[_v("no text")])],
                        2
                )
    }

    其中,this 即使Vue构造函数对象(假定为vm),item即this.item,也是data中的item  

    针对于上一篇的随笔:浅谈Jquery和常用框架Vue变化,我们来解析一下它的render模板

    <div id="example-1">
        <input v-model="title" />
        <button v-on:click="add">udto list</button>
        <ul>
            <li v-for="item in items">
                {{ item.message }}
            </li>
        </ul>
    </div>
    

      模板render解析

    with (this) {
        // noinspection JSAnnotator
        return _c('div', {attrs: {"id": "example-1"}}, [ //div
            _c('input', { //input
                directives: [{
                    name: "model",
                    rawName: "v-model",
                    value: (title),
                    expression: "title"
                }],
                domProps: {"value": (title)}, //model 往 view
                on: {
                    "input": function ($event) {
                        if ($event.target.composing) return;
                        title = $event.target.value //view 往 model
                    }
                }
            }), _v(" "), //换行
            _c('button',
                {
                    on: {
                        "click": add //绑定 methods add
                    }
                },
                [
                    _v("udto list") //文本子节点
                ]
            ), _v(" "), //换行
            _c('ul', 
                _l((items), function (item) {  // <li v-for="item in items"> _l v-for
                return _c('li',
                    [
                        _v("
                " + _s(item.message) + "
            ") //item 对应 vm.item 即 data中的item
                    ]
                )
            }))
        ])
    }
    

    渲染

    从上面例子可以看出,vue通过借鉴改造snabbdom,h函数返回的vNode,vm._c返回的也是vNode,从Vue源码中也验证了这一点,从下面Vue源码看出Vue是通过updateComponent 完成render渲染

      

    var prevVnode = vm._vnode; //旧的vnode,initial render 第一次渲染 vnode 没有存在,装载在容器中,全部渲染
    // updates
    vm.$el = vm.__patch__(prevVnode, vnode); //第二次 新旧vNode对比

    Vue 整个工作流程

    1.  将模板解析成Js,即render函数
    2.    监听模板,通过MVVM响应式绑定model,并完成监听
    3.    render函数渲染成Virtual Node
    4.    初次渲染完成DOM节点的创建,再次渲染新旧Vittual Node对比

    源码地址

    https://github.com/10086XIAOZHANG/VirtualDOMDemo  

  • 相关阅读:
    2014 年最热门的国人开发开源软件TOP 100
    欢迎访问李培冠博客
    Go语言学习之路(持续更新)
    租房项目 获取地区信息服务
    租房项目 启动前的处理
    一步步带你用 FastDFS 搭建文件管理系统 详细的不得鸟
    golang 两个go程轮流打印一个切片
    golang 拷贝大切片一定比小切片代价大吗
    matlab 如何把数组A中与数组B中元素相同的元素删除
    golang 如何翻转含有中文 数字 英文字母等任意字符串
  • 原文地址:https://www.cnblogs.com/fuGuy/p/9222249.html
Copyright © 2020-2023  润新知