资讯专栏INFORMATION COLUMN

前端答疑-对象引用-vue共享数据源的三种方式

JerryC / 1219人阅读

摘要:它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。状态自管理应用包含以下几个部分,驱动应用的数据源,以声明方式将映射到视图,响应在上的用户输入导致的状态变化。

事情发生在上周(2019-06-06)团队技术分享的时候。
起因在于一个问题:vue 中多个组件如何使用同一个变量,我们叫这个变量为 baseConfig 吧。
说实话我没想到那么多人不理解其中的知识。今天我整理一下发出来。

方案一:VUEX 什么是 Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

状态自管理应用包含以下几个部分:

state,驱动应用的数据源;

view,以声明方式将 state 映射到视图;

actions,响应在 view 上的用户输入导致的状态变化。

以下是一个表示“单向数据流”理念的简单示意:

Vuex 的应用

其实看完了上面的介绍,我们就明白,这是一个非常符合我们需求的工具。那么我们就来看看怎么去应用。

mapState 辅助函数 当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性。

从下面的例子可以看到,我们子组件中的值是通过计算属性来从 store 中获取的。这样在通过 mutations 等方式改变之后,我们的值也会动态更新。

当然,你的页面简单的时候,也不需要再去使用 Vuex,考虑一下后面的方案吧。

const store = new Vuex.Store({
  state: {
    baseConfig: {
        server_name: "lilnong.top"
    }
  }
})
// 创建一个 User 组件
const Serv = {
  template: `
{{ server_name }}
`, computed: { server_name() { // this.$store return store.state.baseConfig.server_name } } } const app = new Vue({ el: "#app", store, // 这样可以把 store 的实例注入所有的子组件 components: { Serv }, template: `
` })
方案二:父子组件传参 父传参的方式

baseConfig 需要定义在最外面,然后给所有的子组件都传递进去,当有改变的时候,子组件也会跟着改变。

{
    data: {
        baseConfig: {
            server_name: "lilnong.top"
        }
    }
}
子组件接受参数的方式

每个子组件都需要接收。

{
    props:["server_name", "baseConfig"],//这种是无默认值,无类型检查的,正常使用不推荐这种写法
}
父子组件方案的优缺点

所有的父组件都需要传递参数,所有的子组件都要接收参数。

传入的问题可以通过,传入一个对象的所有参数来解决

方案二:路由组件传参

该方案也叫方案二,并不是我写错了,是因为他们的场景是一样。
在 Vue Router 的路由中,我们把组件配置在 routes 中,导致我们无法在模板之中传递参数。
这里我们需要使用他提供的 props 属性来传参,文档地址。jsRun测试地址。lilnong.top测试地址

const Foo = { template: "
foo
" } const Bar = { template: "
bar
" } const routes = [ { path: "/foo", component: Foo }, { path: "/bar", component: Bar } ] const router = new VueRouter({ routes // (缩写) 相当于 routes: routes }) const app = new Vue({ router }).$mount("#app")

Hello App!

Go to Foo Go to Bar

方案三:全局对象(store 模式)

简单状态管理起步使用 --官方文档

全局对象

就是如下使用,定义一个全局对象,然后修改这个全局对象就好了

const sourceOfTruth = {}
const vmA = new Vue({
  data: sourceOfTruth
})
const vmB = new Vue({
  data: sourceOfTruth
})
store 模式

原理上来讲,还是全局对象,但是通过简单的规定,来明确数据流向

var store = {
  debug: true,
  state: {
    message: "Hello!"
  },
  setMessageAction (newValue) {
    if (this.debug) console.log("setMessageAction triggered with", newValue)
    this.state.message = newValue
  },
  clearMessageAction () {
    if (this.debug) console.log("clearMessageAction triggered")
    this.state.message = ""
  }
}
var vmA = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

var vmB = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

争论核心:全局对象方案究竟行不行?原理?

好了,三种方案这里就已经介绍完了。那开始看看我们的争论:全局放个对象的方式不行(对方观点),数据更新时组件不会自动更新

先说原理,内存地址

vue 数据绑定的原理大家都懂吧?通过 defineProperty 来劫持,Dep 收集依赖等等。
对于对象类型的数据,我们变量里面保存的其实是一个指向堆的地址,我们来看下面的这个例子。

var obj = {};//定义了一个对象,`obj` 存放的是一个地址
obj.a = 1;//通过 `obj` 的地址,找到对象,然后给对象里面放了 `a=1` ;
var obj1 = obj;//把 `obj` 的地址,给 `obj1` 复制了一下
obj1.a = 2;//通过 `obj1` 的地址,找到对象,然后给对象里面放了 `a=2` ;
//这个时候,对象里面存放的就是{a:2}//console.log(obj, obj1)
//这里引出了另一个问题 深拷贝与浅拷贝

这里也就是我的核心原理。

定义一个对象(保存在 window 上)

通过对象变量保存的是地址的原理

我们在其他组件都用 window 上的对象以此来达到目的。

再说场景,细化问题

是不是看到上面的原理好简单?但是往往不是这么简单,下面咱们分析一下情况

window 上没绑对象,而是其他类型这么办?比如说 nullundefined
我也没辙,大哥,看好上面的原理,主要原理就是地址引用

对象覆盖,就是如下的这个赋值场景。
其实我理解你是想给 obj 重新都赋值一下。

obj={};
obj2 = obj;
obj.a = 1;
obj2 = {a:2,b:3};//这里把 obj2 的地址换成了新的一个对象
//console.log(obj, obj2)

但是不能这样写,正确操作如下:

Object.assign(obj2, {a:2,b:3})

一个一个值的写 obj2.a=2;obj2.b=3;

后添加的属性,没有计入 vue 的数据观察队列(新手经常犯的错误

对象变更检测注意事项

于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
 data: {
   a: 1
 }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

对象解决方案 Vue.set(object, propertyName, value)
对象解决方案(实例内) this.$set(object, propertyName, value)

数组更新检测
将一些方法进行了封装 push()、pop()、shift()、unshift()、splice()、sort()、reverse()
通过上面的方法来改变数组可以监听到改变。
由于 JavaScript 的限制,Vue 不能检测以下数组的变动:

当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue

当你修改数组的长度时,例如:vm.items.length = newLength

总结

共享数据三种方法

vuex
大而全,使用复杂

组件值传递
原生自带,使用复杂,适合组件相关数据

store
简单,不适合复杂项目。工程的话,还是推荐 vuex

对象引用需要注意的地方

不能给变量二次赋值obj2={}

只有对象类型才是存地址, ArrayObject
StringNull等不包括在内

增加数据要注意是否被观察到

对象:注意 Vue.set

数组:使用规定方法

测试地址,采用 setTimeout 来模拟异步操作。当时苦的一批,完了还没保存。性感码农,在线编程
成功的说服了在场的兄弟们,然后周四就拖堂了。

资料

VUEX 中文站

状态管理 --vue官网

微信公众号:前端linong

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104573.html

相关文章

  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0
  • 前端面试必问题答疑(2)

    摘要:解决了组件之间同一状态的共享问题。当我们的应用遇到多个组件之间的共享问题时会需要状态管理核心状态管理有个核心,分别是以及。当错误出现时,我们现在也会有一个记录之前发生了什么。此外,每个实例组件仍然可以拥有和管理自己的私有状态 一,css部分 1,简单介绍下css权重优先级: 默认样式 .father{ width:300px; ...

    wuyangchun 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<