zoukankan      html  css  js  c++  java
  • 浅析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 返回的对象,而不是传入源对象。

  • 相关阅读:
    第15.9节 PyQt学习入门:使用Qt Designer进行GUI设计的步骤
    PyQt学习随笔:Model/View开发时在view数据项中设置不同角色数据的方法
    PyQt学习随笔:Model/View开发时从Model相关类派生自定义类需要注意的问题
    PyQt学习随笔:重写setData方法截获Model/View中视图数据项编辑的注意事项
    PyQt学习随笔:Model/View中视图数据项编辑变动实时获取变动数据的方法
    Python中高级知识(非专题部分)学习随笔
    clistctrl 虚拟列表
    数字图象处理图片库
    MFC中char*,string和CString之间的转换
    图像分割之(四)OpenCV的GrabCut函数使用和源码解读
  • 原文地址:https://www.cnblogs.com/goloving/p/13955096.html
Copyright © 2011-2022 走看看