vue 狀態管理(一)

vue 狀態管理(一)

父子組件之間每每使用props$emit 實現數據共享,任意組件可經過bus(一個vue實例)做爲橋樑,實現數據共享。當項目中組件愈來愈多時,組件之間的數據共享變得複雜,難以維護。使用 Vuex 可集中管理組件之間的數據(狀態),使組件之間的數據共享變得簡單。html

父子組件間通訊

父→(props)子組件;子→($meit)父組件,即子組件自定義一個事件,在父組件中監聽該事件。vue

自定義輸入組件:git

<template>
    <input @input="handleInput" :value="value" :placeholder="placeholder" />
</template>
<script>
    export default {
        name: "CustomInput",
        //props 接收父組件傳遞過來的數據
        props: {
            value: {
                type: [Number, String],
                required: true,
                default: ""
            },
            placeholder: {
                type: String,
                default: "提示文本"
            }
        },
        methods: {
            handleInput(event) {
                let val = event.target.value;
                // 子組件的事件監聽函數中觸發一個自定義事件
                this.$emit("customInput", val);
            }
        }
    };
</script>

使用組件:github

<template>
    <div class="store">
        <!-- props 傳遞值 -->
        <custom-input :value="value" @customInput="handleInput" :placeholder="placeholder" />
        <p v-text="value"></p>
    </div>
</template>
<script>
    import CustomInput from '_c/CustomInput.vue'
    export default {
        name: 'Store',
        components: {
            CustomInput
        },
        data() {
            return {
                value: '',
                placeholder: '自定義事件傳遞值'
            }
        },
        methods: {
            //  自定義事假處理器
            handleInput(val) {
                this.value = val
            }
        }
    }
</script>

由於 v-model 指令是雙向綁定的,咱們也能夠用其來實現值的傳遞:web

<template>
    <div class="store">
        <custom-input v-model="inputValue" :placeholder="placeholder" />
        <p v-text="inputValue"></p>
    </div>
</template>
<script>
    import CustomInput from '_c/CustomInput.vue'
    export default {
        name: 'Store',
        components: {
            CustomInput
        },
        data() {
            return {
                inputValue: '',
                placeholder: 'v-mode 傳遞值'
            }
        }
    }
</script>

bus 任意組件通訊

建立一個空的 vue 實例,而後將該實例添加到 vue 的原型上,經過該實例觸發事件監聽事件來在不一樣組件之間共享數據。vuex

//bus.js
import Vue from "vue";
let Bus = new Vue();
export default Bus;

在 main.js 中添加原型屬性:api

import Bus from './lib/bus'
// 經過 bus 實現任意組件傳遞參數
Vue.prototype.$bus=bus
//ChildPage.vue
<template>
    <div id="child-page">
        <h1>{{ msg }}</h1>
        <h3 v-text="data"></h3>
    </div>
</template>
<script>
    export default {
        name: "ChildPage",
        data() {
            return {
                msg: "I am child",
                data: ""
            };
        },
        mounted() {
            // 在掛載聲明周期函數中監聽自定義事件
            this.$bus.$on("customEvent", data => {
                this.data = data;
            });
        }
    };
</script>
<template>
    <div id="app">
        <button @click="sendData">給child傳遞數據</button>
        <p v-text="num"></p>
    </div>
</template>

<script>
    export default {
        name: "App",
        data() {
            return { num: 0 }
        },
        methods: {
            sendData(data) {
                // 由 bus 觸發一個事件,在接收數據的組件中監聽該事件
                this.$bus.$emit('customEvent', ++this.num);
            }
        }
    };
</script>

Vuex 狀態管理

隨着組件的增長,經過以上方式共享數據,會愈來愈複雜,vue 提供了狀態管理插件 Vuex數組

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式;集中存儲和管理應用的全部組件狀態。

理解:緩存

  • 狀態:數據,至關於組件內部的data 的返回值,Vue 是數據驅動的,數據變化每每會表如今視圖層;
  • 集中存儲Vue 只關注視圖層,Vuex 提供了一個倉庫(store)來保存數據,使得數據和視圖分離;
  • 管理:處理保存數據,還可計算、處理數據;
  • 全部組件狀態:全部組件均可獲取倉庫中的數據,即一個項目只有一個數據源。

Vuex 文檔中說:app

經過定義和 隔離狀態管理中的各類概念並經過強制規則維持視圖和狀態間的 獨立性,咱們的代碼將會變得更結構化且易維護。

Vuex 就是經過隔離數據、拆分改變數據的方式使得數據和視圖獨立,數據被組件數共享。

Vuex 狀態圖

虛線內部的三個部分組成了一個Store,組件的數據保存在 State 中,用戶和組件交互時,經過組件內的方法分發(dispatch)一個動做(action,有點像事件),動做會提交(Commit)一個更改(Mutation,也相似事件),改變 State 中的數據,而後獲取數據渲染到視圖上。

  • actions 能夠是 異步操做,故可在action中調用後臺接口獲取新的數據;
  • mutations 只能是 同步操做;
  • mutations 和 actions 均可直接更改 state,可是當 action 含有異步操做時,會使得數據變化混亂,難以跟蹤,使得調試困難;
  • 基於以上緣由,Vuex 規定只能是 mutations 來改變 state。
  • 在開發工具中也可提交 mutations。

使用 vuex

//main.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);// Vuex 是 Vue 的插件

let store = new Vuex.Store({
    state: {     //放置state的值
        count: 0,
        str:"abcd234"
    },
      getters: {   //放置getters方法
          strLen: state => state.str.length
      },
      // mutations只能是同步操做
      mutations: {   //放置mutations方法
       increment(state, payload) {
          //在這裏改變state中的數據
          state.count = payload.number;
       }
      },
      // actions能夠是異步操做
      actions: {      //放置actions方法
           actionName({ commit }) {
              //dosomething
             commit('mutationName')
           },
           getSong ({commit}, id) {
                      //請求後臺數據
              api.getMusicUrlResource(id).then(res => {
                let url = res.data.data[0].url;
              })
              .catch((error) => {  // 錯誤處理
                  console.log(error);
             });
          }
    }
});

new Vue({
  el: '#app',
  store  //  經過 this.store 訪問 store
});

咱們看看 Vuex 和 store 是什麼?

Vuex:

Vuex輸出

Vuex 它其實是一個對象,裏面包含了Store這一構造函數,還有幾個mapActions、mapGetters、mapMutations、mapState、install 方法。

store:

store倉庫

store 是 Vuex 的實例(廢話)。

實際項目中每每將 store 單獨放置的一個文件夾在,mutations 、getters、actions 等屬性各自用一個文件保存。

state

state 對象的屬性時 Vuex 管理的狀態,相似單個組建的 data。

訪問 getters:

  1. this.$store.state
  2. 使用 mapState 映射成計算屬性,推薦
//state.js
export default {
    count: 100,
    name: 'Jack*Zhou',
    firstName: 'Jack',
    lastName: 'Zhou',
    age: 24,
    profession: 'web deveploper',
    company: 'Baidu'
}

組件:

import {mapState} from 'vuex'
export default {
    data(){
        return {
            localCount:0
        }
    },
    computed: {
            localCount() {
                return this.$store.state.count + 1;
            },
            //計算屬性名和 state 屬性名相同:傳入數組
            // ...mapState(['count','name']),
            // 計算屬性名和 state 屬性不一樣,傳入對象
            ...mapState({
                name: state => state.name,
                count: state => state.count,
                countAlias: 'count',
                //爲了使用 this 不能使用箭頭函數
                countPlusLocalCount(state) {
                    return state.count + this.localCount;
                }
            })
        },
}

getters

getters 是對 state 的加工,相似於組件中的 data 和計算屬性的關係。getters 的返回值會被緩存起來,只有當它的依賴改變,纔會從新計算。

訪問 getters:

  1. this.$store.getters
  2. 使用 mapGetters 將 getters 映射成計算屬性,推薦
  3. 方法訪問,不會緩存。
// getters.js
export default {
    fullName: state => state.firstName + ' ' + state.lastName,
    //在getters 中訪問 getters
    info: (state, getters) => {
        return state.age + ',' + getters.fullName;
    },
    //爲了傳遞參數,返回一個函數,
    personInfo: (state, getters) => (city) => {
        return {
            name: getters.fullName,
            age: state.age,
            company: state.company,
            city
        }
    }
}

使用 getters:

import { mapGetters } from 'vuex'
export default {
    name: 'Store',
    computed: {
        ...mapGetters(['fullName', 'info', 'personInfo']),
        myInfo() { return this.personInfo('杭州') },
        ...mapGetters({
            fullNameAlias1: 'fullName',
            //不能寫成函數
            // fullNameAlias2(state){
            //     return state.name+',你好'+this.$store.getters.fullName;
            // }
        })
    },
    mounted() {
        console.log(this.personInfo('成都'))
        console.log(this.myInfo)
    }
}

參考

相關文章
相關標籤/搜索