Vue

by tawowohzyk

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css">
<div id="app">
    <ul class="nav nav-tabs justify-content-end">
      <li class="nav-item" v-for="(group) in groups" :key="group.id">
        <a class="nav-link active" href="#" @click="activateGroup(group)" v-if="group.id == activeGroupId">
          {{ group.name }} ({{ curMessagesCount }})
        </a>
        <a class="nav-link" href="#" @click="activateGroup(group)" v-else>
          {{ group.name }}
        </a>
      </li>
    </ul>
    <table class="table table-bordered">
      <thead>
        <tr>
          <th>講話的人</th>
          <th>訊息</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="msg in curMessages" :key="msg.id">
          <td>{{ msg.sent_by }}</td>
          <td>{{ msg.content }}</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="2">
            <form class="form-inline">
              <label class="sr-only" for="inlineFormInputName2">Name</label>
              <input type="text" class="form-control mb-2 mr-sm-2" placeholder="..." v-model="newMessage">

              <button type="submit" class="btn btn-primary mb-2" @click.prevent="sendMessage">Submit</button>
            </form>
          </td>
        </tr>
      </tfoot>
    </table>
  </div>

Vue

const MessageStore = {
  namespaced: true,

  // 因為這個 MessageStore 會被重複使用,
  // 透過這種寫法才能讓各個 MessageStore instance 的 state 互相獨立
  // https://vuex.vuejs.org/zh/guide/modules.html#%E6%A8%A1%E5%9D%97%E9%87%8D%E7%94%A8
  state: () => ({
    messages: []
  }),

  getters: {
    messagesCount (state) {
      return state.messages.length;
    }
  },

  // 必須搭配 namespaced:true 這個設定,
  // 否則mutations, actions, getters 都會被註冊在全域
  mutations: {
    addMessage(state, { sent_by, content }) {
      state.messages.push({
        sent_by,
        content,
        id: (new Date).getTime()
      });
    }
  }
};

// 用 root store 來管理群組
// 在動態加入的同時,順便動態註冊MessageStore
const store = new Vuex.Store({
  state: {
    groups: [],
    added: 0,
    activeGroupId: null
  },
  mutations: {
    addGroup (state, group) {
      state.groups.push(group);
      state.added++;
    },
    activateGroup (state, { id }) {
      state.activeGroupId = id;
    },
    // 這種動態註冊 module 的 function 也可以寫在 vue component,
    // 寫在這邊單純是想給需要的人示範在mutation裡面做...
    initMessageStore (state, { id }) {
      // 這邊的 this 指向 root store
      const exists = this.hasModule(['groupMessages', id]);
      if (! exists) {
        this.registerModule(['groupMessages', id], MessageStore);
      }
    },
  },
  getters: {
    // 用現在開啟的groupId找到動態store的state
    curMessages(state) {
      return state.activeGroupId
        ? state.groupMessages[state.activeGroupId].messages
        : [];
    },
    curMessagesCount(state, getters) {
      return state.activeGroupId
        ? getters[`groupMessages/${state.activeGroupId}/messagesCount`]
        : 0;
    }
  },
  modules: {
    // 如果要直接宣告nested module,要確保每一層module都存在,在這邊我就直接宣告了
    // 可以拿掉試試看,會出現『parent is undefined』的訊息唷
    groupMessages: {

      // 你可能會覺得 MessageStore 那邊就有 namespaced:true 的設定了,這邊是不是多餘的?
      // 其實不是
      // 如果拿掉,會出現『[vuex] unknown mutation type: groupMessages/1/addMessage』的錯誤喔
      namespaced: true

    }
  },
});

new Vue({
  el: "#app",
  data: () => {
   ...