博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Vue双向绑定实现
阅读量:5873 次
发布时间:2019-06-19

本文共 3258 字,大约阅读时间需要 10 分钟。

参考文章

效果

整体步骤

  1. 首先是在Vue的构造函数中对data中的数据响应化(使用的是defineProperty)
  2. 然后对html中相关指令和{
    {变量}}形式代码编译(compile), 因为这些变量与Vue.data里的数据有关,需要绑定在一起。
  3. 绑定过程是每一个与Vue.data中数据相关的节点,都会创建Watcher对象,然后这个代表节点的Watcher会被收集到数据自己的dep中,当这个数据变化时,会遍历dep中的Watcher。
  4. 数据变化的通知过程,使用defineProperty实现,通过劫持set操作,在其中通知Watcher,通过劫持get操作,来收集依赖。

代码地址

主要代码

复制保存为vmodel.js

// vm == view modelclass Dep{    constructor(){        this.subscribers = [];     }    addSubscriber(sub) {        this.subscribers.push(sub);    }    notify() {        this.subscribers.forEach((sub) => {            sub.update();        });    }}class Watcher {    constructor(vm, node, name, nodeType) {        Dep.target = this;        this.vm = vm;        this.node = node;        this.name = name;        this.nodeType = nodeType;        this.update();        Dep.target = null;    }    update() {        this.get();        if (this.nodeType == 'text') {            this.node.data = this.value;        }        if (this.nodeType == 'input') {            this.node.value = this.value;        }    }    get() {        this.value = this.vm.data[this.name];    }}class Vue{    constructor(options) {        this.data = options.data;        toObserve(this.data);        let root = document.querySelector(options.el);        var newChild = nodeToFragment(root, this);        root.appendChild(newChild);    }}function toReactive(key, value, obj) {    let dep = new Dep();    Object.defineProperty(obj, key, {        get() {            if (Dep.target) {                dep.addSubscriber(Dep.target);            }            return value;        },        set(newValue) {            if (newValue == value) {                return;            }            value = newValue;            dep.notify();        }    });}function toObserve(obj) {    Object.keys(obj).forEach((key) => {        toReactive(key, obj[key], obj);    });}function nodeToFragment(node, vm) {    let flag = document.createDocumentFragment();    let child = node.firstChild;    while (child) { // 遍历child        compile(child, vm);        flag.appendChild(child);        child = node.firstChild;    }    return flag;}function compile(node, vm) {    let reg = /\{\{(.*)\}\}/;    if (node.nodeType == Node.ELEMENT_NODE) {        let attrNode = node.attributes;        for (let i = 0; i < attrNode.length; i++) {            let attr = attrNode[i];            if (attr.nodeName == 'v-model') {                let name = attr.nodeValue;                node.addEventListener('input', (e) => {                    console.log(e);                    vm.data[name] = e.target.value;     // 这里会通知name的subscribers进行update                    console.log(vm);                });                                node.value = vm.data[name]; // 通知                node.removeAttribute('v-model');                new Watcher(vm, node, name, 'input');            }        }    }    else if (node.nodeType == Node.TEXT_NODE) {        if (reg.test(node.nodeValue)) {            let name = RegExp.$1;            name = name.trim();            node.nodeValue = vm.data[name];            new Watcher(vm, node, name, 'text');        }    }}复制代码

使用

复制保存为index.html,和vmodel.js放在同一文件夹。

    
Document
{
{ vueData }}
复制代码

转载地址:http://atenx.baihongyu.com/

你可能感兴趣的文章
Shell Script 学习一
查看>>
O036、Snapshot Instance 操作详解
查看>>
Auto 和 Decltye 的区别
查看>>
常用sql语句
查看>>
submit与button区别提交区别
查看>>
远程推送,集成极光的SDK,证书制造
查看>>
LeetCode-114. Flatten Binary Tree to Linked List
查看>>
Zedboard安装桌面系统ubuntu及opencv(2)
查看>>
函数声明优先级高于变量赋值
查看>>
20151217jqueryUI--自动补全工具
查看>>
链接脚本与重定位
查看>>
Hibernate 框架基本知识
查看>>
keystone nova v2 python
查看>>
VMware虚拟机Bridged(桥接模式)
查看>>
hdu4747 线段树区间修改值,区间查询和及最大值即最大值位置
查看>>
Python 字符串、列表、字典 操作方法大全 & 正则re
查看>>
Vue.js 介绍及其脚手架工具搭建
查看>>
Register code
查看>>
oracle基础入门(二)
查看>>
java 基础知识-数组的7种算法(排序、求和、最值、遍历...)
查看>>