Vuex的一些理解

Vuex图解 


组件调用 actions, fetchTodos 加载数据:多个操作, 进度条开始转圈,发送网络请求, 获得数据,加载完成,进度条定制转圈, 显示数据


action中调用的第一个 mutation : 修改加载状态, notLoading ---> Loading 


 

axios HTTP客户端,网络库, Http GET 请求



请求成功后:

 

 



 








index.html

<!doctype html>
<html lang="en">
  <head>
    <title>Vuex 备忘录</title>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  </head>
  <body>
    
    <div id="app"></div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

List.vue

<template>
  <ul class="list-group mt-5">

    <!-- todos 不是 props, 不是 data, 是 vuex Store 中 state -->
    <!-- 通过 mapState 获得 -->
    <li
      v-for="(item, index) in todos" :key="index"
      class="list-group-item">{{item}}

      <!-- 方案一 -->
      <!-- <button
        @click="rm(index)"
        type="button" 
        class="btn btn-outline-danger btn-sm float-right">X</button>   -->

      <!-- 方案二 -->
      <!-- 通过 mapActions, 在事件处理中直接回调 actions 中的方法 -->
      <button
        @click="removeTask(index)"
        type="button" 
        class="btn btn-outline-danger btn-sm float-right">X</button>  

    </li>
  </ul>
</template>

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

export default {
  name: 'List',

  // 获得状态的 方案一
  // computed: {
  //   list: function() {
  //     // this 当前 Vue 实例
  //     return this.$store.state.todos;
  //   }
  // },

    // 获得状态的 方案二
    computed: mapState(
      [
        'todos'
      ]
    ),


  // 调用 action 方案一
  // methods: {
  //   rm: function(i) {
  //     // action
  //     // 繁琐
  //     this.$store.dispatch('removeTask', i);
  //   },
  // }

  // 方案二
  // mapActions: 映射到 actions
  // 在当前组件中,直接调用 vuex 中定义的 action
  // 不再需要定义 rm 方法间接的调用 $store.dispatch()
  methods: mapActions(
    [
      'removeTask'
    ]
  )

}
</script>

Todo.vue

<template>
  <div class="mt-5">
    <!-- 输入框 -->
    <div class="form-group">
      <input
          v-model="task"
          type="text"
          class="form-control form-control-sm"
          :placeholder="$store.state.input_hint">
    </div>
    <!-- 按钮 -->
    <button
      @click="newTask"
      type="button"
      class="btn btn-primary btn-lg btn-block">创建</button>
  </div>
</template>

<script>
export default {
  name: 'Todo',
  data() {
    return {
      task: ''
    }
  },
  methods: {
    newTask: function() {
      // vue 原始 事件冒泡
      // this.$emit('event', this.task);

      // vuex
      // 可以,但是不推荐:子组件中直接操作状态
      // this.$store.state.todos.unshift(this.task);

      // vuex 推荐 mutations
      // 1) 回调
      // 2)负载的数据(对象)
      // this.$store.commit('createTask', this.task);

      // 最佳实践
      // event --> action --> mutation --> state --> View(组件)
      // 分发(dispatch)给 action
      this.$store.dispatch('createTask', this.task);


      // 负载
      // this.$store.commit(
      //   'createTask', 
      //   {
      //     a: 1,
      //     b: 2,
      //     info: this.task
      //   }
      // );

      // 组件中的方法修改状态 store.state
      // 提交到 变化/突变
      // this.$store.commit('mutation');    // 1  简单的同步场景
      // 分发到 动作/行为
      // this.$store.dispatch('action');    // 2  复杂的所有场景,包含了 1

    }
  }
}
</script>

index.js

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

// 引入常量
import { CREATE_TASK, REMOVE_TASK, OTHER } from "./mutation_name";

// Vue 启用了 Vuex 插件,进行集中式的状态管理
Vue.use(Vuex)

export default new Vuex.Store({
  // 状态(集中所有组件的状态数据)
  // 状态是 响应式(双向绑定的)
  state: {
    title: '备忘录 | Vuex',
    input_hint: '今日事今日毕',
    todos: ['起床', '吃饭', '打豆豆']
  },
  // 同步执行的操作,提供给 action 调用 (commit)
  mutations: {
    REMOVE_TASK(state, n) {
      state.todos.splice(n, 1);
    },
    CREATE_TASK(state, data) {
      state.todos.push(data);
    },
    OTHER(state) {
      console.log('mutation other ' + state.title);
    }
  },
  // 可以包含多个 mutations 的(异步)操作,推荐调用 actions
  actions: {
    // action 第一个参数为 context (上下文)
    // context.commit() 调用 mutation
    createTask(context, data) {
      // action 提交给 mutation (名字是常量)
      context.commit(CREATE_TASK, data);
      context.commit(OTHER);
    },
    // context 调用 mutation
    removeTask(context, id) {
      context.commit(REMOVE_TASK, id);
    }
  },
  // 模块化状态管理(拆分成多个文件分别维护和管理)
  modules: {
  },
  // 读取状态信息
  getters: {
    // 函数定义
    appTitle: function(state) {
      return state.title;
    },
    // 箭头函数,一个参数时,括号可选
    titleInfo: (state) => {
      return state.title;
    }
  }
})

mutation_name.js

// mutations 的名字(一种建议,不是强制的
export let CREATE_TASK = 'CREATE_TASK';
export let REMOVE_TASK = 'REMOVE_TASK';
export let OTHER = 'OTHER';

App.vue

<template>
  <div class="container">
    
    <div class="jumbotron">

      <!-- 方案一:间接、直接 -->
      <!-- 直接访问状态:$store.state -->
      <!-- <h1 class="display-4">{{ $store.state.title }}</h1> -->
 
      <!-- 方案二:多定义的一个函数,【画蛇添足】-->
      <!-- 通过 getters 方式:$store.getters -->
      <!-- <h1 class="display-4">{{ $store.getters.titleInfo }}</h1> -->

      <!-- 方案三:在方案二的基础上 mapGetters -->
      <!-- <h1 class="display-4">方案三</h1> -->
      <h1 class="display-4">{{ titleInfo }}</h1>
      <!-- <h1 class="display-4">{{ appTitle }}</h1> -->

    </div>

    <Todo />

    <List />

  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'
import Todo from "./components/Todo";
import List from "./components/List";

// 导入 getters 映射,启用方案三
import { mapGetters } from "vuex";

export default {
  name: 'App',
  components: {
    Todo,
    List  
  },
  // 方案三
  computed: mapGetters(
    [
      'appTitle',
      'titleInfo'
    ]
  )
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

main.js

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

// 导入了 store
import store from './store'

Vue.config.productionTip = false

// 程序中的 Vue 实例
new Vue({
  // this.$store
  store,
  render: h => h(App)
}).$mount('#app')

效果如图所示:

​​​​​​​

发布了113 篇原创文章 · 获赞 130 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44364444/article/details/104500592
今日推荐