从零单排系列之写一个类vue框架(二)

栏目: 编程语言 · 发布时间: 5年前

内容简介:昨天写了一下节点绑定model的替换,已经如何检测model 的方法今天优化一下,勉强实现一个双向绑定看下昨天的代码

昨天写了一下节点绑定model的替换,已经如何检测model 的方法

今天优化一下,勉强实现一个双向绑定

看下昨天的代码

<script>
    function Vue(obj) {
        var app = document.querySelector(obj.el);
        for(let i in obj.data) {
            this[i] = obj.data[i];
        }
 
        var html = app.childNodes;
        var that = this;
        html.forEach(function(data) {
            if(data.nodeName == '#text') {
                data.data = data.data.replace(/\{\{([\s\S]+)\}\}/g, function(a, b){return that[b]})
            }
        })
    }
</script>
<div id='app'>
    这里是{{title}}
</div>

<script>
    var app = new Vue({
        el: '#app',
        data: {
            title: 'Hello World'
        }
    })
</script>

在实现双向绑定之前,先普及一个set 和 get 的知识。我说点大白话,反正也不是专业的。

一个对象的key在被赋值 value 的时候,被拦截,触发set方法,set的参数就是那个 value

但是这个赋值就会被拦截了,所以需要给一个新的key一个值。然后把value赋值到新的值上面去。 如果强行给之前的key赋值,就会发生无限set 的情况。

稍微加工了一下

<script>
    function Vue(obj) {
        this.app = document.querySelector(obj.el); // 获取函数作用域
        this.data = obj.data; //获取data值
        this.getData(this.data); //设置钩子函数
        this.getWatcher(this.app.childNodes); // 获得包含Model的节点
    }

    Vue.prototype.getData = function(data) {
        for(var i in data) { // 遍历 data 里面的数据
            Object.defineProperty(this, i, { // 在this里面 设置同名key,比如,data里面有title, 那么就去设置一个this.title
                set: function(e) {
                    this.data[i] = e; // 当this.title 被设置 value 的时候,将 this.data.title = value 
                    this.digest(i);  // 更新包含这个model 的 dom
                }.bind(this),
                get: function() {
                    return this.data[i]; // 想获取this.title 的话,就去调取 this.data.title 返回
                }
            })
        }
    }

    Vue.prototype.getWatcher = function(inner) { // 这个代码昨天写过,就是去检测节点中包不包含model
        this.watcher = {};
        var that = this;
         inner.forEach(function(data) {
            if(data.nodeName == '#text') { 
                data.data = data.data.replace(/\{\{([\s\S]+)\}\}/g, function(a, b){
                data.realData = data.data; //自定义一个属性realData,把原始内容保存一下,方便复用 dom.realData = 这里是{{title}}
                 if(!that.watcher[b])
                     that.watcher[b] = [];
                 that.watcher[b].push(data); //把这个节点添加到被监听对象中去 {title:[dom]}
                 return that[b]; // 先把{{title}}替换成 helloworld
             })
            }
        })
    }


    Vue.prototype.digest = function(e) {
        var that = this;
        this.watcher[e].forEach(function(node) {
            node.data = node.realData.replace(/\{\{([\s\S]+)\}\}/g, function(a, b) {return that[b]}); // 把title那个节点改成新的数值
        })
    }
</script>
<div id='app'>
    这里是{{title}}
</div>

<script>
    var app = new Vue({
        el: '#app',
        data: {
            title: 'Hello World'
        }
    })
    setTimeout(function(){app.title = 5;}, 1000)
    setTimeout(function(){app.title = 10;}, 2000)
</script>

代码有些粗劣,但是功能是实现了。

1.首先 先读取 new Vue传入对象时候,data 里面的数据, 然后对其进行遍历,给 实例化对象添加 同名属性, 这个同名属性主要就是用来被监听set,get(双向绑定实现的基本原理)。 也就是 vue.prototype.getData

2.然后呢,去递归dom树(这个以后再写,先简单就一层,不然写的内容会增多很多),然后用正则过滤出里面 {{}}类型的节点,将 这个节点的原始内容(比如{{title}}保存到这个节点的一个自定义属性里,我写的是realData),并将这个节点添加到watcher里面去。 也就是vue.prototype.watcher

3.然后呢,在同名属性被设置的时候呢,就触发钩子函数,将这个同名属性所涉及到的节点的data给更新。 也就是vue.prototype.digest

如果上面的内容没有看的太明白的话,可以参考一下代码注释。。。我下线看看怎么优化代码或者优化思路,晚上或者明天更新。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First Web Design

Head First Web Design

Ethan Watrall、Jeff Siarto / O’Reilly Media, Inc. / 2009-01-02 / USD 49.99

Want to know how to make your pages look beautiful, communicate your message effectively, guide visitors through your website with ease, and get everything approved by the accessibility and usability ......一起来看看 《Head First Web Design》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具