欢迎来到DIVCSS5查找CSS资料与学习DIV CSS布局技术!
最近在写项目的时候碰到一个场景:一个地图应用,有个侧边栏,侧边栏里面放着很多选项,选项改变的时候,应用会根据侧边栏的条件请求数据,然后在地图上放 markers 。页面可以简单抽象成如下结构:
 
// App.vue
 
<div>
 
  <sidebar></sidebar>
 
  <map></map>
 
</div>
 
有很多种方式可以来完成上面的需求,我先介绍 2 种常见的做法,最后再给出一个比较另类但很有趣的方案。
 
1.直接上 vuex
 
通常来讲,有多个组件共享状态的时候,把共享的状态丢给 vuex 来处理是个不错的方案。但是在处理上面那个场景的时候,会显示的有点「笨重」,因为侧边栏实际上是一个表单,如果使用 vuex 的话,就需要为每个选项定义一套 mutation,失去了直接使用 v-model 的便利。
 
直接使用组件状态绑定一个选项
 
// sidebar.vue
 
<input v-model="message">
 
// ...
 
data () {
 
  return {
 
    message: ''
 
  }
 
 
当使用 vuex 绑定一个选项时,多了不少「模板」代码
 
// 定义 state, mutation
 
state: {
 
  message: ''
 
},
 
mutations: {
 
  updateMessage (state, message) {
 
    state.message = message
 
  }
 
}
 
// sidebar.vue
 
<input :value="message" @input="updateMessage">
 
// ...
 
computed: {
 
  ...mapState({
 
    message: state => state.message
 
  })
 
},
 
methods: {
 
  updateMessage (e) {
 
    this.$store.commit('updateMessage', e.target.value)
 
  }
 
}
 
2.将状态放到父组件上
 
如果 sidebar 和 map 有一个共同的父级,使用这种方式处理起来会比上面的简单很多。但是当我们的应用越来越大的时候,往往会把 sidebar 和 map 拆成颗粒度更小的组件,那么通过 props 一层层传给子组件也会变的非常麻烦。
 
3.将组件状态「共享」出来
 
我们通常把组件内的状态写成下面这种形式:
 
// ...
 
data () {
 
  return {
 
     message: ''
 
  }
 
}
 
实际上,我们可以把 data () {} 中返回的对象单独提取到外面,作为一个变量,像下面这种写法:
 
const state = { message: '' }
 
// ...
 
data () {
 
  return state
 
}
 
那么在这个组件初始化过程中,state 对象会被 vue 「响应式化」,这会引出一个有趣的事情:任何组件,只要模版中使用了 state.message ,当 state.message 改变时,页面都会被同步更新。
 
知道了这个之后,我们就可以将侧边栏的状态写成一个独立的文件,作为一个模块引入其他组件中,结构如下:
 
// state.js
 
export default { message: '' }
 
// sidebar.vue
 
<input v-model="state.message" />
 
import state from 'path/to/state.js'
 
// ...
 
data () {
 
  return { state }
 
}
 
// map.vue
 
// 在模版中使用侧边栏的状态
 
<div>{{ state.message }}</div>
 
import state from 'path/to/state.js'
 
// ...
 
data () {
 
  return { state }
 
},
 
created () {
 
  // 将侧边栏的状态作为参数去请求数据
 
  axios.get('/xxxx', { params: state })
 
}
 
这样做的一个好处是,既可以在 sidebar.vue 中把 state 当作「内部」状态,愉快的使用 v-model 绑定数据,map.vue 中也可以方便的拿到 state 做为参数请求,同时还可以直接在 map.vue 的模版中使用 ——state.message——。
 
更进一步
 
上面的方案中,state「响应式化」是发生在子组件初始化的过程中,我希望能在应用开始的时候,主动在某个时刻完成这一步。这个时候就可以借助 Vue 构造函数,像下面这样:
 
// store.js
 
import state from 'path/to/state.js'
 
new Vue({
 
  data: {
 
    state
 
  }
 
})
 
然后在主文件 main.js 中引入 store.js,state 就会被「响应式化」。
 
总结
 
本文阐述了在这个特定场景下,对于如何管理侧边栏状态的一些思考,希望大家看完后有所收获 :)

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h63559.shtml