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 相关文章推荐
解决火狐浏览器下JS setTimeout函数不兼容失效不执行的方法
Nov 14 Javascript
JavaScript中对象属性的添加和删除示例
May 12 Javascript
JavaScript+CSS实现仿Mootools竖排弹性动画菜单效果
Oct 14 Javascript
AngularJS基础 ng-mouseenter 指令示例代码
Aug 02 Javascript
angularJS Provider、factory、service详解及实例代码
Sep 21 Javascript
一次围绕setTimeout的前端面试经验分享
Jun 15 Javascript
浅谈JavaScript find 方法不支持IE的问题
Sep 28 Javascript
利用JavaScript的%做隔行换色的实例
Nov 25 Javascript
jQuery动态移除与增加onclick属性的方法详解
Jun 07 jQuery
js prototype深入理解及应用实例分析
Nov 25 Javascript
JavaScript异步操作的几种常见处理方法实例总结
May 11 Javascript
Javascript 解构赋值详情
Nov 17 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运行SVN命令显示某用户的文件更新记录的代码
2014/01/03 PHP
PHP中的随机性 你觉得自己幸运吗?
2016/01/22 PHP
今天你说520了吗?不仅有php表白书还有java表白神器
2016/05/20 PHP
thinkphp中多表查询中防止数据重复的sql语句(必看)
2016/09/22 PHP
在TP5数据库中四个字段实现无限分类的示例
2019/10/18 PHP
获取焦点时,利用js定时器设定时间执行动作
2010/04/02 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
2013/03/19 Javascript
用js实现table单元格高宽调整,兼容合并单元格(兼容IE6、7、8、FF)实例
2013/06/25 Javascript
js动态删除div元素基本思路及实现代码
2014/05/08 Javascript
javaScript基础语法介绍
2015/02/28 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
JS实现点击按钮后框架内载入不同网页的方法
2015/05/05 Javascript
JS鼠标拖拽实例分析
2015/11/23 Javascript
AngularJS使用ng-options指令实现下拉框
2016/08/23 Javascript
Javascript 引擎工作机制详解
2016/11/30 Javascript
原生js实现网页顶部自动下拉/收缩广告效果
2017/01/20 Javascript
整理关于Bootstrap模态弹出框的慕课笔记
2017/03/29 Javascript
Nodejs--post的公式详解
2017/04/29 NodeJs
使用Electron构建React+Webpack桌面应用的方法
2017/12/15 Javascript
jQuery获取所有父级元素及同级元素及子元素的方法(推荐)
2018/01/21 jQuery
Vuex 在Vue 组件中获得Vuex 状态state的方法
2018/08/27 Javascript
Vue实现开心消消乐游戏算法
2019/10/22 Javascript
JavaScript冒泡算法原理与实现方法深入理解
2020/06/04 Javascript
python模拟登录百度贴吧(百度贴吧登录)实例
2013/12/18 Python
在Python的列表中利用remove()方法删除元素的教程
2015/05/21 Python
python opencv读mp4视频的实例
2018/12/07 Python
Pandas库之DataFrame使用的学习笔记
2019/06/21 Python
使用pyecharts1.7进行简单的可视化大全
2020/05/17 Python
旅游管理实习自我鉴定
2013/09/29 职场文书
前处理班长职位说明书
2014/03/01 职场文书
酒店管理专业毕业生求职自荐信
2014/04/28 职场文书
党员四风问题对照检查材料思想汇报
2014/09/16 职场文书
教师工作态度自我评价
2015/03/05 职场文书
2015年妇幼卫生工作总结
2015/05/23 职场文书
《丑小鸭》教学反思
2016/02/19 职场文书
Win Server2016远程桌面如何允许多用户同时登录
2022/06/10 Servers