溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用

發(fā)布時(shí)間:2021-08-10 11:47:24 來(lái)源:億速云 閱讀:115 作者:小新 欄目:web開發(fā)

小編給大家分享一下如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

開始吧

以下是 notes-vuex-app 的源文件目錄:

 如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用

在使用 vue 2 重寫這個(gè) app 之前,我在想能不能不改變文件目錄結(jié)構(gòu)以及配置位置呢?就是用比較生硬的方式重寫,或者說單純的語(yǔ)法修改。事實(shí)是可行的,否則我就不會(huì)寫這篇文章了。然而面對(duì)的問題非常多,但卻因此深入的理解了 vue 以及 vuex。最大的問題是 webpack 的構(gòu)建,如果使用 webpack 2.0+的話,坑比較多。本人是菜鳥,所以最終選擇了 vue-cli 提供的兩個(gè) webpack 的模板,分別是 webpack-simple 和 webpack,我先使用 webpack-simple,它和原 app 的結(jié)構(gòu)基本吻合。目錄如下:

如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用

使用 vue-cli 生成基本目錄之后,再安裝 vuex2 。

main.js 的小改動(dòng)

原示例 main.js 如下所示,但運(yùn)行出錯(cuò)了,主要是 Vue 2 的根實(shí)例渲染稍有變化

import Vue from 'vue'
import store from './vuex/store'
import App from './components/App.vue'

new Vue({
 store, // 注入到所有子組件
 el: 'body',
 components: { App }
})

改正之后: 

import Vue from 'vue'
import store from './vuex/store'
import App from './components/App.vue'

new Vue({
  store, // inject store to all children
  el: '#app',
  template: '<App/>',
  components: { App }
})

或者

import Vue from 'vue'
import store from './vuex/store'
import App from './components/App.vue'

new Vue({
  store, // inject store to all children
  el: '#app',
  render: h => h(App)
})

vuex 2 的變化

這個(gè)應(yīng)用改寫的主要問題集中在 vuex 2 的變化上,這些變化確實(shí)會(huì)讓人感到凌亂,我無(wú)數(shù)次抓耳撓腮的罵娘。不過通過官方給出的示例也可以看出一些端倪。

首先是 action.js,只需注意一點(diǎn),所有的 dispatch 都要改成 commit。

export const addNote = ({ commit }) => {
 commit('ADD_NOTE')
}

export const editNote = ({ commit }, e) => {
 commit('EDIT_NOTE', e.target.value)
}

export const deleteNote = ({ commit }) => {
 commit('DELETE_NOTE')
}

export const updateActiveNote = ({ commit }, note) => {
 commit('SET_ACTIVE_NOTE', note)
}

export const toggleFavorite = ({ commit }) => {
 commit('TOGGLE_FAVORITE')
}

store.js 變化也不大,但是要注意幾個(gè)地方:

import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'

Vue.use(Vuex)

const state = {
 notes: [],
 activeNote: {}
}

const mutations = {
 ADD_NOTE (state) {
  const newNote = {
   text: 'New note',
   favorite: false
  }
  state.notes.push(newNote)
  state.activeNote = newNote
 },

 EDIT_NOTE (state, text) {
  state.activeNote.text = text
 },

 DELETE_NOTE (state) {
  state.notes.splice(state.notes.indexOf(state.activeNote),1)
  state.activeNote = state.notes[0] || {}
 },

 TOGGLE_FAVORITE (state) {
  state.activeNote.favorite = !state.activeNote.favorite
 },

 SET_ACTIVE_NOTE (state, note) {
  state.activeNote = note
 }
}

const getters = {
 notes: state => state.notes,
 activeNote: state => state.activeNote,
 activeNoteText: state => state.activeNote.text
}

export default new Vuex.Store({
 state,
 mutations,
 actions,
 getters
})

 原示例文件中沒有將 getters 寫到 store.js 中,而是直接在組件中定義的。為了更清晰,我仿照官方示例也提取出來(lái)寫在了 store.js 中,這樣在組件中調(diào)用時(shí)比較方便。其次也引入了 action.js,并作為 actions 對(duì)象傳遞給 Vuex.store(),這算是 vuex 的標(biāo)準(zhǔn)寫法吧,對(duì)于后面在組件中調(diào)用比較有利。

其中要注意 DELETE_NOTE (state){} 這個(gè)方法,原示例使用了 vue1 提供的 remove 方法,但是 vue2 中去掉了這個(gè)方法。仔細(xì)想想就會(huì)明白,這個(gè)函數(shù)的作用就是刪除 notes 數(shù)組中的元素??梢允褂迷?splice 方法。如果 JS 基礎(chǔ)扎實(shí)的話,這里應(yīng)該很好理解,沒有什么大問題。其次相比原示例,添加一個(gè)刪除后操作的判斷。

我之前一直不太理解 flux 的概念,感覺像是新東西,完全不知道它的目的及作用。換成 Vuex,還是有點(diǎn)稀里糊涂。但是通過修改這個(gè)示例,基本算是開竅了。這些東西本身并沒有玄機(jī)奧妙,想一想,如果我們不用框架,而是自己手寫一個(gè) todoMVC 時(shí)要怎么做?應(yīng)該也是這樣的思路,定義一個(gè) notes 數(shù)組變量以及 activeNote 的變量。然后在創(chuàng)建一些改變狀態(tài)的方法。我在面試中遇到過一個(gè)情況,面試官反復(fù)問我為什么需要使用框架,用 jQuery 不是也可以實(shí)現(xiàn)嗎?這樣說確實(shí)沒錯(cuò),用比較原始的方法當(dāng)然可以做,只是代碼結(jié)構(gòu)會(huì)冗余或者凌亂,缺少小而美的特點(diǎn)??蚣芤约霸O(shè)計(jì)模式對(duì)代碼做了整合封裝,對(duì)于一個(gè) CURD 應(yīng)用比較友好,實(shí)現(xiàn)起來(lái)更方便更簡(jiǎn)單。我對(duì)于 Vuex 的理解就是,它是一個(gè)對(duì)象,封裝了與狀態(tài)相關(guān)的方法和屬性。而所謂的狀態(tài)就是點(diǎn)擊、按鍵等操作之后的變化。

組件中使用 vuex

先看一下 Toolbar.vue 這個(gè)組件。修改后的代碼如下:

<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 { mapGetters, mapActions } from 'vuex'

export default {
 computed: mapGetters([
  'activeNote'
 ]),
 methods: {
  ...mapActions([
   'addNote',
   'deleteNote',
   'toggleFavorite'
  ])
 }
}
</script>

 通過和原示例代碼對(duì)比,這里的區(qū)別一目了然。我通過在控制臺(tái)打印 Vue 實(shí)例,折騰很長(zhǎng)時(shí)間才大體明白怎么回事。vuex 1 在組件中使用時(shí)會(huì)直接將 getters 以及 actions 掛到 vuex 這個(gè)屬性上,沒有提供 mapGetters 及 mapActions 等一些方法。而 vuex2 使用 mapGetters 及 mapActions 等一些方法將 actions 的方法掛到 Vue 實(shí)例上??偟膩?lái)說,都是把 actions 的方法掛到 Vue 實(shí)例上。我們從這個(gè)層面上談?wù)?Vue 實(shí)例,Vue 2 的變化就是其屬性的變化。比如 Vue1 中在 methods 中添加的方法可以在 vue 實(shí)例的 $options 屬性中查看,而 vue2 中這些方法可以直接在第一級(jí)屬性中查找或者在 $options 屬性下的原型方法中 __proto__ 尋找。在 vue1 中可以查看 vuex 這個(gè)屬性,但是 vue2 中移除了。至于其它的不同,大家可以自己對(duì)比,通過這種方式,可以深入理解 vue 的設(shè)計(jì)思想。

下圖是 Vue1 實(shí)例截圖:

如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用

ES5 實(shí)現(xiàn)擴(kuò)展運(yùn)算符

假設(shè)其它組件都以這種方式改好了,就在我們滿心歡喜地運(yùn)行示例時(shí),又報(bào)錯(cuò)了。問題出在擴(kuò)展運(yùn)算符 ... 上,webpack-simple 這個(gè)模板無(wú)法解析 ES6 的 ...。為此,我又折騰了很久,想試著修改 webpack  的配置文件,但改動(dòng)太大。我妥協(xié)了,決定拋棄擴(kuò)展運(yùn)算符,手寫這個(gè)方法。當(dāng)然如果使用 webpack 的模板就沒有問題,這個(gè)比較簡(jiǎn)單,我們最后再說。

手寫擴(kuò)展運(yùn)算符 ... 之前,我們先看一下 mapActions 這個(gè)方法。對(duì)于 mapGetters 以及 mapActions 這兩個(gè)函數(shù),最簡(jiǎn)單的理解辦法就是查看 vuex 的源碼,最終返回的是一個(gè)對(duì)象。也就是根據(jù)需要獲取 store.js 中 actions 對(duì)象的某些方法。然后通過擴(kuò)展運(yùn)算符把返回的對(duì)象拆開然后掛到 Vue 實(shí)例上。舉例來(lái)說(以下只是擴(kuò)展運(yùn)算符的用法之一,別的用法可以參考其它的文章): 

var obj = {
  a: 1,
  b: 2,
}

var methods = {
  ...obj
}

// console.log(methods)
{
  a: 1,
  b: 2
}

明白擴(kuò)展運(yùn)算符的用法之后就好辦了。為了簡(jiǎn)單一點(diǎn),我直接使用 babel 官網(wǎng)的在線解析器,查看擴(kuò)展運(yùn)算符的 ES5 寫法。 

// ES5 實(shí)現(xiàn)擴(kuò)展運(yùn)算符...
var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) { 
        target[key] = source[key]; 
      } 
    } 
  }
  return target; 
};

完整的 Toolbar.vue 組件代碼如下:

<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>
  <i @click="_test" class="glyphicon glyphicon-remove"></i>
 </div>
</template>

<script>

import { mapGetters, mapActions } from 'vuex'

// ES5 實(shí)現(xiàn)擴(kuò)展運(yùn)算符...
var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) { 
        target[key] = source[key]; 
      } 
    } 
  }
  return target; 
};

var actions = mapActions([
 'addNote',
 'deleteNote',
 'toggleFavorite'
]);

var methodsObj = _extends({},actions)

export default {
 computed: mapGetters([
  'activeNote'
 ]),
 methods:methodsObj
}
</script>

其余兩個(gè)子組件類似,相信大家已經(jīng)明白了我的思路,具體代碼如下:

NotesList.vue 

<template>
 <div id="notes-list">

  <div id="list-header">
   <h3>Notes | coligo</h3>
   <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="#" rel="external nofollow" 
     :class="{active: activeNote === note}"
     @click="updateActiveNote(note)">
     <h5 class="list-group-item-heading">
      {{note.text.trim().substring(0, 30)}}
     </h5>
    </a>
   </div>
  </div>

 </div>
</template>

<script>

import { mapGetters, mapActions } from 'vuex'

// ES5 實(shí)現(xiàn)擴(kuò)展運(yùn)算符...
var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) { 
        target[key] = source[key]; 
      } 
    } 
  }
  return target; 
};

var getters = mapGetters([
 'activeNote'
]);

var filters = {
 filteredNotes: function () {
  if (this.show === 'all'){
   return this.$store.state.notes
  } else if (this.show === 'favorites') {
   return this.$store.state.notes.filter(note => note.favorite)
  }
 }
}

var actions = mapActions(['updateActiveNote'])

var computedObj = _extends({},getters,filters);

var methodsObj = _extends({},actions);

export default {
 data () {
  return {
   show: 'all'
  }
 },
 computed:computedObj,
 methods:methodsObj
}
</script>

 Editor.vue

<template>
 <div id="note-editor">
  <textarea
   :value="activeNoteText"
   @input="editNote"
   class="form-control">
  </textarea>
 </div>
</template>

<script>

import { mapGetters, mapActions } from 'vuex'

export default {
 computed:mapGetters(['activeNoteText']),
 methods:mapActions(['editNote'])
}
</script>

Webpack 模板

直接使用 vue-cli 的 webpack 模板就會(huì)簡(jiǎn)單很多,可以直接解析擴(kuò)展運(yùn)算符,代碼也會(huì)比較簡(jiǎn)潔。

以上是“如何使用vuejs2.0+vuex 2.0構(gòu)建記事本應(yīng)用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI