我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解如何使用Object.defineProperty实现简易的vue功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解如何使用Object.defineProperty实现简易的vue功能

vue 双向绑定的原理

实现 vue 的双向绑定,v-textv-modelv-on 方法

Vue 响应系统,其核心有三点:observe、watcher、dep

  • observe:遍历 data 中的属性,使用 Object.definePropertyget/set 方法- 对其进行数据劫持;
  • dep:每个属性拥有自己的消息订阅器 dep,用于存放所有订阅了该属性的观察者对象;
  • watcher:观察者(对象),通过 dep 实现对响应属性的监听,监听到结果后,主动触发自己的回调进行响应。
class MinVue {
  constructor(options) {
    this.$data = options.data;
    this.$methods = options.methods;
    this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : el;
    this.bindData(this.$data);
    new Observer(this.$data);
    new Compile(this);
  }
  bindData(data) {
    Object.keys(data).forEach(key => {
      
      Object.defineProperty(this, key, {
        enumerable: true,
        configurable: true,
        get: () => {
          return data[key];
        },
        set: newValue => {
          data[key] = newValue;
        },
      });
    });
  }
}
class Observer {
  constructor(data) {
    this.work(data);
  }
  work(data) {
    if (Object.prototype.toString.call(data) === '[object Object]') {
      Object.keys(data).forEach(key => {
        this.defineReactive(data, key, data[key]);
      });
    }
  }
  defineReactive(data, key, value) {
    const observer = this;
    const dep = new Dep();
    // 当value为对象时,递归调用
    this.work(value);
    
    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: true,
      get: () => {
        if (Dep.target) {
          dep.add(Dep.target);
        }
        return value;
      },
      set: newValue => {
        value = newValue;
        // 赋新值后,新值有可能为对象,重新绑定get set方法
        observer.work(newValue);
        dep.notify();
      },
    });
  }
}
class Dep {
  constructor() {
    this.watcher = new Set();
  }
  add(watcher) {
    if (watcher && watcher.update) this.watcher.add(watcher);
  }
  notify() {
    this.watcher.forEach(watch => watch.update());
  }
}
class Watcher {
  constructor(vm, key, cb) {
    Dep.target = this;
    this.vm = vm;
    this.key = key;
    // 会触发Observer定义的getter方法,收集Dep.target
    this._old = vm.$data[key];
    this.cb = cb;
    Dep.target = null;
  }
  update() {
    const newValue = this.vm.$data[this.key];
    this.cb(newValue);
    this._old = newValue;
  }
}
class Compile {
  constructor(vm) {
    this.vm = vm;
    this.methods = vm.$methods;
    this.compile(vm.$el);
  }
  compile(el) {
    const childNodes = el.childNodes;
    Array.from(childNodes).forEach(node => {
      if (this.isTextNode(node)) {
        this.compileTextNode(node);
      } else if (this.isElementNode(node)) {
        this.compileElement(node);
      }
      if (node.childNodes && node.childNodes.length) this.compile(node);
    });
  }
  isTextNode(node) {
    return node.nodeType === 3;
  }
  isElementNode(node) {
    return node.nodeType === 1;
  }
  compileTextNode(node) {
    // .+?正则懒惰匹配
    const reg = /\{\{(.+?)\}\}/g;
    const text = node.textContent;
    if (reg.test(text)) {
      let key = RegExp.$1.trim();
      node.textContent = text.replace(reg, this.vm[key]);
      new Watcher(this.vm, key, newValue => {
        node.textContent = newValue;
      });
    }
  }
  compileElement(node) {
    const attrs = node.attributes;
    if (attrs.length) {
      Array.from(attrs).forEach(attr => {
        if (this.isDirective(attr.name)) {
          // 根据v-来截取一下后缀属性名
          let attrName = attr.name.indexOf(':') > -1 ? attr.name.substr(5) : attr.name.substr(2);
          let key = attr.value;
          this.update(node, attrName, key, this.vm[key]);
        }
      });
    }
  }
  isDirective(dir) {
    return dir.startsWith('v-');
  }
  update(node, attrName, key, value) {
    if (attrName === 'text') {
      node.textContent = value;
      new Watcher(this.vm, key, newValue => {
        node.textContent = newValue;
      });
    } else if (attrName === 'model') {
      node.value = value;
      new Watcher(this.vm, key, newValue => {
        node.value = newValue;
      });
      node.addEventListener('input', e => {
        this.vm[key] = node.value;
      });
    } else if (attrName === 'click') {
      node.addEventListener(attrName, this.methods[key].bind(this.vm));
    }
  }
}

测试 MinVue

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h3>{{ msg }}</h3>
      <p>{{ count }}</p>
      <h1>v-text</h1>
      <p v-text="msg"></p>
      <input type="text" v-model="count" />
      <button type="button" v-on:click="increase">add+</button>
      <button type="button" v-on:click="changeMessage">change message!</button>
      <button type="button" v-on:click="recoverMessage">recoverMessage!</button>
    </div>
  </body>
  <script class="lazy" data-src="./js/min-vue.js"></script>
  <script>
    new MinVue({
      el: '#app',
      data: {
        msg: 'hello,mini vue.js',
        count: 666,
      },
      methods: {
        increase() {
          this.count++;
        },
        changeMessage() {
          this.msg = 'hello,eveningwater!';
        },
        recoverMessage() {
          console.log(this);
          this.msg = 'hello,mini vue.js';
        },
      },
    });
  </script>
</html>

以上就是详解如何使用Object.defineProperty实现简易的vue功能的详细内容,更多关于Object.defineProperty vue的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

详解如何使用Object.defineProperty实现简易的vue功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详解如何使用Object.defineProperty实现简易的vue功能

这篇文章主要为大家介绍了如何使用Object.defineProperty实现简易的vue功能示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-16

vue如何实现简易选项卡功能

这篇文章主要讲解了“vue如何实现简易选项卡功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue如何实现简易选项卡功能”吧!1. 效果:1. 实现发布评论功能2. 实现评论列表的展示3.
2023-07-02

如何使用session实现简易购物车功能

这篇文章主要介绍“如何使用session实现简易购物车功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“如何使用session实现简易购物车功能”文章能帮助大家解决问题。整体思路:先写一个JSP用于
2023-06-29

Android studio如何实现简易的计算器功能

这篇文章主要讲解了“Android studio如何实现简易的计算器功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android studio如何实现简易的计算器功能”吧!具体效果如下J
2023-06-30

如何使用Java实现一个简易版的多级菜单功能

小编给大家分享一下如何使用Java实现一个简易版的多级菜单功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!正文1,首先是数据库的设计DROP TABLE IF
2023-06-26

vue如何实现简单的分页功能

这篇文章将为大家详细讲解有关vue如何实现简单的分页功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下我们都知道在spring boot项目中安装pagehelper可以实现分页功能,但是在v
2023-06-29

vue实现一个简单的分页功能实例详解

这篇文章主要介绍了vue实现一个简单的分页功能,需要的朋友可以参考下
2022-12-24

vue如何实现简单的购物车功能

这篇文章主要介绍“vue如何实现简单的购物车功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue如何实现简单的购物车功能”文章能帮助大家解决问题。1.实现效果:2.涉及到的知识点:toFixed
2023-07-02

如何使用vue实现打印功能

这篇“如何使用vue实现打印功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何使用vue实现打印功能”文章吧。第一种方法
2023-07-04

如何使用vue实现计时器功能

小编给大家分享一下如何使用vue实现计时器功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下首先我们要知道setTimeout和setInterval的区别setTimeout只在指定时间后执行一次,代码如下:
2023-06-20

详解如何使用Python实现复制粘贴的功能

pandas 里面有一个 pd.read_clipboard 函数,可以根据你复制的内容生成DataFrame。本文就利用这个函数实现复制粘贴的功能,感兴趣的可以了解一下
2023-01-03

如何使用PHP开发一个简易的购物车功能

简介:随着电子商务的快速发展,购物车功能在网上商城中是必不可少的一部分。本文将介绍如何使用PHP语言开发一个简易的购物车功能,帮助读者了解购物车的基本原理,并且提供具体的代码示例,以便读者可以更好地理解和实践。一、购物车基本原理在开始开发购
2023-10-21

如何使用vue实现手写签名功能

本篇内容介绍了“如何使用vue实现手写签名功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 个人实现截图:安装:npm install v
2023-06-20

如何使用Vue实现拖动截图功能

这篇文章主要介绍了如何使用Vue实现拖动截图功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何使用Vue实现拖动截图功能文章都会有所收获,下面我们一起来看看吧。一、安装html2canvas、vue-cro
2023-07-04

详解Vue PC端如何实现扫码登录功能

本篇文章给大家带来了关于Vue的相关知识,其中主要介绍了在PC端实现扫码的原理是什么?怎么生成二维码图片?怎么用Vue实现前端扫码登录?感兴趣的朋友,下面一起来看一下吧,希望对大家有帮助。
2023-05-14

如何使用Python实现简单的人脸识别功能

小编给大家分享一下如何使用Python实现简单的人脸识别功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、首先梳理一下实现人脸识别需要进行的步骤:流程大致如此
2023-06-14

如何使用php来实现简单的用户登录功能

这篇文章主要介绍“如何使用php来实现简单的用户登录功能”,在日常操作中,相信很多人在如何使用php来实现简单的用户登录功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用php来实现简单的用户登录功能
2023-07-05

编程热搜

目录