Vue 3.0 function-based API尝鲜(六):组件间通信

关键词:state、Vuex、context.root

从广义上来说,我觉得组件间通信的应用场景,无非就是父子组件间的通信和非父子组件间(兄弟、祖孙……)的通信。其实说白了,所谓的通信,就是控制数据的流动,也就是控制“状态”;我倒是挺认可有限状态机模型的。如果进一步细分,大致是这样几种:

  1. 父子组件间通信,这个是最简单也是最常用的场景。父子组件间的通信可以直接通过props$emit完成,如果放在3.0,就是propscontext.emit。从直观感受上说,父子组件之间的关系,有点CSS那种一层层叠加的感觉;如果从面向对象理论的角度说,有点类似于组合委托,拥有共同的生命周期。
  2. 总线通信,我觉得store模式也算总线的一种。这个适用于比较简单的组件间通信。有时候需要兄弟组件传值,或者一个父组件需要管理多个子组件(这个时候用props就会臃肿,而且不好维护),并且整个项目规模不大,完全可以考虑用一个总线代替Vuex来管理整个项目的状态。当然缺陷也是很明显的,扩展性明显不足,同时对没有办法很好地追踪数据的流动(至少很不优雅),给调试带来了困难。说到底是一个工程问题,要在成本和效率上进行权衡。
  3. Vuex通信,这个单独拿出来,适用于比较复杂的项目。有时候会有一些全局共享的数据,比如token和一些登录信息。虽然这些数据也可以存在sessionStorage、localStorage或者cookie里,但刷新后丢失这个特性有时候还是很有用的,比如我可以检测这个来更新token。我很喜欢Dan Abramov那句话:“Flux libraries are like glasses: you’ll know when you need them.”需要的时候,你自然就会想到它。Vuex可以更好地在组件外部管理状态,而且是那种受控的全局变量,避免了无法维护的公共耦合。
  4. router通信。不要忘了,router也是可以携带数据的。有时候,我们需要在两个页面间传递数据(比如id),但是这个数据只在这里出现,并不值得放进Vuex里。这个时候,我们就可以让router来传递数据;可能还需要activateddeactivated钩子的配合。router的params和query都可以承担这个职责。

说起总线,要么就是创建一个空的Vue实例,然后用$emit$on进行传递:

// bus.js
import Vue from 'vue'
export const bus = new Vue()
// parent.vue
created () {
    bus.$on('foo', (bar) => {// do sth...})
}
// child.vue
bus.$emit('foo', bar)

但是这种写法的限制比较多,要求监听的对象(在这里是父组件)一定要先于被监听的对象创建;而且中途销毁子组件也会影响监听。

或者像官方文档上写的那样,创建一个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 = ''
  }
}

不过在这种简单的应用场景下,还有更简单的方案;我们只是需要一个状态的容器而已,不是吗?所以……还记得2.6的新API,Vue.observable吗?

让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。

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

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

我们先设想一个最简单的非父子组件间通信的场景。这个时候,我们可以用Vue.observable创建一个容器,然后就可以代替之前的bus了:

import Vue from 'vue'
export const bus = Vue.observable({
  foo: 'bar'
})

在3.0里,state,从某种意义上,是可以用来取代Vue.observable的:

import Vue from 'vue'
import { plugin, state } from 'vue-function-api'

Vue.use(plugin)

export const bus = state({
  foo: 'bar'
})

需要注意的是,这里一定要有一个Vue.use的过程。这个不同于函数式的组件。不过,在3.0里,state的作用并不仅止于这些。它的真正意义,大概是作为包装对象的另一面,作为共享状态的容器只是其中一个应用场景罢了:

如果你依然想创建一个没有包装的响应式对象,可以使用 stateAPI(和 2.x 的 Vue.observable()等同)。

说完这个,说说Vuex的用法。我们都知道,Vuex和router是挂载在根实例上的,所以我们可以用$store$router$route来调用它们。这一点在main里体现得很明显:

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

但是到了3.0,$已经被setup代替了。那么,我们应该怎么使用呢?可以看一个例子,这个是来自vue-function-api的issue的写法:

setup (props, { root }) {
  const fields = computed(() => root.$store.state.fields)
}

不过,为了支持3.0,Vuex和router的API显然是会有变动的。按照作者的说法,未来的API可能会类似于这样:

import  { useStore, useComputed } from 'vuex';

setup (props, { root }) {
  const store = useStore();
  const filed = useComputed('state.field');
}

目前为了达到这个效果(也就是所谓的FOP,面向未来编程),可以按照作者的说法,搞一个tricky的适配;这个我也在demo里写了:

const store = new Vuex.Store({//...})

export function userStore() {
  return store;
}

当然,也有dalao自己实现了一个版本。虽然我并不认识他……但是我觉得很有意思,就分享给大家:传送门

目录

Vue 3.0 function-based API尝鲜(一):前言

Vue 3.0 function-based API尝鲜(二):配置与启动

Vue 3.0 function-based API尝鲜(三):包装对象

Vue 3.0 function-based API尝鲜(四):值得一提的watch

Vue 3.0 function-based API尝鲜(五):生命周期

Vue 3.0 function-based API尝鲜(七):This与Refs

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3.0中的组件高级功能包括保持动态组件状态和引用DOM元素。 保持动态组件状态的方法是使用Vue内置的<keep-alive>组件。通过将动态组件包裹在<keep-alive>标签中,可以在切换动态组件时保持组件的状态。例如: ```html <keep-alive> <component :is="comName"></component> </keep-alive> ``` 在这个例子中,comName是一个data属性,用于指定当前要渲染的组件的名称。通过在<component>标签中使用:is属性,可以动态地指定要渲染的组件。 引用DOM元素的方法是使用ref属性。通过给DOM元素添加ref属性,可以在组件中通过$refs属性获取对DOM元素的引用。例如: ```html <template> <h3>MyRef组件</h3> <button @click="getRef">获取$refs引用</button> </template> <script> export default { methods: { getRef() { console.log(this.$refs) // $refs指向一个空对象,需要在DOM元素上添加ref属性 } } } </script> ``` 在这个例子中,点击按钮后,调用getRef方法可以在控制台上输出当前组件实例对象this。通过this.$refs可以访问到DOM元素的引用。 以上就是Vue3.0组件高级功能的两个示例,分别是保持动态组件状态和引用DOM元素。希望能对你有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Vue3.0----组件高级【下】(第五章)](https://blog.csdn.net/QQ675396947/article/details/127486948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值