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 相关文章推荐
判断一个对象是否为jquery对象的方法
Mar 12 Javascript
jQuery实现的经典竖向伸缩菜单效果代码
Sep 24 Javascript
深入解析JavaScript中的arguments对象
Jun 12 Javascript
js字符串引用的两种方式(必看)
Sep 18 Javascript
Angular2 PrimeNG分页模块学习
Jan 14 Javascript
jQuery插件版本冲突的处理方法分析
Jan 16 Javascript
vue awesome swiper异步加载数据出现的bug问题
Jul 03 Javascript
vue 内置过滤器的使用总结(附加自定义过滤器)
Dec 11 Javascript
vue+element树组件 实现树懒加载的过程详解
Oct 21 Javascript
原生javascript实现类似vue的数据绑定功能示例【观察者模式】
Feb 24 Javascript
vue+ElementUI 关闭对话框清空验证,清除form表单的操作
Aug 06 Javascript
vue+springboot+element+vue-resource实现文件上传教程
Oct 21 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
Re:从零开始的异世界生活 第2季 开播啦
2020/07/24 日漫
Laravel5.4框架中视图共享数据的方法详解
2019/09/05 PHP
php中array_fill函数的实例用法
2021/03/02 PHP
A标签触发onclick事件而不跳转的多种解决方法
2013/06/27 Javascript
js中判断对象是否为空的三种实现方法
2013/12/23 Javascript
Javascript递归打印Document层次关系实例分析
2015/05/15 Javascript
基于jQuery实现在线选座之高铁版
2015/08/24 Javascript
js将json格式的对象拼接成复杂的url参数方法
2016/05/25 Javascript
Three.js学习之网格
2016/08/10 Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
2017/04/01 Javascript
详解小程序原生使用ES7 async/await语法
2018/08/06 Javascript
ExtJs使用自定义插件动态保存表头配置(隐藏或显示)
2018/09/25 Javascript
微信小程序实现留言板(Storage)
2018/11/02 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
vue在响应头response中获取自定义headers操作
2020/07/24 Javascript
vue路由的配置和页面切换详解
2020/09/09 Javascript
Python MD5文件生成码
2009/01/12 Python
从零学python系列之新版本导入httplib模块报ImportError解决方案
2014/05/23 Python
python利用有道翻译实现&quot;语言翻译器&quot;的功能实例
2017/11/14 Python
Python语言实现百度语音识别API的使用实例
2017/12/13 Python
python 顺时针打印矩阵的超简洁代码
2018/11/14 Python
python实现Excel文件转换为TXT文件
2019/04/28 Python
Python使用sklearn库实现的各种分类算法简单应用小结
2019/07/04 Python
Django中间件基础用法详解
2019/07/18 Python
django表单的Widgets使用详解
2019/07/22 Python
python3实现将json对象存入Redis以及数据的导入导出
2020/07/16 Python
前端canvas动画如何转成mp4视频的方法
2019/06/17 HTML / CSS
HTML5 直播疯狂点赞动画实现代码 附源码
2020/04/14 HTML / CSS
AmazeUI图片轮播效果的示例代码
2020/08/20 HTML / CSS
世界上最具创新性的增强型知名运动品牌:Proviz
2018/04/03 全球购物
高级编程求职信模板
2014/02/16 职场文书
公安派出所所长四风问题个人对照检查材料
2014/10/04 职场文书
销售员态度差检讨书
2014/10/26 职场文书
2016年端午节校园广播稿
2015/12/18 职场文书
教师廉政准则心得体会
2016/01/20 职场文书
golang的文件创建及读写操作
2022/04/14 Golang