前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >对vue源码的初步认识和理解

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

作者头像
sam dragon
发布2018-01-17 11:27:34
8090
发布2018-01-17 11:27:34
举报
文章被收录于专栏:cnblogscnblogs

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

一、mvvm至少包含的内容

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

二、我的实现

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

代码语言:javascript
复制
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. 指令的定义

代码语言:javascript
复制
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的生成

代码语言:javascript
复制
//转换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

代码语言:javascript
复制
//解析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. 第一次初始化

代码语言:javascript
复制
//调用所有的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

代码语言:javascript
复制
<div id="app">
    <span data-hv="text:title"></span>
    <span data-hv="text:title"></span>
    <input data-hv="model:title" />
</div>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-06-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、mvvm至少包含的内容
  • 二、我的实现
    • 1. 变量的定义与watch的实现
      • 2. 指令的定义
        • 3. vModel的生成
          • 4. 解析dom为vNode
            • 5. 第一次初始化
              • 6. 被解析的dom
              相关产品与服务
              对象存储
              对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档