亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構建記事本應用

2019-11-19 16:19:29
字體:
來源:轉載
供稿:網友

前言

首先說明這并不是一個教程貼,而記事本應用是網上早有的案例,對于學習 vuex 非常有幫助。我的目的是探索 vuex 2.0 ,然后使用 vuejs 2.0 + vuex 2.0 重寫這個應用,其中最大的問題是使用 vue-cli 構建應用時遇到的問題。通過這些問題深入探索 vue 以及 vuex 。

我對于框架的學習一直斷斷續續,最先接觸的是 react,所以有一些先入為主的觀念,喜歡 react 更多一點,尤其在應用的構建層面來說。之所以斷斷續續,是因為自己 JS 基礎較弱,剛開始學習的時候,只是比著葫蘆畫瓢,雖然可以做出點東西,但對于其中的一些概念仍然云里霧里,不知所云,無法深入理解框架。所以我又臨時放棄框架的學習,開始學習 JS 基礎。事實證明打牢基礎之后,學習框架以及理解框架是神速的。而學習 webgl 和 three.js 的過程與此類似。沒有 webgl 的基礎,學習 three.js 只會停留在初級階段。

我在過去的半年參加了很多面試,幾乎無一例外的都會被問框架的使用情況,但是其中很多公司屬于隨波逐流,使用框架比較盲目。甚至覺得使用框架是極其高大上的事情。雖然我學習過框架,但畢竟沒有深入學習也沒有拿得出手的項目,所以只是只言片語的說兩句,大部分知識是懵懂的。然而面對面試官不屑的神情以及以此作為選拔的指標,心想這樣的面試官太膚淺。當然很多公司的面試還是以基礎為主??蚣軐儆谔剿鳎ハ鄬W習的狀態。我在這篇文章中強調一點,學習能力以及解決問題的能力更重要。

開始吧

言歸正傳,對于這個筆記本案例,大家可以直接百度搜 vue notes ,這是一篇英文教程,大家看到的都是翻譯的。在剛開始 vue 資料稀缺的時候,這樣的文章非常珍貴。demo 點這里。說白了,算是 todoMVC 案例的一個變體。當初覺得這個例子非常好,想跟著學一學,結果一拖半年過去了。這幾天終于抽時間把這個例子敲了一遍。學習在于舉一反三。如果大家按照網上教程來做,那么 NPM 包默認安裝的都是最新版本,運行會報錯。所以如果用 vuex 2 要怎么寫呢?

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

 

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

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

main.js 的小改動

原示例 main.js 如下所示,但運行出錯了,主要是 Vue 2 的根實例渲染稍有變化

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 的變化

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

首先是 action.js,只需注意一點,所有的 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 變化也不大,但是要注意幾個地方:

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 中,而是直接在組件中定義的。為了更清晰,我仿照官方示例也提取出來寫在了 store.js 中,這樣在組件中調用時比較方便。其次也引入了 action.js,并作為 actions 對象傳遞給 Vuex.store(),這算是 vuex 的標準寫法吧,對于后面在組件中調用比較有利。

其中要注意 DELETE_NOTE (state){} 這個方法,原示例使用了 vue1 提供的 remove 方法,但是 vue2 中去掉了這個方法。仔細想想就會明白,這個函數的作用就是刪除 notes 數組中的元素。可以使用原生的 splice 方法。如果 JS 基礎扎實的話,這里應該很好理解,沒有什么大問題。其次相比原示例,添加一個刪除后操作的判斷。

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

組件中使用 vuex

先看一下 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> </div></template><script>import { mapGetters, mapActions } from 'vuex'export default { computed: mapGetters([  'activeNote' ]), methods: {  ...mapActions([   'addNote',   'deleteNote',   'toggleFavorite'  ]) }}</script>

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

下圖是 Vue1 實例截圖:

ES5 實現擴展運算符

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

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

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

明白擴展運算符的用法之后就好辦了。為了簡單一點,我直接使用 babel 官網的在線解析器,查看擴展運算符的 ES5 寫法。 

// ES5 實現擴展運算符...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 實現擴展運算符...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>

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

NotesList.vue 

<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="#" rel="external nofollow"      :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, mapActions } from 'vuex'// ES5 實現擴展運算符...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 模板就會簡單很多,可以直接解析擴展運算符,代碼也會比較簡潔。我就不多說了,直接貼上 github 的地址,大家有不懂的可以看一下:https://github.com/nzbin/notes-app-vuejs2-vuex2

總結

終于寫完了這篇文章,感慨頗多。這個例子比較典型,學習的人很多,可能我并不是第一個重寫這個案例的人,我只是與大家分享我的一些心得。順便提一句,為了重寫這個示例并解決遇到的這些小問題,我們可能要使用很多資源,比如 github、codePen、stackoverflow、npm 官網、babel 官網、vuejs 官網、vuex 官網、博客等等?;仡^再想想 Vue 到底是什么,一個對象,沒錯,一個集合了很多屬性和方法的對象。為什么要強調面向對象的重要性,可能這就是最好的闡釋,包括 jQuery、react、其它框架等等。一旦遇到問題,在控制臺打印 Vue 實例,反復查看其屬性可能很有幫助。

最后發個預告,下一篇文章我想探討一下面向對象的 CSS,分析幾個優秀的 UI 框架,我相信每個人都可以書寫屬于自己的 CSS 框架。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
韩国三级日本三级少妇99| 精品国产拍在线观看| 久久久久国产视频| 精品日韩中文字幕| 亚洲国产又黄又爽女人高潮的| 欧美成人网在线| 精品国产乱码久久久久久婷婷| 奇米成人av国产一区二区三区| 奇米一区二区三区四区久久| 亚洲色图狂野欧美| 中文字幕久久亚洲| 成人免费xxxxx在线观看| 日韩精品视频免费| 欧美性猛交xxxx乱大交蜜桃| 日韩av在线免费看| 久久久久久久久久久久久久久久久久av| www.欧美精品| 亚洲国产精品嫩草影院久久| 51精品国产黑色丝袜高跟鞋| 欧美理论电影在线播放| 久久精品夜夜夜夜夜久久| 国产香蕉一区二区三区在线视频| 日韩电影免费在线观看中文字幕| 久久天天躁夜夜躁狠狠躁2022| 超碰97人人做人人爱少妇| 亚洲国产精品国自产拍av秋霞| 欧美激情视频一区二区三区不卡| 国产精品免费看久久久香蕉| 色先锋资源久久综合5566| 91国产美女在线观看| 日韩av网站在线| 色老头一区二区三区在线观看| 欧洲日韩成人av| 国产香蕉一区二区三区在线视频| 热久久免费视频精品| 高清一区二区三区日本久| 日韩女在线观看| 青青草国产精品一区二区| 中文字幕日韩欧美| 青青a在线精品免费观看| 欧美日韩成人网| 在线观看亚洲区| 亚洲第一中文字幕| 久久国内精品一国内精品| 欧美激情xxxxx| 日本国产一区二区三区| 亚洲美女又黄又爽在线观看| 成人网页在线免费观看| 欧美二区在线播放| 在线观看国产成人av片| 最近中文字幕mv在线一区二区三区四区| 日韩av资源在线播放| 欧美激情视频播放| 日韩欧美999| 欧美高清激情视频| 亚洲国产成人久久综合| 日韩欧亚中文在线| 亚洲国产欧美一区二区三区久久| 国产ts一区二区| 国产精品揄拍500视频| 国产精品吴梦梦| 国产成人拍精品视频午夜网站| 欧美日韩高清在线观看| 91久久精品国产91久久性色| 日韩av电影在线播放| 久久韩国免费视频| 狠狠躁天天躁日日躁欧美| 成人做爽爽免费视频| 亚洲精选中文字幕| 欧美丝袜一区二区| 日韩中文字幕第一页| 中文字幕久热精品视频在线| 精品国产31久久久久久| 国产ts人妖一区二区三区| 国产视频精品一区二区三区| 美女999久久久精品视频| 国产91九色视频| 亚洲成人精品久久| 欧美福利视频在线| 欧美国产乱视频| 中文字幕亚洲图片| 欧美激情一级欧美精品| 中日韩午夜理伦电影免费| 中文字幕亚洲二区| 日本精品视频网站| 久久成人精品一区二区三区| 一区二区av在线| 亚洲午夜av电影| 国产在线久久久| 亚洲最大的网站| 欧美在线播放视频| 国产精品第10页| 国产精品永久免费| 91av在线视频观看| 国产激情久久久久| 孩xxxx性bbbb欧美| 中文字幕日韩专区| 8x海外华人永久免费日韩内陆视频| 久久久这里只有精品视频| 亚洲石原莉奈一区二区在线观看| 国产精品视频999| 国产精品白嫩初高中害羞小美女| 日韩精品中文字幕久久臀| 欧美又大又硬又粗bbbbb| 国产精品96久久久久久又黄又硬| 精品在线欧美视频| 欧美一级片久久久久久久| 亚洲成人av在线| 日本不卡视频在线播放| 国产成人av网| 国产一区二区在线播放| www.日韩免费| 最近日韩中文字幕中文| 欧美成人激情视频免费观看| 国产日韩欧美夫妻视频在线观看| 91国偷自产一区二区三区的观看方式| 伊人久久久久久久久久久久久| 久久久女人电视剧免费播放下载| 在线视频免费一区二区| 欧美一级在线播放| 精品毛片网大全| 日韩中文字幕在线观看| 大伊人狠狠躁夜夜躁av一区| 欧美性生交大片免网| 国产精品久久久久aaaa九色| 久久久久久综合网天天| 亚洲色在线视频| 亚洲精品综合久久中文字幕| 欧美综合激情网| 国产精品吊钟奶在线| 国产成+人+综合+亚洲欧美丁香花| 日韩精品一区二区视频| 色爱av美腿丝袜综合粉嫩av| 日韩av在线网| 欧美又大粗又爽又黄大片视频| 九九精品在线观看| 亚洲午夜女主播在线直播| 日韩成人在线网站| 欧美性猛交xxxx免费看久久久| 欧美激情aaaa| 亚洲精品国精品久久99热一| 日韩成人性视频| 欧美影院久久久| 国产综合视频在线观看| 欧美日韩加勒比精品一区| 91久久久精品| 日韩av手机在线观看| 国产热re99久久6国产精品| 亚洲欧美日韩一区二区三区在线| 精品久久香蕉国产线看观看亚洲| 成人在线激情视频| 国内精品模特av私拍在线观看| 国产精品影院在线观看| 国产精品一二三视频| 亚洲欧美福利视频| 精品偷拍一区二区三区在线看| 成人网在线观看| 久久精品影视伊人网| 成人免费直播live| 麻豆精品精华液| 亚洲天堂av在线播放| 亚洲美女性视频| 亚洲欧美激情在线视频| 91日韩在线视频|