天天看點

前端開發:Vuex的基本使用

Vue x

為vue.js應用程式開發的狀态管理模式

采用集中式存儲管理應用的所有元件狀态

以相應的規則保證以一種可預測的方式發生變化

應用場景

讀取,多個視圖依賴于同一個狀态

修改,不同視圖的行為需要改變同一個狀态

組成部分

State 資料倉庫

getter 擷取資料

Mutation 修改資料

Action 送出mutation

安裝Vuex

1、安裝vuex包:npm install vuex

2、建立執行個體:new Vuex.store()

3、在main.js中将vuex執行個體挂載到vue對象上

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'

Vue.config.productionTip = false

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        count: 0
    }
})

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

count++示例

思路

1、state中建立count字段

2、mutations中建立一個count++的mutation

3、button新增click事件觸發mutation改變count

main.js

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'

Vue.config.productionTip = false

Vue.use(Vuex)

const store = new Vuex.Store({
    // 狀态資料
    state: {
        count: 0
    },

    // 狀态改變方法
    mutations: {
        // 第一個參數是state, 可以接受第二個參數
        increaseCount(state) {
            state.count++;
        }
    }
})

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

App.vue

<template>
  <div id="app">
    <h1>count: {{count}}</h1>
    <button @click="increaseCount">點我++</button>
  </div>
</template>

<script>
export default {
  name: "app",

  computed: {
    count() {
      // 擷取狀态資料
      return this.$store.state.count;
    }
  },
  
  methods: {
    increaseCount() {
      // 修改狀态資料
      this.$store.commit("increaseCount");
    }r
  }
};
</script>
      

項目實戰

業務目标

1、制作一個需要賬号登入的課程學習項目

2、不同的課程需要不同的會員等級,實作購買會員的功能,課程分享

項目功能

1、通過state.userinfo控制使用者登入路由限制

2、多元件共享state.userStatus 和 state.vipLevel狀态

3、多元件修改state.userstatus 和 state.vipLevel狀态

檔案目錄樹

src
    ├── App.vue
    ├── main.js
    ├── router.js
    ├── store
    │   ├── actions.js
    │   ├── getters.js
    │   ├── index.js
    │   ├── mutations.js
    │   └── state.js
    └── views
        ├── Home.vue
        └── Login.vue      

檔案代碼

<template>
  <div id="app">
    <router-view/>
  </div>
</template>      
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'
import Vant from 'vant';
import 'vant/lib/index.css';

Vue.use(Vant);

Vue.config.productionTip = false

// 前置守衛,權限校驗
router.beforeEach((to, from, next) => {
    if (store.state.username || to.path === "/login") {
        next()
    } else {
        next({
            path: "/login"
        })
    }
})


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

router.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
            path: '/',
            name: 'Home',
            component: Home
        },
        {
            path: '/login',
            name: 'Login',
            component: () =>
                import ('./views/Login.vue')
        }
    ]
})      

store/actions.js

export default {
    buyVip({ commit }, username) {
        return new Promise((resolve, reject) => {
            // 模拟後端互動耗時
            setTimeout(() => {
                commit("setUserInfo", username)
                resolve("購買成功")
            }, 1000)
        })
    }
}      

store/getters.js

export default {
    getUserLevel(state) {
        switch (state.username) {
            case "admin":
                return "管理者";
                
            case "user":
                return "會員";
               
            default:
                return "普通使用者"
                
        }
    }
}      

store/index.js

import Vuex from 'vuex'
import Vue from 'vue'
import state from './state'
import mutations from './mutations'
import getters from './getters'
import actions from './actions'

Vue.use(Vuex)

const store = new Vuex.Store({
    state,
    getters,
    actions, // 異步操作
    mutations // 同步操作
})

export default store      

store/mutations.js

export default {
    setUserInfo(state, username) {
        state.username = username;
    }

}      

store/state.js

export default {
    username: "",
    password: ""
}      

views/Home.vue

<template>
  <div>
    <h1>詳情頁</h1>
    <p>歡迎登入:</p>
    <p>{{this.$store.getters.getUserLevel}}</p>
    <p>{{getUserLevel}}</p>
    <p>{{this.$store.state.username }}</p>
    <p>{{username}}</p>
    <van-button type="primary" @click="byVip" size="large">購買會員</van-button>
  </div>
</template>

<script>
import { mapGetters, mapState } from "vuex";

export default {
  computed: {
    // 解構
    ...mapGetters(["getUserLevel"]),
    ...mapState(["username"])
  },

  methods: {
    byVip() {
      this.$store.dispatch("buyVip", "user").then(res => {
        this.$dialog.alert({
          message: res
        });
      });
    }
  }
};
</script>      

views/Login.vue

<template>
  <div style="margin: 20px;">
    <div style="text-align: center;background-color:#EEEEEE">
      <h1>登入</h1>
    </div>
    <van-cell-group>
      <van-field v-model="username" label="使用者名" placeholder="請輸入使用者名" required />

      <van-field v-model="password" @keyup.enter.native="login" label="密碼" type="password" placeholder="請輸入密碼" required />
      <div style="margin-top:30px">
        <van-button type="primary" @click="login" size="large">登入</van-button>
      </div>
    </van-cell-group>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
      password: ""
    };
  },
  methods: {
    login() {
      if (this.username !== "" && this.password !== "") {
        this.$store.commit("setUserInfo", this.username);
        this.$router.push({
          path: "/"
        });
      } else {
        this.$dialog.alert({
          message: "登入失敗"
        });
      }
    }
  }
};
</script>      

繼續閱讀