iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >详解如何使用Object.defineProperty实现简易的vue功能
  • 730
分享到

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

Object.defineProperty vuevue简易功能 2023-05-16 20:05:59 730人浏览 八月长安
摘要

目录Vue 双向绑定的原理测试 MinVuevue 双向绑定的原理 实现 vue 的双向绑定,v-text、v-model、v-on 方法 Vue 响应系统,其核心有三点:obser

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 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的资料请关注编程网其它相关文章!

--结束END--

本文标题: 详解如何使用Object.defineProperty实现简易的vue功能

本文链接: https://www.lsjlt.com/news/210535.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • 详解如何使用Object.defineProperty实现简易的vue功能
    目录vue 双向绑定的原理测试 MinVuevue 双向绑定的原理 实现 vue 的双向绑定,v-text、v-model、v-on 方法 Vue 响应系统,其核心有三点:obser...
    99+
    2023-05-16
    Object.defineProperty vue vue简易功能
  • vue如何实现简易选项卡功能
    这篇文章主要讲解了“vue如何实现简易选项卡功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue如何实现简易选项卡功能”吧!1. 效果: 实现发布评论功能 实现评论列表的展示 使用标签页...
    99+
    2023-07-02
  • vue实现简易的计算器功能
    本文实例为大家分享了vue实现简易计算器功能的具体代码,供大家参考,具体内容如下 实现功能:将两个输入框中的值进行加减乘除计算 用到的知识点: 1.v-model数据双向绑定 2. ...
    99+
    2024-04-02
  • vue实现简易选项卡功能
    本文实例为大家分享了vue实现简易选项卡功能的具体代码,供大家参考,具体内容如下 1. 效果: 1. 实现发布评论功能 2. 实现评论列表的展示 3. 使用标签页切换的方式来实现 4...
    99+
    2024-04-02
  • Vue实现简易记事本功能
    本文实例为大家分享了Vue实现简易记事本功能的具体代码,供大家参考,具体内容如下 预览图: 功能如下: (1)输入任务并按下回车键,可将任务添加至任务列表(不可输入重复任务) (...
    99+
    2024-04-02
  • 如何使用session实现简易购物车功能
    这篇文章主要介绍“如何使用session实现简易购物车功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“如何使用session实现简易购物车功能”文章能帮助大家解决问题。整体思路:先写一个JSP用于...
    99+
    2023-06-29
  • Vue怎么实现简易记事本功能
    这篇文章主要讲解了“Vue怎么实现简易记事本功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue怎么实现简易记事本功能”吧!预览图:功能如下:(1)输入任务并按下回车键,可将任务添加至任...
    99+
    2023-06-25
  • 使用session实现简易购物车功能
    本文实例为大家分享了用session实现简易购物车功能的具体代码,供大家参考,具体内容如下 整体思路:先写一个JSP用于实现商品图片的读取(再次之前要写好连接数据库),当点加入购物车...
    99+
    2024-04-02
  • C++如何实现简易通讯录功能
    这篇文章主要讲解了“C++如何实现简易通讯录功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++如何实现简易通讯录功能”吧!实现功能提示:这里可以添加本文要记录的大概内容:通过c++语法...
    99+
    2023-07-02
  • Android studio如何实现简易的计算器功能
    这篇文章主要讲解了“Android studio如何实现简易的计算器功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android studio如何实现简易的计算器功能...
    99+
    2023-06-30
  • 如何使用Java实现一个简易版的多级菜单功能
    小编给大家分享一下如何使用Java实现一个简易版的多级菜单功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!正文1,首先是数据库的设计DROP TABL...
    99+
    2023-06-26
  • Android实现简易的闹钟功能
    本文实例为大家分享了Android实现简易的闹钟功能的具体代码,供大家参考,具体内容如下 主要是通过广播,实现一个闹钟的简易功能。 实现效果如下: 主界面为一个简易的设置闹钟Butt...
    99+
    2024-04-02
  • C#如何实现简易计算器小功能
    这篇文章主要介绍C#如何实现简易计算器小功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体内容如下简易的登陆界面。具有幻灯片效果。(picturebox time控件)计算器支持多位数,小数,括号的运算。音乐是一...
    99+
    2023-06-29
  • vue如何实现简单的分页功能
    这篇文章将为大家详细讲解有关vue如何实现简单的分页功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下我们都知道在spring boot项目中安装pagehelper可以实现分页功能,但是在v...
    99+
    2023-06-29
  • vue实现一个简单的分页功能实例详解
    这是一个简单的分页功能,只能够前端使用,数据不能通过后台服务器进行更改,能容已经写死了。 下面的内容我是在做一个关于婚纱项目中用到的,当时好久没用vue了,就上网区找了别人的博客来看...
    99+
    2022-12-24
    vue分页功能 vue实现一个简单的分页功能
  • VUE如何利用vue-print-nb实现打印功能详解
    目录一、安装vue-print-nb二、引入Vue项目三、参数说明四、应用五、注意点补充:空白页的解决方法总结一、安装vue-print-nb 没有什么前提要求,直接安装即可,但因为...
    99+
    2024-04-02
  • vue如何实现简易的弹出框
    目录vue实现弹出框1.Template2.script => data 中定义3.script => methods 中定义关闭方法4.样式vue实现弹窗选择1.创建一...
    99+
    2024-04-02
  • Vue如何实现简单搜索功能
    这篇文章主要讲解了“Vue如何实现简单搜索功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue如何实现简单搜索功能”吧!1、概述在vue项目中,搜索功能是我们经常需要使用的一个场景,最常...
    99+
    2023-07-05
  • Golang实现简易的命令行功能
    目录前言开始flag.Stringflag.Intflag.StringVarflag.IntVar定义命令行参数实现 -f -v 是否强制拷贝copyFileAction 实现co...
    99+
    2023-02-13
    Golang实现命令行功能 Golang命令行功能 Golang命令行
  • vue如何实现简单的购物车功能
    这篇文章主要介绍“vue如何实现简单的购物车功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue如何实现简单的购物车功能”文章能帮助大家解决问题。1.实现效果:2.涉及到的知识点:toFixed...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作