vue2.x 对象劫持的原理实现


Posted in Javascript onApril 19, 2020

目标:手写迷你版Vue

一:使用rollup打包,打包后的代码体积更小,更适合写框架源码的打包

npm i rollup -D

二:安装babel相关的包,以及实现静态服务,设置环境变量的包

npm i @babel/core @babel/preset-env rollup-plugin-babel roullup-plugin-serve cross-env -D

三:包的相关介绍

  • rollup (打包工具)
  • @babel/core(用babel核心模块)
  • @babel/preset-env(babel将高级语法转成低级语法)
  • rollup-plugin-serve(实现静态服务)
  • cross-env(设置环境变量)
  • rollup-plugin-babel(桥梁)

四:根目录书写rollup.config.js

import babel from 'rollup-plugin-babel';
import serve from 'rollup-plugin-serve';
export default {
 input:'./src/index.js', // 以哪个文件作为打包的入口
 output:{
   file:'dist/umd/vue.js', // 出口路径
   name:'Vue', // 指定打包后全局变量的名字
   format: 'umd', // 统一模块规范
   sourcemap:true, // es6-> es5 开启源码调试 可以找到源代码的报错位置
 },
 plugins:[ // 使用的插件
   babel({
     exclude:"node_modules/**"
   }),
   process.env.ENV === 'development'?serve({
     open:true,
     openPage:'/public/index.html', // 默认打开html的路径
     port:3000,
     contentBase:''
   }):null
 ]
}

配置package.josn

{
 "name": "vue_souce",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
  "build:dev": "rollup -c",
  "serve": "cross-env ENV=development rollup -c -w"
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "devDependencies": {
  "@babel/core": "^7.9.0",
  "@babel/preset-env": "^7.9.5",
  "cross-env": "^7.0.2",
  "rollup": "^2.6.1",
  "rollup-plugin-babel": "^4.4.0",
  "rollup-plugin-serve": "^1.0.1"
 }
}

五:新建index.html(public/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script src="/dist/umd/vue.js"></script>
  <script>
    let vm = new Vue({
      el:'#app',
      // 随便给些数据
      data(){
        return {
        name:'张三',
        age:11,
        address:{
          number:0,
          name:'李四'
        }}
      },
    })
    vm._data.address = {a:1};
    console.log(vm._data)
  </script>
</body>
</html>

六:编写Vue入口:index.js

// Vue的核心代码 只是Vue的一个声明
import {initMixin} from './init';
function Vue(options){
  // 进行Vue的初始化操作
  this._init(options);

}
// 通过引入文件的方式 给Vue原型上添加方法
initMixin(Vue); // 给Vue原型上添加一个_init方法
export default Vue

七:编写初始化操作 init.js

import {initState} from './state'
// 在原型上添加一个init方法
export function initMixin(Vue){
  // 初始化流程
  Vue.prototype._init = function (options) {
    // 数据的劫持
    const vm = this; // vue中使用 this.$options 指代的就是用户传递的属性
    vm.$options = options;

    // 初始化状态
    initState(vm); // 分割代码
  }
}

八:初始化数据

import {observe} from './observer/index.js'
export function initState(vm){
  const opts = vm.$options;
  // vue的数据来源 属性 方法 数据 计算属性 watch
  if(opts.props){
    initProps(vm);
  }
  if(opts.methods){
    initMethod(vm);
  }
  if(opts.data){
    initData(vm);
  }
  if(opts.computed){
    initComputed(vm);
  }
  if(opts.watch){
    initWatch(vm);
  }
}
function initProps(){}
function initMethod() {}
function initData(vm){
  // 数据初始化工作
  let data = vm.$options.data; // 用户传递的data
  data = vm._data = typeof data === 'function'?data.call(vm):data;
  // 对象劫持 用户改变了数据 我希望可以得到通知 =》 刷新页面
  // MVVM模式 数据变化可以驱动视图变化 
  // Object.defineProperty () 给属性增加get方法和set方法
  observe(data); // 响应式原理
}
function initComputed(){}
function initWatch(){}

九:书写核心监听功能

// 把data中的数据 都使用Object.defineProperty重新定义 es5
// Object.defineProperty 不能兼容ie8 及以下 vue2 无法兼容ie8版本
import {
  isObject
} from '../util/index'
// 后续我可以知道它是不是一个已经观察了的数据 __ob__
class Observer{
  constructor(value){ // 仅仅是初始化的操作
    // vue如果数据的层次过多 需要递归的去解析对象中的属性,依次增加set和get方法
    // 对数组监控
    this.walk(value); // 对对象进行观测
  }
  walk(data){
    let keys = Object.keys(data); // [name,age,address]

    // 如果这个data 不可配置 直接return
    keys.forEach((key)=>{
      defineReactive(data,key,data[key]);
    })
  }
}
function defineReactive(data,key,value){
  observe(value); // 递归实现深度检测
  Object.defineProperty(data,key,{
    configurable:true,
    enumerable:false,
    get(){ // 获取值的时候做一些操作
      return value;
    },
    set(newValue){ // 也可以做一些操作
      if(newValue === value) return;
      observe(newValue); // 继续劫持用户设置的值,因为有可能用户设置的值是一个对象
      value = newValue;
    }
  });
}

export function observe(data) {
  let isObj = isObject(data);
  if (!isObj) {
    return
  }
  return new Observer(data); // 用来观测数据
}

十:编写工具类文件,存放校验对象

/**
 * 
 * @param {*} data 当前数据是不是对象
 */
export function isObject(data) {
  return typeof data === 'object' && data !== null;
}

总结:

1 创建Vue构造函数,接收所有所有参数options
2 分类初始化options,本章主要处理data,让data上的引用类型的数据通过Object.definePrototy 变成响应式的,初始化是有循序的,先初始化props 然后初始化method 然后初始化data computed watch

3 核心如下

function defineReactive(data,key,value){
  observe(value); // 递归实现深度检测
  Object.defineProperty(data,key,{
    configurable:true,
    enumerable:false,
    get(){ // 获取值的时候做一些操作
      return value;
    },
    set(newValue){ // 也可以做一些操作
      if(newValue === value) return;
      observe(newValue); // 继续劫持用户设置的值,因为有可能用户设置的值是一个对象
      value = newValue;
    }
  });
}

到此这篇关于vue2.x 对象劫持的原理实现的文章就介绍到这了,更多相关vue2.x 对象劫持内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript URL参数读取改进版
Jan 16 Javascript
JS 自动完成 AutoComplete(Ajax 查询)
Jul 07 Javascript
javascript验证身份证完全方法具体实现
Nov 18 Javascript
浅析JavaScript中的类型和对象
Nov 29 Javascript
9款2014最热门jQuery实用特效推荐
Dec 07 Javascript
JavaScript浏览器对象之一Window对象详解
Jun 03 Javascript
EasyUI学习之Combobox下拉列表(1)
Dec 29 Javascript
微信小程序 this和that详解及简单实例
Feb 13 Javascript
php输出全部gb2312编码内的汉字方法
Mar 04 Javascript
vuex vue简单使用知识点总结
Aug 29 Javascript
JS实现纵向轮播图(初级版)
Jan 18 Javascript
js实现点击上传图片并设为模糊背景
Aug 02 Javascript
基于js判断浏览器是否支持webGL
Apr 18 #Javascript
JavaScript对象字面量和构造函数原理与用法详解
Apr 18 #Javascript
javascript 内存模型实例详解
Apr 18 #Javascript
javascript-hashchange事件和历史状态管理实例分析
Apr 18 #Javascript
javascript使用Blob对象实现的下载文件操作示例
Apr 18 #Javascript
原生js实现的观察者和订阅者模式简单示例
Apr 18 #Javascript
es6函数name属性功能与用法实例分析
Apr 18 #Javascript
You might like
php比较两个字符串长度的方法
2015/07/13 PHP
javascript div 弹出可拖动窗口
2009/02/26 Javascript
js中使用DOM复制(克隆)指定节点名数据到新的XML文件中的代码
2011/07/27 Javascript
下拉列表选择项的选中在不同浏览器中的兼容性问题探讨
2013/09/18 Javascript
js确认删除对话框效果的示例代码
2014/02/20 Javascript
jquery默认校验规则整理
2014/03/24 Javascript
推荐4个原生javascript常用的函数
2015/01/12 Javascript
jQuery简单实现禁用右键菜单
2015/03/10 Javascript
JS实现的倒计时效果实例(2则实例)
2015/12/23 Javascript
Bootstrap入门书籍之(五)导航条、分页导航
2016/02/17 Javascript
浅谈Angularjs link和compile的使用区别
2016/10/21 Javascript
bootstrap datetimepicker2.3.11时间插件使用
2016/11/19 Javascript
JS+HTML+CSS实现轮播效果
2017/11/28 Javascript
js正则取值的结果数组调试方法
2018/10/10 Javascript
Node.js中console.log()输出彩色字体的方法示例
2019/12/01 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
2019/12/06 Javascript
详细分析JavaScript中的深浅拷贝
2020/09/17 Javascript
使用Python编写一个模仿CPU工作的程序
2015/04/16 Python
详解 Python 与文件对象共事的实例
2017/09/11 Python
安装python时MySQLdb报错的问题描述及解决方法
2018/03/20 Python
Python字典中的键映射多个值的方法(列表或者集合)
2018/10/17 Python
python tkinter实现界面切换的示例代码
2019/06/14 Python
Python3.6 + TensorFlow 安装配置图文教程(Windows 64 bit)
2020/02/24 Python
浅谈keras中自定义二分类任务评价指标metrics的方法以及代码
2020/06/11 Python
Python判断远程服务器上Excel文件是否被人打开的方法
2020/07/13 Python
瑞典的玛丽小姐:Miss Mary of Sweden
2019/02/13 全球购物
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
Onzie官网:美国时尚瑜伽品牌
2019/08/21 全球购物
用你熟悉的语言写一个连接ORACLE数据库的程序,能够完成修改和查询工作
2012/06/11 面试题
简单的JAVA编程面试题
2013/03/19 面试题
信息部岗位职责
2013/11/12 职场文书
《蜗牛》教学反思
2014/02/18 职场文书
幼儿园开学寄语
2014/04/03 职场文书
安全生产责任书范本
2014/04/15 职场文书
新店开张活动方案
2014/08/24 职场文书
叶问观后感
2015/06/15 职场文书