• 对vue源码的初步认识和理解


          根据vue的官网介绍,可以得知vue是一个mvvm框架,且是响应式的。为了更深入了理解其内涵,本人以及理解实现了一个简单的mvvm学习的demo。下面分享给大家,欢迎大家一起讨论。

    一、mvvm至少包含的内容

    1. 指令集合,如:text、model等
    2. 数据模型,与视图交互的数据
    3. 组件的支持:也就是部分html代码的动态更新

    二、我的实现

    1. 变量的定义与watch的实现

    var directives = {}; //指令集合
    var vNodes = new Array(); //解析的Dom集合
    
    var dataModel = {
        name:"name",
        title: "title"
    }; //数据Model
    
    var Watch = {
        isInit: false,
        watchs: new Array(),
        run: function(newValue, expOrfn){ 
            var self = this;
            if(!self.isInit){
                expOrfn.call(vModel);
            }
            this.watchs.map(function(data,index){
                data.nodes.map(function(d,i){
                    if(self.isInit){
                        d.directive.init(newValue, d, data); //绑定初始化值, 以及初始化一些事件
                    }else{
                        d.directive.update(newValue, d, data); //只更新值,此时run的调用来值value-set
                    }
                });
            });
            
            self.watchs = [];
        },
        push:function(watch){
            this.watchs.push(watch);
        }
    } //任务管理

    说明:

    1. Watch的push方法,用于依赖的添加,然后run来执行所以依赖,执行完成后,需要清理当前依赖的集合。在vue中依赖的收集是在dep中完成的,而watch提供的任务管理(不知道理解是否正确)

    2. 指令的定义

    directives.text = { 
        init: function(value, vNode){
            vNode.elm.textContent = value;
        },
        update: function(value, vNode){
            vNode.elm.textContent = value;
        }
    }
    //需要响应事件的怎么办
    directives.model ={ 
        init: function(value, vNode, _watch){
            vNode.elm.value = value; //判断自己发生的改变,不应该再改变自己 
            vNode.elm.addEventListener('keyup',function(evt){
                vNode.model[_watch.key] = vNode.elm.value;
            }); 
        },
        update:function(){
    
        }   
    }

    说明:

    1. 由于是demo学习示例,所以只定义了简单的text和model两个指定,text:用于数据的显示,而model用于input(输入框)的响应

    3. vModel的生成

    //转换vModel,暂支持一级
    var properties = Object.getOwnPropertyNames(dataModel);
    var vModel = {}, formSetting = false;
    for( var index in properties){ 
        (function refreshData(_index){
            var key = properties[_index];
            var property = Object.getOwnPropertyDescriptor(dataModel, key);
            var setter = property.set;
            var getter = property.get;
            var _val = property.value;
            var _getter = function(){
                var val = getter ? getter.call(vModel) : _val;
                //收集依赖,与watch要分开
                Watch.push({
                    key: key,
                    nodes: vNodes.filter(function(data,index){
                        return data.modelKey == key ? true : false;
                    }),
                    getter: _getter
                });
                return val;
            };
            Object.defineProperty(vModel, key, {
                configurable: true,
                enumerable: true,
                set: function(value){
                    if(setter){
                        setter.call(vModel, value);
                    } 
                    //处理依赖
                    Watch.run(value, _getter);
                    //this.value = value;
                },
                get: _getter
    
            })
        })(index);
    }

    说明:

    1. vModel是根据dataModel生成的,也就是自定义了每个属性的get和set方法,在es6中也可以用proxy实现(是否说对了)。
    2. 在属性set的时候,会先调用get方法来收集依赖。方便值改变后,能将所影响的内容都修改掉。

    4. 解析dom为vNode

    //解析vNodes
    var app = document.getElementById('app');
    app.childNodes.forEach(function(data,index){
        if(data.nodeType != 1) return;
        var hv = data.getAttribute('data-hv');
        var hvs = hv.split(',');
        hvs.forEach(function(item,row){
            var keyValue = item.split(':'); //vNode对象上一定要有model,这是方便vNode相应时候的找vModel
            vNodes.push({
                directive: directives[keyValue[0]],
                modelKey: keyValue[1],
                model: vModel,
                elm: data
            });
        });
    });

    说明:

    1. 这里说解析为vNode很是牵强,因为此只是收集了dom上data-hv指定的指令,并将对就的指令、元素、vModel等组成一个对象存储在vNodes中,以供vModel各属性的get方法收集依赖时引用。

    5. 第一次初始化

    //调用所有的get一次
    Watch.isInit = true;
    var _keys = Object.getOwnPropertyNames(vModel);
    _keys.map(function(key,data){
        var data = vModel[key];
        Watch.run(data); 
    });
    Watch.isInit = false;

    说明:

    1. 将初始化的vModel的值渲染到Dom上,这里是主动执行每个的get,然后运行watch.run方法。
    2. 此处设计和实现本人感觉与vue的思路不对,如有高人看见,麻烦提点与指引。

    6. 被解析的dom

    <div id="app">
        <span data-hv="text:title"></span>
        <span data-hv="text:title"></span>
        <input data-hv="model:title" />
    </div>
  • 相关阅读:
    inet_ntoa解析
    日语常用计算机词汇
    Visual Studio 2012 : error LNK2026: module unsafe for SAFESEH image
    android异常总结四 :Unexpected text found in layout file: """
    android异常总结三 :R文件丢失
    android异常总结二 :This text field does not specify an inputType or a hint
    android异常总结一 :reslayoutOtherActivity.xml: Invalid file name: must contain only [a-z0-9_.]
    Win8下配置java环境
    CUDA实例练习(五):两数相加
    CUDA实例练习(四):矩阵转置
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/7006923.html
Copyright © 2020-2023  润新知