vue源码系列之 响应式数据处理

vue源码系列之 响应式数据处理

index.html

  • 创建一个Vue实例对象,并且传入一个对象
<!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"> {{ name }}</div>
  <script src="dist/vue.js"></script>
  <script>
    // viewModel 数据模型 MVVM view - vm - model
    let vm = new Vue({
      el: "#app",
      // data: {
      //   name: "xpl"
      // }
      data() {
        return {
          name: "xpl",
          a: {
            name: "aaa",
            b: {
              name: "bbb"
            }
          }
        }
      }
    })
    // console.log("vm.$options", vm.$options); // {el: '#app', data: {…}}
    console.log("vm", vm); // {$options: {el: '#app', data: ƒ}, _data: { name: "xpl" }}}
  </script>
</body>

</html>

src / index.js

  • 对Vue实例对象调用时,传入的数据 options进行初始化操作
import {
  initMixin
} from "./init";
// Vue 类 -> options 为用户传入的选项
function Vue(options) {
  this._init(options); //初始化操作
}

// 扩展原型的
initMixin(Vue)
export default Vue;

src / init.js

  • 对传入的对象进行拓展等,有data的数据劫持,props,watch等拓展!
  • 首先先阐述的是对data的设置为响应式数据
    • 把this指向当前Vue实例对象,设置为vm对象
    • 给与Vue实例对象挂载$options属性,之后进行拓展
    • initSate(vm) // 初始化数据 状态开始
import {
  initSate
} from "./state";

// 表示在vue的基础上 做一次混合操作
export function initMixin(Vue) {

  Vue.prototype._init = function (options) {
    // console.log("initMixin options", options);
    const vm = this;
    vm.$options = options; //options传入的Vue类的对象数据 后续对 options进行扩展操作

    // 对数据状态的 初始化 watch computed props等
    initSate(vm)
  }
}

state.js

  • 针对Vue实例对象上的 $options 选项根据不同的方式去处理,data,props,watch等初始化状态
  • 这边阐述的是,针对data 数据的初始化状态
    • 强制vm对象添加_data属性,进行关联起来,实现MVVM模式
    • observe(data); 针对数据data进行数据的监听,实现响应式数据的设置!
// 状态的初始化
import {
  observe
} from "./observe/index";
import {
  isFunction
} from "./utils";
export function initSate(vm) {
  // console.log("状态的初始化", vm.$options); // {el: '#app', data: {…}}
  const opts = vm.$options; // 拿到vue实例的所有选项

  // if (opts.props) {
  //   initProps()
  // }
  if (opts.data) {
    initData(vm);
  }
  // if (opts.computed) {
  //   initComputed()
  // }
  // if (opts.watch) {
  //   initWatch()
  // }
}

function initData(vm) {
  let data = vm.$options.data;
  // console.log("data初始化", data); // {name: 'xpl'} 修改后的:ƒ data() { return { name: "xpl" } }
  // 把数据设置为响应式数据 
  // vue2 会把数据将data中的所有数据 进行数据劫持 Object.defineProporty()
  // 判断data是不是函数,若是函数则调用这个函数,并且指向当前vue实例对象 否者的话就返回当前data
  // 此时 vm 和 data 是没有任何关系的! 强制vm对象添加_data属性,进行关联起来
  data = vm._data = isFunction(data) ? data.call(vm) : data;
  // console.log("data", data); // {name: 'xpl'}
  // 观察数据 data
  observe(data);
}

observe / index.js

  • 监听data数据对象,
    • 首先先判断是否为对象,为对象的时候 才观测
    • 之后调用 Observer(data) 观察者模式
    • 观察者针对传入的对象进行遍历,对每一个对象上的属性进行劫持,设置为响应式属性
    • defineReactive方法为 定义响应式数据
      • 首先默认而言,传入的数据是对象套对象,则需要对数据data的递归劫持 observe(value);
      • 再者就是通过 Object.defineProperty 方法对数据进行设置响应式数据
        • 其中又分为取值,直接返回value即可
        • 又分为修改值
          • 若是普通的修改值,则直接返回newVal
          • 若是修改的是对象中的属性,则又需要递归劫持 observe(newVal)
import {
  isObject
} from "../utils";
// 检测数据的变化 类是有类型的,对象是无类型!
class Observer {
  constructor(data) { // 对对象中的所有属性 进行劫持
    this.walk(data); // 对每一个对象劫持后 调用一次
  }
  walk(data) {
    Object.keys(data).forEach(key => {
      defineReactive(data, key, data[key]); // 把对象中的属性 定义为响应式数据
    })
  }
}
// vue2 对对象进行遍历后 将每个属性 用defineProperty重新定义 -> 造成性能较差
function defineReactive(data, key, value) {
  // 注意点:就是value为对象的时候,需要再劫持
  observe(value); // 本身默认传入的数据为对象套对象时,则需要递归劫持
  // console.log("defineReactive", data, key, value); // defineReactive {name: 'xpl'} name xpl
  Object.defineProperty(data, key, {
    get() { // 取值
      return value;
    },
    set(newVal) { // 设置data新的值
      observe(newVal) // 对数据进行修改时 是一个对象,又需要劫持,修改为响应式数据
      value = newVal;
    }
  })
}

// 观察者 监听data数据
export function observe(data) {
  // console.log("observe内的", data); // observe内的 {name: 'xpl'}
  // 如果为对象的时候 才观测
  if (!isObject(data)) {
    return;
  }
  // 默认而言 data是一个对象
  return new Observer(data)
}

utils.js

// 判断是不是函数
export function isFunction(val) {
  return typeof val === 'function'
}
// 判断是不是对象
export function isObject(val) {
  return typeof val === 'object' && val !== null
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值