美文网首页前端杂货铺
学习用Vuex构建一个Notes App

学习用Vuex构建一个Notes App

作者: loosenRogers | 来源:发表于2019-03-09 17:28 被阅读0次

    Vuex是一套解决vue中组件通信的较完备解决方案。该文通过一个简单的例子来学习如何使用Vuex这个状态管理模块。

    项目地址:vuex-notes-app
    引自:notes-app-vuejs-vuex

    Vuex基础概念

    Vuex是一种全局单例模式管理,所有组件对其共用;同时,将状态变量的定义(State)调用(Getter)以及变更(Mutation/Action)隔离开,是代码书写更加结构化。按照规范去修改状态,这样借助官方提供的devtools,我们便可对mutation进行日志记录,在debug时大有裨益。这边不对每块基础内容进行详情解释,详见官方文档Vuex。下面开始,动手通过Vuex构建一个Notes App吧。

    项目构建

    我们需要实现的Notes App如下:


    Notes App

    需要实现的Note分为三部分:

    1. Toolbar,工具边栏,有add、collect以及delete
    2. NoteList,Notes列表,包含All Notes以及Favorites两个列表,Tab用以切换
    3. Editor,Note编辑区域

    因此,项目也为分割三个组件;同时,我们这次的主题是Vuex,所以我们会将所有的数据都使用Vuex来维护。我们使用vue-cli的simple-webpack搭建一个项目,项目结构如下:


    项目目录结构

    使用Vuex构建Store

    src/store目录下,我么创建一个store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        // 定义所需的状态变量
      },
      getters: {
        // 获取状态数据
      },
      mutations: {
        // 修改状态数据(同步操作)
      },
      actions: {
        // 修改状态数据(异步操作)
      }
    })
    

    为了让所有组件能够更方便地使用store,不需要在组件内频繁手动导入,我们需要在main.js中将其在实例中进行注册

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store/store.js'
    
    new Vue({
      el: '#app',
      store,
      render: h => h(App)
    })
    
    

    接下来,我们来定义需要共享的state
    首先,定义notes: []数组用来存放创建的notes

    • Toolbar中的add/delete需要对其进行增删
    • NoteList需要对其进行列表渲染;

    然后,需要定义activeNote: {}来存放当前正在操作的note

    • Toolbardelete动作会在notes: []中找到activeNote: {}进行删除
    • Toolbarcollect动作会其置位favourite
    • NoteList中列表点击会变更activeNote
    • Editor中会修改activeNote中的内容

    根据以上内容,我们来丰富我们的store中的内容

    state: {
        notes: [],
        activeNote: {}
    },
    mutations: {
        ADD_NOTE (state){
          const newNote = {
            text: "New note",
            favorite: false
          }
          state.notes.push(newNote)
          state.activeNote = newNote
        },
        DELETE_NOTE (state){
          let index = state.notes.indexOf(state.activeNote)
          if(index > -1){
            state.notes.splice(index,1)
          }
          state.activeNote = state.notes[0]
        },
        TOGGLE_FAVORITE (state){
          state.activeNote.favorite = !state.activeNote.favorite
        },
        SET_ACTIVE_NOTE (state, note) {
          state.activeNote = note
        },
        EDIT_NOTE (state, text) {
          state.activeNote.text = text
        }
     }
    

    至此,我们已经定义完了store中的state以及mutation
    下面来看看需要定义哪些getter来获取state

    • NoteList中需要获取notes来渲染全部notes列表以及favoriteNotes来渲染favorite notes列表
    • Editor中需要渲染activeNote中的内容text

    所以, storegetter内容如下:

      getters: {
        notes: state => state.notes,
        activeNote: state => state.activeNote,
        favoriteNotes: state => {
          return state.notes.filter(note => note.favorite)
        }
      }
    

    至此,我们整个store就完工了。接下来,我们会在组件中去调用store中各项内容。

    创建组件

    由于上面,我们已经根据数据以及操作捋好了思路,创建组件的工作就顺其自然了:

    • 切页面
    • 获取store中数据进行渲染
    • 根据页面操作修改store中的数据

    根组件(App.vue)

    <template lang="html">
      <div id="app">
        <toolbar></toolbar>
        <notes-list></notes-list>
        <editor></editor>
      </div>
    </template>
    
    <script>
    import Toolbar from './components/Toolbar.vue'
    import NotesList from './components/NotesList.vue'
    import Editor from './components/Editor.vue'
    
    export default {
      name: 'app',
      components: {
        Toolbar,
        NotesList,
        Editor
      }
    }
    </script>
    

    子组件--Toolbar

    各组件中样式,我们都是沿用了原项目的;样式文件在src/styles.css。在Toolbar中我们需要获取当前正在编辑的activeNote来判断其是否被favorite。由于,我们根组件中注册了store,所以我们不需要再重复引入。当在组件中需要调用多个mutation时,可以使用官方提供的mapMutations来简化书写。

    <template>
      <div id="toolbar">
        <i @click="addNote" class="glyphicon glyphicon-plus"></i>
        <i @click="toggleFavorite"
          class="glyphicon glyphicon-star"
          :class="{starred: activeNote.favorite}"></i>
        <i @click="deleteNote" class="glyphicon glyphicon-remove"></i>
      </div>
    </template>
    
    <script>
    import { mapMutations } from 'vuex'
    
    export default {
      computed: {
        activeNote() {
          return this.$store.getters.activeNote
        }
      },
      methods: {
        ...mapMutations({
          addNote: 'ADD_NOTE',
          deleteNote: 'DELETE_NOTE',
          toggleFavorite: 'TOGGLE_FAVORITE'
        })
      }
    }
    </script>
    

    子组件--NotesList

    同时,当在组件中需要获取多个state时,可以通过mapGetters来简化书写

    <template>
      <div id="notes-list">
    
        <div id="list-header">
          <h2>Notes | coligo</h2>
          <div class="btn-group btn-group-justified" role="group">
            <!-- All Notes button -->
            <div class="btn-group" role="group">
              <button type="button" class="btn btn-default"
                @click="show = 'all'"
                :class="{active: show === 'all'}">
                All Notes
              </button>
            </div>
            <!-- Favorites Button -->
            <div class="btn-group" role="group">
              <button type="button" class="btn btn-default"
                @click="show = 'favorites'"
                :class="{active: show === 'favorites'}">
                Favorites
              </button>
            </div>
          </div>
        </div>
        <!-- render notes in a list -->
        <div class="container">
          <div class="list-group">
            <a v-for="note in filteredNotes"
              class="list-group-item" href="#"
              :class="{active: activeNote == note}"
              @click="updateActiveNote(note)">
              <h4 class="list-group-item-heading">
                {{note.text.trim().substring(0, 30)}}
              </h4>
            </a>
          </div>
        </div>
    
      </div>
    </template>
    
    <script>
    import { mapGetters } from 'vuex'
    
    export default {
      data () {
        return {
          show: 'all'
        }
      },
      computed: {
        ...mapGetters([
          'notes',
          'activeNote',
          'favoriteNotes'
        ]),
        filteredNotes () {
          return this.show === 'all' ? this.notes : this.favoriteNotes
        }
      },
      methods: {
        updateActiveNote(note) {
          this.$store.commit('SET_ACTIVE_NOTE', note)
        }
      }
    }
    </script>
    

    子组件--Editor

    <template>
      <div id="note-editor">
        <textarea
          :value="activeNote.text"
          @input="editNote"
          class="form-control">
        </textarea>
      </div>
    </template>
    
    <script>
    export default {
      computed: {
        activeNote() {
          return this.$store.getters.activeNot
        }
      },
      methods: {
        editNote(e){
          this.$store.commit('EDIT_NOTE', e.target.value)
        }
      }
    }
    </script>
    

    至此,一个基于Vuex进行数据构建的Note App就完成了。具体代码戳这里vuex-notes-app

    参考

    1. notes-app-vuejs-vuex

    相关文章

      网友评论

        本文标题:学习用Vuex构建一个Notes App

        本文链接:https://www.haomeiwen.com/subject/owfspqtx.html