vuex-stepbystep 經典案例,詳細註釋一步到位

why前端_小牛_到犀牛發表於2018-12-22

系列文章

Vuex

是什麼(官網已經很完善了)

  • Vuex 是一個 Vue 中的狀態管理工具
  • 狀態,即資料(data)
  • 狀態管理工具就是用來管理 Vue 專案中元件中的資料的

為什麼要使用 Vuex

  • Vuex 只應該在中大型複雜的 Vue 專案中使用
  • 小專案中不需要使用 Vuex

Vuex 的說明

  • Vuex 採用集中的方式統一管理了專案中所有需要共享的資料,只要元件之間相同共享資料就要通過 Vuex 才能實現
  • 可預測性
  • 可以簡單理解為 Vuex 是一個增強版的 bus

狀態管理

  • 前端最早的狀態管理思想是由 React 的 Flux 提出來的
  • Flux 不僅提出了 前端狀態管理的思想,也提供對應的實現
  • 其他狀態管理庫:Flux / Redux / Mobx / Vuex

actions 和 mutations 的區別

Vuex 中的核心概念

  • store

Vuex 的特點

  • Vuex 中的資料也是響應式的(雙向繫結的)

案例搭建

  • 技術點
    • vuex
    • vue-cli 2.0
    • todos 模板
  • 專案目錄

vuex-stepbystep 經典案例,詳細註釋一步到位

  • 然後我們開始搭建專案,使用vue-cli的步驟,就跳上過了,樓主在vue-admin教程中有詳細步驟,現在我們在src目錄下新建store資料夾,然後新建index.js檔案,然後我們初始化store,程式碼如下

vuex-stepbystep 經典案例,詳細註釋一步到位

import Vue from 'vue'//引入vue
import Vuex from 'vuex'//引入vuex

// 安裝
Vue.use(Vuex)

// 初始化state
const state = {}

// mutations
const mutations = {}

// 建立store把state和mutation 寫入Vuex.store中
const store = new Vuex.Store({
  state,
  mutations
})

export default store //匯出store
複製程式碼
  • 然後我們在main.js引入,掛載到vue的例項中
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'

// 匯入樣式
import '@/assets/index.css'

// 匯入store
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 將 Vuex(store) 和 Vue例項關聯到一起
  store,
  components: { App },
  template: '<App/>'
})

複製程式碼
  • 然後配置App.vue,把todos模板元件匯入App.vue中,我們的store就配置好了
    vuex-stepbystep 經典案例,詳細註釋一步到位

功能完成

  • 效果圖 (ps:經典到吐)
    vuex-stepbystep 經典案例,詳細註釋一步到位
  • 我們現在完善store,把資料填入,進行增刪更新的一些狀態的統一操作。
import Vue from 'vue'//引入vue
import Vuex from 'vuex'//引入vuex

// 安裝
Vue.use(Vuex)

// 初始化state
const state = {
  todos: [
    { id: 1, name: '禿頭', done: false },
    { id: 2, name: '女朋友跑了', done: false },
    { id: 3, name: '左手更加的有力', done: true }
  ]
}

// mutations配置
const mutations = {
  // 根據id修改完任務的成狀態
  changeDone(state, payload) {
    // 1 根據id找到當前任務
    const curTodo = state.todos.find(item => item.id === payload.id) //箭頭函式了解下
    // 2 狀態直接取反即可
    curTodo.done = !curTodo.done
  },

  // 新增任務方法
  addTodo(state, payload) {
    const length = state.todos.length
    const id = length === 0 ? 1 : state.todos[length - 1].id + 1

    state.todos.push({
      id,
      name: payload.name,
      done: false
    })
  },

  // 刪除任務方法
  delTodo(state, payload) {
    state.todos.splice(payload.index, 1)
  },

  // 更新任務方法
  updateTodo(state, payload) {
    // 查詢到當前要更新的任務
    const curTodo = state.todos.find(item => item.id === payload.id)
    // 修改名稱
    curTodo.name = payload.name
  },

  // 清除已完成任務
  clearAllDone(state) {
    state.todos = state.todos.filter(item => !item.done)
  }
}

// actions 非同步操作(面試考察點)
// 內部還是提交的 mutations
const actions = {
  // 非同步新增任務
  addTodoAsync(context, payload) {
    // setTimeout就是一個非同步操作, 內部還是提交的 mutations
    setTimeout(() => {
      context.commit('addTodo', {
        name: payload.name
      })
    }, 2000)
  }
}

// getters
// 相當於Vue元件中的 計算屬性 ,用法完全相同
// 當需要從現有的state中得到一些新的資料(比如:從 todos 集合中,得到未完成任務數量)
// 就要使用 getters ,也就是計算屬性
const getters = {
  // 未完成任務數量
  unDoneCount(state) {
    return state.todos.filter(item => !item.done).length
  },

  // 控制清除已完成任務按鈕的展示和隱藏
  showClearDone(state) {
    return state.todos.some(item => item.done)
  }
}

// 建立store
const store = new Vuex.Store({
  // 開啟嚴格模式
  // 開發期間 NODE_ENV 的值為: 'development'
  // 生成環境中 NODE_ENV 的值為: 'production'
  strict: process.env.NODE_ENV !== 'production',
  state,
  mutations,
  actions,
  getters
})

export default store

複製程式碼
  • 然後我們進行TodoHeader的新增操作
    vuex-stepbystep 經典案例,詳細註釋一步到位
<template>
  <header class="header">
    <h1>todos</h1>
    <input 
      <!--資料繫結,對應data中的資料-->
		v-model="todoName" 
		<!--enter修飾符,繫結時間-->
		@keyup.enter="addTodo"
		 class="new-todo" 
		 placeholder="What needs to be done?"
		 <!--自動聚焦-->
		 autofocus>
  </header>
</template>

<script>
export default {
  data() {
    return {
      // 因為這個資料只會在當前元件中使用
      // 因此,就不需要放到 Vuex 中
      todoName: ''
    }
  },

  methods: {
    // 新增任務
    addTodo() {
    //input輸入框通常我們會trim一下,把空格幹掉
      if (this.todoName.trim() === '') {
        return
      }

      // 呼叫 Vuex 中提供的 mutations 即可(在元件中,通過$store.commit方法來執行mutation)
      // this.$store.commit('addTodo', {
      //   name: this.todoName
      // })

      // 呼叫 actions 來完成,非同步新增(action在元件內通過$store.dispatch觸發)
      this.$store.dispatch('addTodoAsync', {
        name: this.todoName
      })

      this.todoName = ''//完成之後,清空input框的內容
    }
  }
}
</script>
複製程式碼
  • 然後我們操作列表元件TodoList

vuex-stepbystep 經典案例,詳細註釋一步到位

<template>
  <section class="main">
    <input id="toggle-all" class="toggle-all" type="checkbox">
    <label for="toggle-all">Mark all as complete</label>
    <ul class="todo-list">
      <!--
        完成狀態: completed
        編輯狀態: editing
       -->
      <li 
			:class="{ completed: todo.done, editing: todo.id === editId }"
			 v-for="(todo, index) in $store.state.todos" 
			 :key="todo.id">
        <div class="view">
          <!--
            前提:因為我們知道 Vuex 中的資料,只能通過 mutations 中提供的方法來修改
            因為在 checkbox 中使用了 v-model,v-model是雙向繫結的,當點選 核取方塊 的時候,會將其對應的資料修改,
            這樣就違背了 Vuex 中資料只能由 mutations 修改這個原則了!!!

            資料 -> 檢視: :checked="todo.done" (單向)
            檢視 -> 資料: 先繫結一個事件,在事件中呼叫 mutations 來完成資料修改
           -->
          <input 
					class="toggle"
					 type="checkbox"
					 :checked="todo.done"
					 @change="changeDone(todo.id)">
          <!-- <input class="toggle" type="checkbox" v-model="todo.done"> -->
          <label @dblclick="showEditStatus(todo.id)">{{ todo.name }}</label>
          <button class="destroy" @click="delTodo(index)"></button>
        </div>
        <input class="edit" :value="todo.name" @keyup.enter="updateTodo(todo.id, index)" ref="todoUpdate">
      </li>
    </ul>
  </section>
</template>

<script>
export default {
  data() {
    return {
      // 臨時變數,用來處理編輯狀態
      editId: -1
    }
  },
  methods: {
    // 出現編輯狀態
    showEditStatus(id) {
      this.editId = id
    },

    // 更新任務名稱
    updateTodo(id, index) {
      // 根據索引號找到對應的文字框
      const name = this.$refs.todoUpdate[index].value

      this.$store.commit('updateTodo', {
        id,
        name
      })

      // 去掉編輯狀態
      this.editId = -1
    },

    // 切換完成狀態
    changeDone(id) {
      // 呼叫 mutations 中提供的方法,來修改state中的資料
      this.$store.commit('changeDone', {
        id
      })
    },

    // 刪除任務
    delTodo(index) {
      this.$store.commit('delTodo', {
        index
      })
    }
  }
}
</script
<style>
</style>

複製程式碼
  • 底部就一個清除,直接貼程式碼了
export default {
  methods: {
    // 清除所有已完成任務
    clearAllDone() {
      this.$store.commit('clearAllDone')
    }
  }
}
複製程式碼

結語

  • 我看了有些,博文,感覺把vueX都神話了,各位小夥伴把我這篇教程看完,其實就這些東西。
  • 大專案確實很方便,具體使用:按需使用。

相關文章