摘要:前幾天翻譯了基于這篇博客的文章用構(gòu)建一個筆記應(yīng)用。概述如果熟悉的使用,可以放心地跳過這一段。存的數(shù)據(jù)都是對象。修改的邏輯簡單來說就是在思路上要完成從數(shù)組到對象的轉(zhuǎn)換。把以上各條添加到里面。
前幾天翻譯了基于這篇博客的文章:用 Vuex 構(gòu)建一個筆記應(yīng)用。在此基礎(chǔ)上我對它做了一些更新:
把數(shù)據(jù)同步到 Firebase 上,不會每次關(guān)掉瀏覽器就丟失數(shù)據(jù)。
加了筆記檢索功能
為保證代碼整潔,加上了 eslint
你可以從 Github Repo 下載源碼,和 Firebase 的同步效果看下面這個 gif:
一、把數(shù)據(jù)同步到 Firebase可能你也知道 Vue.js 和 Firebase 合作搞出了一個 Vuefire, 但是在這里并不能用它,因為用 Vuex 管理數(shù)據(jù)的結(jié)果就是組件內(nèi)部只承擔(dān)基本的View層的職責(zé),而數(shù)據(jù)基本上都在 store 里面。所以我們只能把數(shù)據(jù)的存取放在 store 里面。
1.1 Firebase 概述如果熟悉 Firebase 的使用,可以放心地跳過這一段。
如果你還沒有 Firebase 的賬號,可以去注冊一個,注冊號之后會自動生成一個"MY FIRST APP",這個初始應(yīng)用給的地址就是用來存數(shù)據(jù)的地方。
Firebase 存的數(shù)據(jù)都是 JSON 對象。我們向 JSON 樹里面加數(shù)據(jù)的時候,這條數(shù)據(jù)就變成了 JSON 樹里的一個鍵。比方說,在/user/mchen下面加上widgets屬性之后,數(shù)據(jù)就變成了這個樣子:
{ "users": { "mchen": { "friends": { "brinchen": true }, "name": "Mary Chen", "widgets": { "one": true, "three": true } }, "brinchen": { ... }, "hmadi": { ... } } }創(chuàng)建數(shù)據(jù)引用
要讀寫數(shù)據(jù)庫里的數(shù)據(jù),首先要創(chuàng)建一個指向數(shù)據(jù)的引用,每個引用對應(yīng)一條 URL。要獲取其子元素,可以用child API, 也可以直接把子路徑加到 URL 上:
// referene new Firebase(https://docs-examples.firebaseio.com/web/data) // 子路徑加到 URL 上 new Firebase("https://docs-examples.firebaseio.com/web/data/users/mchen/name") // child API rootRef.child("users/mchen/name")Firebase 數(shù)據(jù)庫中的數(shù)組
Firebase 數(shù)據(jù)庫不能原生支持?jǐn)?shù)組。如果你存了一個數(shù)組,實際上是把它存儲為一個用數(shù)組作為鍵的對象:
// we send this ["hello", "world"] // firebase database store this {0: "hello", 1: "world"}存儲數(shù)據(jù)
set() 方法把新數(shù)據(jù)放到指定的引用的路徑下,代替那個路徑下原有的數(shù)據(jù)。它可以接收各種數(shù)據(jù)類型,如果參數(shù)是 null 的話就意味著刪掉這個路徑下的數(shù)據(jù)。
舉個例子:
// 新建一個博客的引用 var ref = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog") var usersRef = ref.child("users") usersRef.set({ alanisawesome: { date_of_birth: "June 23, 1912", full_name: "Alan Turing" }, gracehop: { date_of_birth: "December 9, 1906", full_name: "Grace Hopper" } })
當(dāng)然,也可以直接在子路徑下存儲數(shù)據(jù):
usersRef.child("alanisawesome").set({ date_of_birth: "June 23, 1912", full_name: "Alan Turing" }) usersRef.child("gracehop").set({ date_of_birth: "December 9, 1906", full_name: "Grace Hopper" })
不同之處在于,由于分成了兩次操作,這種方式會觸發(fā)兩個事件。另外,如果usersRef下本來有數(shù)據(jù)的話,那么第一種方式就會覆蓋掉之前的數(shù)據(jù)。
上面的set()對數(shù)據(jù)具有"破壞性",如果我們并不想改動原來的數(shù)據(jù)的話,可能update()是更合適的選擇:
var hopperRef = userRef.child("gracehop") hopperRef.update({ "nickname": "Amazing Grace" })
這段代碼會在 Grace 的資料下面加上 nickname 這一項,如果我們用的是set()的話,那么full_name和date_of_birth就會被刪掉。
另外,我們還可以在多個路徑下同時做 update 操作:
usersRef.update({ "alanisawesome/nickname": "Alan The Machine", "gracehop/nickname": "Amazing Grace" })
前面已經(jīng)提到了,由于數(shù)組索引不具有獨特性,F(xiàn)irebase 不提供對數(shù)組的支持,我們因此不得不轉(zhuǎn)而用對象來處理。
在 Firebase 里面,push方法會為每一個子元素根據(jù)時間戳生成一個唯一的 ID,這樣就能保證每個子元素的獨特性:
var postsRef = ref.child("posts") // push 進去的這個元素有了自己的路徑 var newPostRef = postsRef.push() // 獲取 ID var uniqueID = newPostRef.key() // 為這個元素賦值 newPostRef.set({ author: "gracehop", title: "Announcing COBOL, a New Programming language" }) // 也可以把這兩個動作合并 postsRef.push().set({ author: "alanisawesome", title: "The Turing Machine" })
最后生成的數(shù)據(jù)就是這樣的:
{ "posts": { "-JRHTHaIs-jNPLXOQivY": { "author": "gracehop", "title": "Announcing COBOL, a New Programming Language" }, "-JRHTHaKuITFIhnj02kE": { "author": "alanisawesome", "title": "The Turing Machine" } } }
這篇博客聊到了這個 ID 是怎么回事以及怎么生成的。
獲取數(shù)據(jù)獲取 Firebase 數(shù)據(jù)庫里的數(shù)據(jù)是通過對數(shù)據(jù)引用添加一個異步的監(jiān)聽器來完成的。在數(shù)據(jù)初始化和每次數(shù)據(jù)變化的時候監(jiān)聽器就會觸發(fā)。value事件用來讀取在此時數(shù)據(jù)庫內(nèi)容的快照,在初始時觸發(fā)一次,然后每次變化的時候也會觸發(fā):
// Get a database reference to our posts var ref = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts") // Attach an asynchronous callback to read the data at our posts reference ref.on("value", function(snapshot) { console.log(snapshot.val()); }, function (errorObject) { console.log("The read failed: " + errorObject.code); });
簡單起見,我們只用了 value 事件,其他的事件就不介紹了。
1.2 Firebase 的數(shù)據(jù)處理方式對代碼的影響開始寫代碼之前,我想搞清楚兩個問題:
Firebase 是怎么管理數(shù)據(jù)的,它對組件的 View 有什么影響
用戶交互過程中是怎么和 Firebase 同步數(shù)據(jù)的
先看第一個問題,這是我在 Firebase 上保存的 JSON 數(shù)據(jù):
{ "notes" : { "-KGXQN4JVdopZO9SWDBw" : { "favorite" : true, "text" : "change" }, "-KGXQN6oWiXcBe0a54cT" : { "favorite" : false, "text" : "a" }, "-KGZgZBoJJQ-hl1i78aa" : { "favorite" : true, "text" : "little" }, "-KGZhcfS2RD4W1eKuhAY" : { "favorite" : true, "text" : "bit" } } }
這個亂碼一樣的東西是 Firebase 為了保證數(shù)據(jù)的獨特性而加上的。我們發(fā)現(xiàn)一個問題,在此之前 notes 實際上是一個包含對象的數(shù)組:
[ { favorite: true, text: "change" }, { favorite: false, text: "a" }, { favorite: true, text: "little" }, { favorite: true, text: "bit" }, ]
顯然,對數(shù)據(jù)的處理方式的變化使得渲染 notes 列表的組件,也就是 NotesList.vue 需要大幅修改。修改的邏輯簡單來說就是在思路上要完成從數(shù)組到對象的轉(zhuǎn)換。
舉個例子,之前 filteredNotes 是這么寫的:
filteredNotes () { if (this.show === "all"){ return this.notes } else if (this.show === "favorites") { return this.notes.filter(note => note.favorite) } }
現(xiàn)在的問題就是,notes 不再是一個數(shù)組,而是一個對象,而對象是沒有 filter 方法的:
filteredNotes () { var favoriteNotes = {} if (this.show === "all") { return this.notes } else if (this.show === "favorites") { for (var note in this.notes) { if (this.notes[note]["favorite"]) { favoriteNotes[note] = this.notes[note] } } return favoriteNotes } }
另外由于每個對象都對應(yīng)一個自己的 ID,所以我也在 state 里面加了一個activeKey用來表示當(dāng)前筆記的 ID,實際上現(xiàn)在我們在TOGGLE_FAVORITE,SET_ACTIVE這些方法里面都需要對相應(yīng)的activeKey賦值。
再看第二個問題,要怎么和 Firebase 交互:
// store.js let notesRef = new Firebase("https://crackling-inferno-296.firebaseio.com/notes") const state = { notes: {}, activeNote: {}, activeKey: "" } // 初始化數(shù)據(jù),并且此后數(shù)據(jù)的變化都會反映到 View notesRef.on("value", snapshot => { state.notes = snapshot.val() }) // 每一個操作都需要同步到 Firebase const mutations = { ADD_NOTE (state) { const newNote = { text: "New note", favorite: false } var addRef = notesRef.push() state.activeKey = addRef.key() addRef.set(newNote) state.activeNote = newNote }, EDIT_NOTE (state, text) { notesRef.child(state.activeKey).update({ "text": text }) }, DELETE_NOTE (state) { notesRef.child(state.activeKey).set(null) }, TOGGLE_FAVORITE (state) { state.activeNote.favorite = !state.activeNote.favorite notesRef.child(state.activeKey).update({ "favorite": state.activeNote.favorite }) }, SET_ACTIVE_NOTE (state, key, note) { state.activeNote = note state.activeKey = key } }二、筆記檢索功能
效果圖:
這個功能比較常見,思路就是列表渲染 + 過濾器:
// NoteList.vue
// NoteList.vue filters: { byTitle (notesToFilter, filterValue) { var filteredNotes = {} for (let note in notesToFilter) { if (notesToFilter[note]["text"].indexOf(filterValue) > -1) { filteredNotes[note] = notesToFilter[note] } } return filteredNotes } }三、在項目中用 eslint
如果你是個 Vue 重度用戶,你應(yīng)該已經(jīng)用上 eslint-standard 了吧。
"eslint": "^2.0.0", "eslint-config-standard": "^5.1.0", "eslint-friendly-formatter": "^1.2.2", "eslint-loader": "^1.3.0", "eslint-plugin-html": "^1.3.0", "eslint-plugin-promise": "^1.0.8", "eslint-plugin-standard": "^1.3.2"
把以上各條添加到 devDependencies 里面。如果用了 vue-cli 的話, 那就不需要手動配置 eslint 了。
// webpack.config.js module: { preLoaders: [ { test: /.vue$/, loader: "eslint" }, { test: /.js$/, loader: "eslint" } ], loaders: [ ... ], eslint: { formatter: require("eslint-friendly-formatter") } }
如果需要自定義規(guī)則的話,就在根目錄下新建.eslintrc,這是我的配置:
module.exports = { root: true, // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style extends: "standard", // required to lint *.vue files plugins: [ "html" ], // add your custom rules here "rules": { // allow paren-less arrow functions "arrow-parens": 0, "no-undef": 0, "one-var": 0, // allow debugger during development "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0 } }四、結(jié)語
講得比較粗糙,具體可以拿源碼跑一下。如果有什么問題,歡迎評論。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/79360.html
摘要:官網(wǎng)地址聊天機器人插件開發(fā)實例教程一創(chuàng)建插件在系統(tǒng)技巧使你的更加專業(yè)前端掘金一個幫你提升技巧的收藏集。我會簡單基于的簡潔視頻播放器組件前端掘金使用和實現(xiàn)購物車場景前端掘金本文是上篇文章的序章,一直想有機會再次實踐下。 2道面試題:輸入URL按回車&HTTP2 - 掘金通過幾輪面試,我發(fā)現(xiàn)真正那種問答的技術(shù)面,寫一堆項目真不如去刷技術(shù)文章作用大,因此刷了一段時間的博客和掘金,整理下曾經(jīng)被...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構(gòu)建單頁應(yīng)用新篇華麗的分割線原文地址前言在最近學(xué)習(xí)的時候,看到國外一篇講述了如何使用和來構(gòu)建一個簡單筆記的單頁應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構(gòu)建單頁應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構(gòu)建單頁應(yīng)用新篇華麗的分割線原文地址前言在最近學(xué)習(xí)的時候,看到國外一篇講述了如何使用和來構(gòu)建一個簡單筆記的單頁應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構(gòu)建單頁應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構(gòu)建單頁應(yīng)用新篇華麗的分割線原文地址前言在最近學(xué)習(xí)的時候,看到國外一篇講述了如何使用和來構(gòu)建一個簡單筆記的單頁應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構(gòu)建單頁應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構(gòu)建單頁應(yīng)用新篇華麗的分割線原文地址前言在最近學(xué)習(xí)的時候,看到國外一篇講述了如何使用和來構(gòu)建一個簡單筆記的單頁應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構(gòu)建單頁應(yīng)用【新篇】 ---------...
閱讀 1908·2023-04-25 16:28
閱讀 825·2021-11-23 09:51
閱讀 1613·2019-08-30 15:54
閱讀 1287·2019-08-30 15:53
閱讀 2965·2019-08-30 15:53
閱讀 3541·2019-08-30 15:43
閱讀 3377·2019-08-30 11:18
閱讀 3467·2019-08-26 10:25