美文网首页
通过数据劫持实现mvvm框架

通过数据劫持实现mvvm框架

作者: 鱼竿23333 | 来源:发表于2019-05-10 14:46 被阅读0次

记录公开课内容:

实现步骤
​ 1.vue中最简单表达式使用

​ 2.我们如何实现渲染表达式里的数据

​ 3.修改数据后如何更新视图

​ 4.如何劫持数据监听数据改变

​ 5.通过发布订阅模式通知数据更新

​ 6.多层数据如何渲染

​ 7.v-model的初次渲染

​ 8.精简代码实现双绑

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="kvue.js" type="text/javascript"></script>
    <title>Document</title>
</head>

<body>
    <div id="app">
        {{ message }}
        <p>{{message}}</p>
        <input type="text" k-model="name" /> {{name}}
    </div>
</body>
<script>
let vm = new Kvue({
    el:"#app",
    data:{
        message:"测试数据",
        name:"张三",
    }
})
vm._data.message = "测试数据";
vm._data.name = "李四";
// vm.message
// vm.options
console.log(vm._data);

</script>

</html>

Kvue.js

class Kvue {
    constructor(options) {
        this.$options = options;
        this._data = options.data;
        //劫持数据;
        this.observer(this._data);
        this.compile(options.el);
    }
    observer(data) {
        Object.keys(data).forEach(key => {
            let value = data[key];
            let dep = new Dep();
            Object.defineProperty(data, key, {
                configurable: true,
                enumerable: true,
                get() {
                    if (Dep.target) {
                        dep.addSub(Dep.target);
                    }
                    return value;
                },
                set(newValue) {
                    console.log("set", newValue);
                    if (newValue !== value)
                        value = newValue;
                    dep.notify(newValue);
                }
            })
        })

    }
    compile(el) {
        let element = document.querySelector(el);
        this.compileNode(element);
    }
    compileNode(element) {
        let childNodes = element.childNodes;
        // console.log(childNodes);
        Array.from(childNodes).forEach(node => {
            if (node.nodeType == 3) {
                //文本
                // console.log(node);
                let nodeContent = node.textContent;
                // console.log(nodeContent);
                let reg = /\{\{\s*(\S*)\s*\}\}/;
                if (reg.test(nodeContent)) {
                    // console.log("("+RegExp.$1+")");
                    node.textContent = this._data[RegExp.$1];
                    new Watcher(this, RegExp.$1, newValue => {
                        node.textContent = newValue;
                    });
                }
            } else if (node.nodeType == 1) {
                //标签
                let attrs = node.attributes;
                // console.log(attrs);
                Array.from(attrs).forEach(attr => {
                    // console.log(attr);
                    let attrName = attr.name;
                    let attrValue = attr.value;
                    // console.log(attrName);
                    if (attrName.indexOf("k-") == 0) {
                        attrName = attrName.substr(2);
                        console.log(attrName);
                        if (attrName == "model") {
                            node.value = this._data[attrValue];
                        }
                        node.addEventListener("input", e => {
                            // console.log(e.target.value);
                            this._data[attrValue] = e.target.value;
                        })
                        new Watcher(this, attrValue, newValue => {
                            node.value = newValue;
                        });
                    }
                })
            }
            if (node.childNodes.length > 0) {
                this.compileNode(node);
            }
        })
    }
}



class Dep {
    constructor() {
        this.subs = [];
    }
    addSub(sub) {
        this.subs.push(sub);
    }
    notify(newValue) {
        this.subs.forEach(v => {
            v.update(newValue);
        })
    }
}

class Watcher {
    constructor(vm, exp, cb) {
        Dep.target = this;
        vm._data[exp];
        this.cb = cb;
        Dep.target = null
    }
    update(newValue) {
        console.log("更新了", newValue);
        this.cb(newValue);
    }
}

constructor
constructor是一种用于创建和初始化[class]创建的对象的特殊方法。
在一个类中只能有一个名为 “constructor” 的特殊方法。
一个类中出现多次构造函数 (constructor)方法将会抛出一个 [SyntaxError]对象代表尝试解析语法上不合法的代码的错误。

相关文章

  • 通过数据劫持实现mvvm框架

    记录公开课内容: 实现步骤​ 1.vue中最简单表达式使用 ​ 2.我们如何实现渲染表达式里的数据 ​ ...

  • vue-框架mvvm学习

    通过数据劫持实现vue(mvvm)框架 vue中最简单的表达式的使用如何实现渲染表达式里面的数据修改数据后如何更新...

  • Vue MVVM 原理实现

    核心原理 MVVM 双向数据绑定, 数据驱动视图 Vue 实现 MVVM 采用 数据劫持 + 发布订阅模式 : ...

  • 从 0.5 开始造轮子 仿 vue 的 mvvm(二)

    替换数据劫持对象   上一篇实现了 mvvm 实现思路,可是不够优雅还有很多问题,我先解决这个问题数据劫持的问题。...

  • MVVM 和 MVC 渲染过程

    MVVM: 数据初始化时,为每个属性添加 Observer 劫持监听,通过Object.difinePropert...

  • 24,vue、vuex

    一,谈谈MVVM原理数据劫持 + 发布-订阅者。Object.defineProperty( )劫持getter和...

  • vue数据绑定原理

    实现原理:vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的.1)数据劫持、vue是通过Obje...

  • Vue源码03-响应式原理

    这节将专门讲解vue MVVM响应式处理 Vue采用的是 实现数据的响应式 数据劫持 Observer类 Obse...

  • 个人手写的MVVM

    1.MVVM(入口函数) 为vm添加数据代理 调用其他函数(数据劫持,模版编译) 2.observer(数据劫持)...

  • 2020-07-03 vue双绑原理

    mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来...

网友评论

      本文标题:通过数据劫持实现mvvm框架

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