浅析Vue.observable()实现类似vuex的状态管理功能创建响应式全局数据

一、说明

  我们习惯于用Vuex去解决状态的共享问题,但是在小项目中使用就会有增大代码体积和将代码复杂化的烦恼,所以在Vue(2.6.0)的版本中新增了一个跨组件通信方案:Vue.observable(object)。

  其作用是让一个对象可响应,Vue 内部会用它来处理 data 函数返回的对象。返回的对象可以直接用于 渲染函数 和 计算属性 内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景。

const state = Vue.observable({ count: 0 })

const Demo = {
  render(h) {
    return h('button', {
      on: { click: () => { state.count++ }}
    }, `count is: ${state.count}`)
  }
}

二、如何使用

  用过vuex的都知道,在我们添加了vuex依赖后,我们为首先会在src目录下新建一个store文件夹,用来管理我们的状态,没有用过的同学可以先去学习一下。

  仿照那种格式,我们也在src目录下新建store文件夹,并新建子文件 index.jsstate.jsmutations.js。这里,我分别介绍一下这些文件的作用,并附上代码:

1、state.js:就是一个状态,存储全局数据

import Vue from 'vue'
export default Vue.observable({
  count: 0
})

2、mutations.js:用来更新state;将state.js的数据导入,用于操作

import state from './state'
export default {
  addCount () {
    state.count++
  }
}

3、index.js:用来将state与mutations合并成一个对象,并导出;将数据与计数器方法合并为一个store并导出

import state from './state'
import mutations from './mutations'
export default {
  state,
  mutations
}

4、在页面中使用数据(将store 首先导入)

import store from '@/store' // 注意这点并不是vuex

// 这样就可以直接使用
store.state
store.mutations

  当然也可以不分文件,直接写在同一个js里。这样其实更方便

// 文件路径 - /store/store.js
import Vue from 'vue'

export const store = Vue.observable({ count: 0 })
export const mutations = {
  setCount (count) {
    store.count = count
  }
}

  使用

<template>
    <div>
        <label for="bookNum">数 量</label>
            <button @click="setCount(count+1)">+</button>
            <span>{{count}}</span>
            <button @click="setCount(count-1)">-</button>
    </div>
</template>

<script>
import { store, mutations } from '../store/store' // Vue2.6新增API Observable

export default {
  name: 'Add',
  computed: {
    count () {
      return store.count
    }
  },
  methods: {
    setCount: mutations.setCount
  也可以直接 ...mutations,就可以使用mutations里声明的方法了
} }
</script>

  就这么简单,轻量好用。

三、源码解读

  从源码可以看出Vue.observable实际就是封装了observe

  首先判断是否包含__ob__这个属性,然后实例化一个Observer对象:

 

  由于传入的不是数组,进入walk(),在walk中遍历key,并使用defineReactive$$1创建响应式对象

Walk through all properties and convert them into getter/setters. This method should only be called when value type is Object.
遍历所有属性并将它们转换为getter/setter。仅当值类型为Object时才应调用此方法。

  通过property.get进行取值,通过property.set进行赋值

  接下来调用Object.defineProperty()给对象定义响应式属性(Object.defineProperty是vue.js实现「响应式系统」的关键之一)

  • enumerable,属性是否可枚举,默认 false。
  • configurable,属性是否可以被修改或者删除,默认 false。
  • get,获取属性的方法。(进行依赖收集)(数据劫持)
  • set,设置属性的方法。(进行响应式更新)

  dep.notify():通过dep.notify()对观察者watchers进行通知,然后state就成全局响应式对象了。

  需要注意的是:在 Vue 2.x 中,被传入的对象会直接被 Vue.observable 改变;在 Vue 3.x 中,则会返回一个可响应的代理,而对源对象直接进行修改仍然是不可响应的。因此,为了向前兼容,官方推荐始终操作使用 Vue.observable 返回的对象,而不是传入源对象。

原文地址:https://www.cnblogs.com/goloving/p/13955096.html