十、Vue:Vuex實現data(){}內數據多個組件間共享


一、概述

官方文檔:https://vuex.vuejs.org/zh/installation.html

1.1vuex有什么用

Vuex:實現data(){}內數據多個組件間共享一種解決方案(類似react的redux)

1.2什么情況下使用vuex

	雖然 Vuex 可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。
	如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗余的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 global event bus 就足夠您所需了。但是,如果您需要構建是一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇。

1.3Vuex狀態管理

	view ->(dispatch) Action ->(Commit) Mutations ->(Mutate) State -> View
	注意:Action不是必需品,如果有異步操作才可能用到Action,否則可以不使用

1.4Actions:

	Action 提交的是 mutation,而不是直接變更狀態。
	Action 可以包含任意異步操作。

二、安裝及使用

官方文檔:https://vuex.vuejs.org/zh/installation.html

安裝方法1,npm

cnpm install vuex --save
或
npm install vuex --save

安裝方法2,cdn

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

其它略過,見文檔。

【使用】

在一個模塊化的打包系統中,您必須顯式地通過 Vue.use() 來安裝 Vuex:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

當使用全局 script 標簽引用 Vuex 時,不需要以上安裝過程。

2.1 vuex定義共享數據和引用 state:{}

應用場景: 例如在購物車中,你在商品詳情頁進行加減庫存操作,而到購物車詳情中時,用之前學得的data(){}內數據用法,你是得不到商品詳情里的商品數量這個數據的,此時就引入了state:{}做為所有頁面的共享數據,加減商品都可使用此處的數據,從而實現數據的共享。
代碼實例
(多余代碼為父子組件互傳值復習)

第1步,引入vuex並創建store實例 src/main.js

[1]引入vuex
[2]使用vuex
[3]創建一個store實例(主要)
[4]所有組件共用數據存放處
[5]注入store(重要)

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex' //[1]引入vuex

Vue.use(Vuex)//[2]使用vuex

//[3]創建一個store實例
const store=new Vuex.Store({
  state:{//[4]所有組件共用數據存放處
    count:10
  }
})

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

第2步,引用1步所創建的共享數據count(src/components/home.vue)

【1】獲取store里的共享數據方法1直接調用(this.$store.state.count)

<template>
  <div>
    <Hello :title='msg' @msg='getmsg'/><br/>
    {{msg2}}<br/>
    <!-- 【1】獲取store里的共享數據方法1 -->
    home:獲取vuex的store共用數據:{{this.$store.state.count}}
  </div>
</template>

<script>
import Hello from './hello.vue';

  export default{
    name:'home',
    data(){
      return{
        msg:'Home向Hello傳的消息',
        msg2:''
      }
    },
    components:{Hello},
    methods:{
      getmsg(data){
        this.msg2=data;
      }
    }
  }
</script>

<style>
</style>

第2.2步,其它組件都可以引用共享數據

src/components/hello.vue
【1】寫一個函數獲取vuex並返回store共享數據
【2】獲取vuex的store共享數據方法2(在computed內寫一個獲取函數,再調用)

<template>
  <div>
    <!--【2】獲取vuex的store共享數據方法2 -->
    hello子組件:{{getCount}}----{{title}}<br/>
    <button @click="sendMsg">給父組件傳消息</button>
  </div>
</template>

<script>
export default{
  name:'hello',
  data(){
    return{
      msg:'Hello子組件向父組件傳數據'
    }
  },
  props:{
    title:{
      type:String,
      default:''
    }
  },
  computed:{
    //【1】寫一個函數獲取vuex並返回store共享數據
    getCount(){
      return this.$store.state.count
    }
  },
  methods:{
    sendMsg(){
      this.$emit('msg',this.msg)
    }
  }
}
</script>

<style>
</style>

效果:成功獲取到在mian.js內定義的count數據值

10

2.2 修改共享數據實例 mutaitions:{}

第1步,定義修改共享數據的函數 main.js

[6]更改state里的數據在mutations里寫函數操作
[6.1.0]自加函數,用於其它組件操作數據通過 this.\(store.commit('increment') [6.1.1]自減函數,用於其它組件操作數據通過 this.\)store.commit('decrement')

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex' //[1]引入vuex

Vue.use(Vuex)//[2]使用vuex

//[3]創建一個store實例
const store=new Vuex.Store({
  state:{//[4]所有組件共用數據存放處
    count:10
  },//[6]更改state里的數據在mutations里寫函數操作
  mutations: {
    increment (state) {//[6.1.0]自加函數,用於其它組件操作數據通過 this.$store.commit('increment')
      state.count++
    },
    decrement(state){//[6.1.1]自減函數,用於其它組件操作數據通過 this.$store.commit('decrement')
      state.count--
    }
  }
})

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

第2步,在組件中使用1步定義的修改共享數據函數 home.vue

【1】使用mutations里定義好的函數進行共享數據自加操作
【1.1】使用mutations里定義好的函數進行共享數據自減操作
【2】修改共享數據自加
【2.1】修改共享數據自減

<template>
  <div>
    <Hello :title='msg' @msg='getmsg'/><br/>
    {{msg2}}<br/>
    <!-- 獲取store里的共享數據方法1 -->
    home:獲取vuex的store共用數據:{{this.$store.state.count}}<br/><br/>

    <button @click='add'>加store.state里數據</button> <!-- 【2】修改共享數據自加 -->
    <button @click="sub">減</button> <!-- 【2.1】修改共享數據自減 -->

  </div>
</template>

<script>
import Hello from './hello.vue';

  export default{
    name:'home',
    data(){
      return{
        msg:'Home向Hello傳的消息',
        msg2:''
      }
    },
    components:{Hello},
    methods:{
      add(){//【1】使用mutations里定義好的函數進行共享數據自加操作
        this.$store.commit('increment')
      },
      sub(){//【1.1】使用mutations里定義好的函數進行共享數據自減操作
        this.$store.commit('decrement')
      },
      getmsg(data){
        this.msg2=data;
      }
    }
  }
</script>

<style>
</style>

hello.vue 不重要

<template>
  <div>
    <!--獲取vuex的store共享數據方法2 -->
    hello子組件:{{getCount}}----{{title}}<br/>
    <button @click="sendMsg">給父組件傳消息</button>
  </div>
</template>

<script>
export default{
  name:'hello',
  data(){
    return{
      msg:'Hello子組件向父組件傳數據'
    }
  },
  props:{
    title:{
      type:String,
      default:''
    }
  },
  computed:{
    //寫一個函數獲取vuex並返回store共享數據
    getCount(){
      return this.$store.state.count
    }
  },
  methods:{
    sendMsg(){
      this.$emit('msg',this.msg)
    }
  }
}
</script>

<style>
</style>

效果:點加按鈕會進行共享數據自加操作,減則自減

注意:數據變更后,所有地方數據都會自動進行變更
在這里插入圖片描述

2.3 actions的使用

Actions:
Action 提交的是 mutation,而不是直接變更狀態。
Action 可以包含任意異步操作。
mutaitions內只能執行同步操作。

src/main.js 定義actions:{}內函數

【1】用動作操作mutations里函數

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex' //[1]引入vuex

Vue.use(Vuex)//[2]使用vuex

//[3]創建一個store實例
const store=new Vuex.Store({
  state:{//[4]所有組件共用數據存放處
    count:10
  },//[6]更改state里的數據在mutations里寫函數操作
  mutations: {
    increment (state) {//[6.1.0]自加函數,用於其它組件操作數據通過 this.$store.commit('increment')
      state.count++
    },
    decrement(state){//[6.1.1]自減函數,用於其它組件操作數據通過 this.$store.commit('decrement')
      state.count--
    }
  },
  actions:{//【1】用動作操作mutations里函數
    increment(context){//context承上啟下
      context.commit('increment');
    },
    decrement(context){
      context.commit('decrement');
    }
  }
})

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

src/components/home.vue 調用actions內的函數

【1】使用main.js里actions里定義好的函數進行共享數據自加操作
【1.1】使用main.js里action里定義好的函數進行共享數據自減操作
this.$store.dispatch('decrement')

<template>
  <div>
    <Hello :title='msg' @msg='getmsg'/><br/>
    {{msg2}}<br/>
    <!-- 獲取store里的共享數據方法1 -->
    home:獲取vuex的store共用數據:{{this.$store.state.count}}<br/><br/>

    <button @click='add'>加store.state里數據</button> <!-- 【2】修改共享數據自加 -->
    <button @click="sub">減</button> <!-- 【2.1】修改共享數據自減 -->

  </div>
</template>

<script>
import Hello from './hello.vue';

  export default{
    name:'home',
    data(){
      return{
        msg:'Home向Hello傳的消息',
        msg2:''
      }
    },
    components:{Hello},
    methods:{
      add(){//【1】使用main.js里actions里定義好的函數進行共享數據自加操作
        // this.$store.commit('increment')
        this.$store.dispatch('increment')
      },
      sub(){//【1.1】使用main.js里action里定義好的函數進行共享數據自減操作
        // this.$store.commit('decrement')
        this.$store.dispatch('decrement')
      },
      getmsg(data){
        this.msg2=data;
      }
    }
  }
</script>

<style>
</style>

效果:同上,操作共享數據,1加,2減

在這里插入圖片描述

2.3.1 actions內執行異步操作

src/main.js actions:{}內進行異步模擬

【異步】異步操作模擬,利用setTimeout函數延遲1秒執行自加操作

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex' //[1]引入vuex

Vue.use(Vuex)//[2]使用vuex

//[3]創建一個store實例
const store=new Vuex.Store({
  state:{//[4]所有組件共用數據存放處
    count:10
  },//[6]更改state里的數據在mutations里寫函數操作
  mutations: {
    increment (state) {//[6.1.0]自加函數,用於其它組件操作數據通過 this.$store.commit('increment')
      state.count++
    },
    decrement(state){//[6.1.1]自減函數,用於其它組件操作數據通過 this.$store.commit('decrement')
      state.count--
    }
  },
  actions:{
    increment(context){
      // context.commit('increment');
      setTimeout(function(){ //【異步】異步操作模擬,利用setTimeout函數延遲1秒執行自加操作
        context.commit('increment');
      },1000)
    },
    decrement(context){
      context.commit('decrement');
    }
  }
})

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

src/components/home.vue

代碼同上例,略過

效果同上例略過

2.4 getter:{}的使用

應用場景:例如在購物車中,利用2.3例的自減減少庫存,當減少到0時還可以繼續減為負數,此時商家將要向用戶倒找錢,這樣顯然不合理。因此引入getter函數;

src/main.js 寫 getters用於控制共享數據

【getter】用於控制共享數據的使用
如果count數據大於0則返回count,否則只返回0(小於0時只返回0)

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex' //[1]引入vuex

Vue.use(Vuex)//[2]使用vuex

//[3]創建一個store實例
const store=new Vuex.Store({
  state:{//[4]所有組件共用數據存放處
    count:10
  },
  getters:{//【getter】用於控制共享數據的使用
    controlState(state){ //如果count數據大於0則返回count,否則只返回0(小於0時只返回0)
      return state.count > 0 ? state.count : 0
    }
  },
  //[6]更改state里的數據在mutations里寫函數操作
  mutations: {
    increment (state) {//[6.1.0]自加函數,用於其它組件操作數據通過 this.$store.commit('increment')
      state.count++
    },
    decrement(state){//[6.1.1]自減函數,用於其它組件操作數據通過 this.$store.commit('decrement')
      state.count--
    }
  },
  actions:{
    increment(context){
      // context.commit('increment');
      setTimeout(function(){ //異步操作模擬,利用setTimeout函數延遲1秒執行自加操作
        context.commit('increment');
      },1000)
    },
    decrement(context){
      context.commit('decrement');
    }
  }
})

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

src/components/home.vue

【getters-1】通過computed寫函數來獲取store里的共享數據方法
【getters-2】通過computed寫函數來顯示store里的共享數據

<template>
  <div>
    <Hello :title='msg' @msg='getmsg'/><br/>
    {{msg2}}<br/>
    <!-- 【getters-2】通過computed寫函數來顯示store里的共享數據 -->
    home:獲取vuex的store共用數據:{{getState}}<br/><br/>

    <button @click='add'>加store.state里數據</button> <!--修改共享數據自加 -->
    <button @click="sub">減</button> <!--修改共享數據自減 -->

  </div>
</template>

<script>
import Hello from './hello.vue';

  export default{
    name:'home',
    data(){
      return{
        msg:'Home向Hello傳的消息',
        msg2:''
      }
    },
    components:{Hello},
    computed:{//【getters-1】通過computed寫函數來獲取store里的共享數據方法
      getState(){
        return this.$store.getters.controlState;
      }
    },
    methods:{
      add(){//使用mutations里定義好的函數進行共享數據自加操作
        // this.$store.commit('increment')
        this.$store.dispatch('increment')
      },
      sub(){//使用mutations里定義好的函數進行共享數據自減操作
        // this.$store.commit('decrement')
        this.$store.dispatch('decrement')
      },
      getmsg(data){
        this.msg2=data;
      }
    }
  }
</script>

<style>
</style>

效果:加了用getter獲取數據2處最多只能減到0,沒加的,3還是會返回負數

在這里插入圖片描述

2.5 moudel模塊操作

官方文檔:https://vuex.vuejs.org/zh/guide/modules.html

由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。當應用變得非常復雜時,store 對象就有可能變得相當臃腫。

為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

2.6 store提取為單獨文件

也可參考 router
具體步驟:

  1. 新建一個src/store文件夾
  2. 在建立一個文件/src/store/index.js
  3. 把store提取到2步建好的文件
  4. 在main.js里引入store文件

/src/store/index.js

【1】注意導出:創建一個store倉庫

import Vue from "vue"
import Vuex from 'vuex'

Vue.use(Vuex)

// 【1】注意導出:創建一個store倉庫
export default new Vuex.Store({
	state: {
		count: 10
	},
	mutations: {
		increment(state) {
			state.count++;
		},
		decrement(state) {
			state.count--;
		}
	},

	actions: {
		// context:承上啟下
		increment(context) {
			setTimeout(function() {
				context.commit("increment");
			})
		},
		decrement(context) {
			setTimeout(function() {
				context.commit("decrement");
			})
		}
	},
	getters: {
		controlState(state) {
			return state.count > 0 ? state.count : 0
		}
	}
});

main.js

【1】全局引入store文件

import Vue from 'vue'
import App from './App.vue'
import store from './store/index.js' //【1】全局引入store文件

new Vue({
  el: '#app',
  store,//[5]注入store
  render: h => h(App)
})

效果:同上例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM