[vue]多组件共享数据与vuex模块化

简介: [vue]多组件共享数据与vuex模块化

前言

系列文章目录:

[Vue]目录

老师的课件笔记,不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU

笔记在线版: https://note.youdao.com/s/5vP46EPC

视频:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通

1. 多组件共享数据案例

1.1 实现效果

1.2 代码实现

store/index.js

// 该文件用于创建 vuex 中最为核心的 store
// 引入 vue
import Vue from 'vue'
// 引入 vuex
import Vuex from 'vuex'
// 使用 vuex
Vue.use(Vuex)
// 准备 actions 用于响应组件中的动作
const actions = {
  // 等一等再加
  incrementWait(context, value) {
    console.log('actions 中的 incrementWait 被触发', context, value)
    setTimeout(() => {
      context.commit('INCREMENTWAIT', value)
    }, 500);
  },
  // 当前求和为奇数再加
  incrementOdd(context, value) {
    console.log('actions 中的 incrementOdd 被触发', context, value)
    if (context.state.sum % 2) {
      context.commit('INCREMENTODD', value)
    }
  }
}
// 准备 mutations 用于操作数据 state
const mutations = {
  // 加法
  INCREMENT(store, value) {
    console.log('mutations 中的 INCREMENT 被触发', store, value)
    store.sum += value
  },
  // 减法
  DECREMENT(store, value) {
    console.log('mutations 中的 DECREMENT 被触发', store, value)
    store.sum -= value
  },
  // 等一等再加
  INCREMENTWAIT(store, value) {
    console.log('mutations 中的 INCREMENTWAIT 被触发', store, value)
    store.sum += value
  },
  // 当前求和为奇数再加
  INCREMENTODD(store, value) {
    console.log('mutations 中的 INCREMENTODD 被触发', store, value)
    store.sum += value
  },
  // 添加人员
  ADD_PERSON(state, person) {
    state.personList.unshift(person)
  }
}
// 准备 state 用于存储数据
const state = {
  // 当前求和
  sum: 0,
  school: 'SGG',
  subject: '前端',
  personList: [
    {id: '001', name: '张三'}
  ]
}
// getters 
const getters = {
  // 会有一个参数 state
  // 获取当前求和放大十倍后的值
  bigSum(state) {
    return state.sum * 10
  }
}
// 创建并导出 store
export default new Vuex.Store({
  actions,
  mutations,
  state,
  getters
})

main.js

import Vue from 'vue'
import App from './App.vue'
// 引入 store
import store from './store'
//关闭vue的生产提示
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
  store
}).$mount('#app')

App.vue

<template>
  <div>
    <!-- 使用子组件 -->
    <Count></Count>
    <hr>
    <Person></Person>
  </div>
</template>
<script>
// 导入子组件
import Count from './components/Count.vue'
import Person from './components/Person.vue'
export default {
  name: 'App',
  // 注册子组件
  components: {
    Count,
    Person
  }
}
</script>

Count.vue

<template>
  <div>
    <h1>当前求和为: {{sum}}</h1>
    <h1>当前求和放大10倍为: {{bigSum}}</h1>
    <h1>学校: {{school}}</h1>
    <h1>学科: {{subject}}</h1>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="INCREMENT(n)">+</button>
    <button @click="DECREMENT(n)">-</button>
    <button @click="incrementWait(n)">等一等再加</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <h3>Person组件的总人数为: {{personList.length}}</h3>
  </div>
</template>
<script>
// 导入 mapState mapGetters
import { mapState, mapGetters } from 'vuex'
// 引入 mapMutations
import { mapMutations, mapActions } from 'vuex'
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  computed: {
    // 借助mapState生成计算属性,从state中读取数据。(数组写法)
    ...mapState(['sum', 'school', 'subject', 'personList']),
    //借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
    ...mapGetters(['bigSum'])
  },
  methods: {
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    ...mapMutations(['INCREMENT', 'DECREMENT']),
    // 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
    ...mapActions(['incrementWait', 'incrementOdd'])
  }
}
</script>
<style>
button {
  margin: 5px;
}
h3 {
  color: brown;
}
</style>

Person.vue

<template>
  <div>
    <h1>人员列表</h1>
    <input type="text" placeholder="请输入姓名" v-model="name">
    <button @click="addPerson">添加</button>
    <ul>
      <li v-for="person in personList" :key="person.id">{{person.name}}</li>
    </ul>
    <h3>Count组件求和为: {{sum}}</h3>
  </div>
</template>
<script>
// 导入 mapState mapMutations
import {mapState, mapMutations} from 'vuex'
// 导入 nanoid 用于 id 的生成
import {nanoid} from 'nanoid'
export default {
  name: 'Person',
  data() {
    return {
      name: ''
    }
  },
  computed: {
    ...mapState(['personList', 'sum'])
  },
  methods: {
    addPerson() {
      const person = {
        id: nanoid(),
        name: this.name
      }
      this.ADD_PERSON(person)
      this.name = ''
    },
    ...mapMutations(['ADD_PERSON'])
  }
}
</script>
<style>
</style>

2. vuex 模块化

vuex 模块化是将 vuex 中 actions、mutations、state、getters 中的数据和方法根据功能进行拆分。即和同一个功能相关的 actions、mutations、state、getters 放在一起。

2.1 vuex 模块化拆分

store/index.js

// 该文件用于创建 vuex 中最为核心的 store
// 引入 vue
import Vue from 'vue'
// 引入 vuex
import Vuex from 'vuex'
// 使用 vuex
Vue.use(Vuex)
// 和计算相关的配置项
const acountOptions = {
  actions: {
    // 等一等再加
    incrementWait(context, value) {
      console.log('actions 中的 incrementWait 被触发', context, value)
      setTimeout(() => {
        context.commit('INCREMENTWAIT', value)
      }, 500);
    },
    // 当前求和为奇数再加
    incrementOdd(context, value) {
      console.log('actions 中的 incrementOdd 被触发', context, value)
      if (context.state.sum % 2) {
        context.commit('INCREMENTODD', value)
      }
    }
  },
  mutations: {
    // 加法
    INCREMENT(store, value) {
      console.log('mutations 中的 INCREMENT 被触发', store, value)
      store.sum += value
    },
    // 减法
    DECREMENT(store, value) {
      console.log('mutations 中的 DECREMENT 被触发', store, value)
      store.sum -= value
    },
    // 等一等再加
    INCREMENTWAIT(store, value) {
      console.log('mutations 中的 INCREMENTWAIT 被触发', store, value)
      store.sum += value
    },
    // 当前求和为奇数再加
    INCREMENTODD(store, value) {
      console.log('mutations 中的 INCREMENTODD 被触发', store, value)
      store.sum += value
    },
  },
  state: {
    sum: 0,
    school: 'SGG',
    subject: '前端',
  },
  getters: {
    bigSum(state) {
      return state.sum * 10
    }
  }
}
// 和人员相关的配置项
const personOptions = {
  actions: {},
  mutations: {
    // 添加人员
    ADD_PERSON(state, person) {
      state.personList.unshift(person)
    }
  },
  state: {
    personList: [
      { id: '001', name: '张三' }
    ]
  },
  getters: {}
}

2.2 使用模块化后的配置项

创建store实例对象时,使用模块化后的配置项,模块化后的配置项需要写在store的modules配置项中。

store/index.js

// 创建并导出 store
export default new Vuex.Store({
  modules: {
    acount: acountOptions,
    person: personOptions
  }
})

2.2 开启命名空间

// 配置项开启命名空间
namespaced: true,

store/index.js

// 和计算相关的配置项
const acountOptions = {
  namespaced: true,
  actions: {
    ......
  },
  mutations: {
    ......
  },
  state: {
    ......
  },
  getters: {
    ......
  }
}
// 和人员相关的配置项
const personOptions = {
  namespaced: true,
  actions: {},
  mutations: {
    ......
  },
  state: {
    ......
  },
  getters: {}
}

2.3 模块化后读取数据和方法

vuex 模块化使用 mapState、mapGetters、mapMutations、mapActions 读取数据和获取相应的方法,需要在数组和对象前面先传入一个参数,该参数为数据和方法对应所在的命名空间。

Count.vue

<template>
  <div>
    <h1>当前求和为: {{sum}}</h1>
    <h1>当前求和放大10倍为: {{bigSum}}</h1>
    <h1>学校: {{school}}</h1>
    <h1>学科: {{subject}}</h1>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="INCREMENT(n)">+</button>
    <button @click="DECREMENT(n)">-</button>
    <button @click="incrementWait(n)">等一等再加</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <h3>Person组件的总人数为: {{personList.length}}</h3>
  </div>
</template>
<script>
// 导入 mapState mapGetters
import { mapState, mapGetters } from 'vuex'
// 引入 mapMutations
import { mapMutations, mapActions } from 'vuex'
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  computed: {
    // 借助mapState生成计算属性,从state中读取数据。(数组写法)
    ...mapState('acount',['sum', 'school', 'subject']),
    ...mapState('person',['personList']),
    //借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
    ...mapGetters('acount',['bigSum'])
  },
  methods: {
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)
    ...mapMutations('acount',['INCREMENT', 'DECREMENT']),
    // 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
    ...mapActions('acount',['incrementWait', 'incrementOdd'])
  }
}
</script>
<style>
button {
  margin: 5px;
}
h3 {
  color: brown;
}
</style>

Person.vue

<template>
  <div>
    <h1>人员列表</h1>
    <input type="text" placeholder="请输入姓名" v-model="name">
    <button @click="addPerson">添加</button>
    <ul>
      <li v-for="person in personList" :key="person.id">{{person.name}}</li>
    </ul>
    <h3>Count组件求和为: {{sum}}</h3>
  </div>
</template>
<script>
// 导入 mapState mapMutations
import {mapState, mapMutations} from 'vuex'
// 导入 nanoid 用于 id 的生成
import {nanoid} from 'nanoid'
export default {
  name: 'Person',
  data() {
    return {
      name: ''
    }
  },
  computed: {
    ...mapState('acount',['sum']),
    ...mapState('person',['personList'])
  },
  methods: {
    addPerson() {
      const person = {
        id: nanoid(),
        name: this.name
      }
      this.ADD_PERSON(person)
      this.name = ''
    },
    ...mapMutations('person', ['ADD_PERSON'])
  }
}
</script>
<style>
</style>

3. 总结 多组件共享数据与vuex模块化

3.1. 目的

让代码更好维护,让多种数据分类更加明确。

3.2. 修改store.js

const countAbout = {
     namespaced:true,//开启命名空间
     state:{x:1},
     mutations: { ... },
     actions: { ... },
     getters: {
       bigSum(state){
          return state.sum * 10
       }
     }
   }
   const personAbout = {
     namespaced:true,//开启命名空间
     state:{ ... },
     mutations: { ... },
     actions: { ... }
   }
   const store = new Vuex.Store({
     modules: {
       countAbout,
       personAbout
     }
   })

3.3 开启命名空间后,组件中读取state数据

//方式一:自己直接读取
   this.$store.state.personAbout.list
   //方式二:借助mapState读取:
   ...mapState('countAbout',['sum','school','subject']),

3.4. 开启命名空间后,组件中读取getters数据:

//方式一:自己直接读取
   this.$store.getters['personAbout/firstPersonName']
   //方式二:借助mapGetters读取:
   ...mapGetters('countAbout',['bigSum'])

3.5. 开启命名空间后,组件中调用dispatch

//方式一:自己直接dispatch
   this.$store.dispatch('personAbout/addPersonWang',person)
   //方式二:借助mapActions:
   ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

3.6. 开启命名空间后,组件中调用commit

//方式一:自己直接commit
   this.$store.commit('personAbout/ADD_PERSON',person)
   //方式二:借助mapMutations:
   ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),


相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
146 64
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
41 8
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
监控 JavaScript 算法
深度剖析 Vue.js 响应式原理:从数据劫持到视图更新的全流程详解
本文深入解析Vue.js的响应式机制,从数据劫持到视图更新的全过程,详细讲解了其实现原理和运作流程。
|
2月前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
2月前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
2月前
|
存储 JavaScript
Vue 状态管理工具vuex
Vue 状态管理工具vuex
|
2月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
65 1
|
2月前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
67 1
|
8月前
|
JavaScript API
【vue实战项目】通用管理系统:api封装、404页
【vue实战项目】通用管理系统:api封装、404页
82 3