摘要:因此在這個(gè)項(xiàng)目做完等待測(cè)試的時(shí)候我思考了一下,誰(shuí)說(shuō)過(guò)濾器就一定放在里面。
這個(gè)問(wèn)題是在下在做一個(gè)Vue項(xiàng)目中遇到的實(shí)際場(chǎng)景,這里記錄一下我遇到問(wèn)題之后的思考和最后怎么解決的(老年程序員記性不好 -。-),過(guò)程中會(huì)涉及到一些Vue源碼的概念比如$mount、render watcher等,如果不太了解的話可以瞅瞅 Vue源碼閱讀系列文章 ~
問(wèn)題是這樣的:頁(yè)面從后臺(tái)拿到的數(shù)據(jù)是由0、1之類的key,而這個(gè)key代表的value比如0-女、1-男的對(duì)應(yīng)關(guān)系是要從另外一個(gè)數(shù)據(jù)字典接口拿到的;類似于這樣的Api:
{ "SEX_TYPE": [ { "paramValue": 0, "paramDesc": "女" }, { "paramValue": 1, "paramDesc": "男" } ] }
那么如果view拿到的是0,就要從字典中找到它的描述女并且顯示出來(lái);下面故事開始了
1. 思考有人說(shuō),這不是過(guò)濾器 filter 要做的事么,直接Vue.filter不就行了,然而問(wèn)題是這個(gè)filter是要等待異步的數(shù)據(jù)字典接口返回之后才能拿到,如果在$mount的時(shí)候這個(gè)filter沒(méi)有找到,那么就會(huì)導(dǎo)致錯(cuò)誤影響之后的渲染(白屏并報(bào)undefined錯(cuò));
我想到的解決方法有兩個(gè):
把接口變?yōu)橥剑?b>beforeCreate或created鉤子中同步地獲取數(shù)據(jù)字典接口,保證在 $mount的時(shí)候可以拿到注冊(cè)好的filter,保證時(shí)序,但是這樣會(huì)阻塞掛載,延長(zhǎng)白屏?xí)r間,因此不推介;
把filter的注冊(cè)變?yōu)楫惒剑讷@取filter之后通知 render watcher 更新自己,這樣可以利用vue自己的響應(yīng)式化更新視圖,不會(huì)阻塞渲染,因此在下初步采用了這個(gè)方法。
2. 實(shí)現(xiàn)因?yàn)閒ilter屬于 asset_types ,關(guān)于在Vue實(shí)例中asset_types的訪問(wèn)鏈有以下幾個(gè)結(jié)論;具體代碼實(shí)踐可以參考: Codepen - filter test
asset_types包括filters、components、directives,以下所有的asset_types都自行替換成前面幾項(xiàng)
子組件中的asset_types訪問(wèn)不到父組件中的asset_types,但是可以訪問(wèn)到全局注冊(cè)的掛載在$root.$options.asset_types.__proto__上的asset_types,這里對(duì)應(yīng)源碼 src/core/util/options.js
全局注冊(cè)方法Vue.asset_types,比如Vue.filters注冊(cè)的asset_types會(huì)掛載到根實(shí)例(其他實(shí)例的$root)的$options.asset_types.__proto__上,并被以后所有創(chuàng)建的Vue實(shí)例繼承,也就是說(shuō),以后所有創(chuàng)建的Vue實(shí)例都可以訪問(wèn)到
組件的slot的作用域僅限于它被定義的地方,也就是它被定義的組件中,訪問(wèn)不到父組件的asset_types,但是可以訪問(wèn)到全局定義的asset_types
同理,因?yàn)閙ain.js中的new Vue()實(shí)例是根實(shí)例,它中注冊(cè)的asset_types會(huì)被掛載在$root.$options.asset_types上而不是$root.$options.asset_types.__proto__上
根據(jù)以上幾個(gè)結(jié)論,可以著手coding了~
2.1 使用根組件的filters因此首先我考慮的是把要注冊(cè)的filter掛載到根組件上,這樣其他組件通過(guò)訪問(wèn)$root可以拿到注冊(cè)的filter,這里的實(shí)現(xiàn):
{{ rootFilters( sexVal )}}
注冊(cè)filter的js
// utils/filters import * as Api from "api" /** * 獲取并注冊(cè)過(guò)濾器 * 注冊(cè)在$root.$options.filters上不是$root.$options.filters.__proto__上 * 注意這里的this是vue實(shí)例,需要用call或apply調(diào)用 * @returns {Promise} */ export function registerFilters() { return Api.sysParams() // 獲取數(shù)據(jù)字典的Api,返回的是promise .then(({ data }) => { Object.keys(data).forEach(T => this.$set(this.$root.$options.filters, T, val => { const tar = data[T].find(item => item["paramValue"] === val) return tar["paramDesc"] || "" }) ) return data }) .catch(err => console.error(err, " in utils/filters.js")) }
這樣把根組件上的filters變?yōu)轫憫?yīng)式化的,并且在渲染的時(shí)候因?yàn)樵?b>rootFilters方法中訪問(wèn)了已經(jīng)在created中被響應(yīng)式化的$root.$options.filters,所以當(dāng)異步獲取的數(shù)據(jù)被賦給$root.$options.filters的時(shí)候,會(huì)觸發(fā)這個(gè)組件render watcher的重新渲染,這時(shí)候再獲取rootFilters方法的時(shí)候就能取到filter了;
那這里為什么不用Vue.filter方法直接注冊(cè)呢,因?yàn)?b>Object.defineProperty不能監(jiān)聽__proto__上數(shù)據(jù)的變動(dòng),而全局Vue.filter是將過(guò)濾器注冊(cè)在了根組件$root.$options.asset_types.__proto__上,因此其變動(dòng)不能被響應(yīng)。
這里的代碼可以進(jìn)一步完善,但是這個(gè)方法存在一定的問(wèn)題,首先這里使用了Vue.util上不穩(wěn)定的方法,另外在使用中到處可見(jiàn)this.$root.$options這樣訪問(wèn)vue實(shí)例內(nèi)部屬性的情況,不太文明,讀起來(lái)也讓人困惑。
因此在這個(gè)項(xiàng)目做完等待測(cè)試的時(shí)候我思考了一下,誰(shuí)說(shuō)過(guò)濾器就一定放在filters里面 -。-,也可以使用mixin來(lái)實(shí)現(xiàn)嘛
2.2 使用mixin使用mixin要注意一點(diǎn),因?yàn)関ue中把data里所有以_、$開頭的變量都作為內(nèi)部保留的變量,并不代理到當(dāng)前實(shí)例上,因此直接this._xx是無(wú)法訪問(wèn)的,需要通過(guò)this.$data._xx來(lái)訪問(wèn)。
// mixins/sysParamsMixin.js import * as Api from "api" export default { data() { return { _filterFunc: null, // 過(guò)濾器函數(shù) _sysParams: null, // 獲取數(shù)據(jù)字典 _sysParamsPromise: null // 獲取sysParams之后返回的Promise } }, methods: { /* 注冊(cè)過(guò)濾器到_filterFunc中 */ _getSysParamsFunc() { const { $data } = this return $data._sysParamsPromise || ($data._sysParamsPromise = Api.sysParams() .then(({ data }) => { this.$data._sysParams = data this.$data._filterFunc = {} Object.keys(data).forEach(paramKey => this.$data._filterFunc[paramKey] = val => { const tar = data[paramKey].find(item => item["paramValue"] === val) return tar && tar["paramDesc"] || "" }) return data }) .catch(err => console.error(err, " in src/mixins/sysParamsMixin.js"))) }, /* 按照鍵值獲取單個(gè)過(guò)濾器 */ _rootFilters(val, id = "SEX_TYPE") { const func = this.$data._filterFunc const mth = func && func[id] return mth && mth(val) || val }, /* 獲取數(shù)據(jù)字典 */ _getSysParams() { return this.$data._sysParams } } }
這里把Api的promise保存下來(lái),如果其他地方還用到的話直接返回已經(jīng)是resolved狀態(tài)的promise,就不用再次去請(qǐng)求數(shù)據(jù)了。另外為了在其他實(shí)例中也可以方便的訪問(wèn),這里掛載在根組件上。
那在我們的根組件中怎么使用呢:
// src/main.js import sysParamsMixin from "mixins/sysParamsMixin" new Vue({ el: "#app", mixins: [sysParamsMixin], render: h => h(App), })
在需要用過(guò)濾器的組件中:
{{ $root._rootFilters( sexVal )}}
這里不僅注冊(cè)了過(guò)濾器,而且也暴露了數(shù)據(jù)字典,以方便某些地方的列表顯示,畢竟這是實(shí)際項(xiàng)目中常見(jiàn)的場(chǎng)景。
當(dāng)然如果使用vuex更好,不過(guò)這里的場(chǎng)景個(gè)人覺(jué)得沒(méi)必要用vuex,如果還有更好的方法可以討論一下下啊~
網(wǎng)上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學(xué)習(xí)過(guò)程中的總結(jié),如果發(fā)現(xiàn)錯(cuò)誤,歡迎留言指出~
參考:
Vue.js 2.5.17 源碼
Vue源碼閱讀系列
Vue 2.5.17 filter test
PS:歡迎大家關(guān)注我的公眾號(hào)【前端下午茶】,一起加油吧~
另外可以加入「前端下午茶交流群」微信群,長(zhǎng)按識(shí)別下面二維碼即可加我好友,備注加群,我拉你入群~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/97566.html
摘要:基礎(chǔ)布局的中主要為部分,分別是用于搜索篩選和分頁(yè)的表單控件用于排序表格的表頭以及用于展示數(shù)據(jù)的。這也是前瞻發(fā)布之后,提出廢棄部分功能后許多人反應(yīng)較為強(qiáng)烈的原因。 與上周的第一篇實(shí)踐教程一樣,在這篇文章中,我將繼續(xù)從一種常見(jiàn)的功能——表格入手,展示Vue.js中的一些優(yōu)雅特性。同時(shí)也將對(duì)filter功能與computed屬性進(jìn)行對(duì)比,說(shuō)明各自的適用場(chǎng)景,也為vue2.0版本中即將刪除的部...
摘要:基礎(chǔ)布局的中主要為部分,分別是用于搜索篩選和分頁(yè)的表單控件用于排序表格的表頭以及用于展示數(shù)據(jù)的。這也是前瞻發(fā)布之后,提出廢棄部分功能后許多人反應(yīng)較為強(qiáng)烈的原因。 與上周的第一篇實(shí)踐教程一樣,在這篇文章中,我將繼續(xù)從一種常見(jiàn)的功能——表格入手,展示Vue.js中的一些優(yōu)雅特性。同時(shí)也將對(duì)filter功能與computed屬性進(jìn)行對(duì)比,說(shuō)明各自的適用場(chǎng)景,也為vue2.0版本中即將刪除的部...
摘要:記錄一些小技巧和踩過(guò)的坑由于本篇文章內(nèi)容太多,導(dǎo)致編輯器有點(diǎn)卡,所以新開辟了一篇實(shí)踐二,后續(xù)再這里更新。組件的生命周期函數(shù)是在標(biāo)簽里的數(shù)據(jù)發(fā)生變化時(shí)候觸發(fā)數(shù)據(jù)可能更新了,但是沒(méi)有綁定到上面的話,不會(huì)調(diào)用鉤子函數(shù)。 記錄一些小技巧和踩過(guò)的坑 由于本篇文章內(nèi)容太多,導(dǎo)致SF編輯器有點(diǎn)卡,所以新開辟了一篇 vue2實(shí)踐(二),后續(xù)再這里更新。 1. props 帶不帶冒號(hào)的區(qū)別 ...
摘要:從到上線簡(jiǎn)介是個(gè)框架。現(xiàn)在,我們完成一個(gè)項(xiàng)目后,需要打包,因?yàn)樵陂_發(fā)環(huán)境下,運(yùn)行所依賴的包達(dá)到好幾百個(gè),為了將文件體積縮減到正常范圍,必須按需打包。 Vue從Hello World到上線 Vue 簡(jiǎn)介 Vue是個(gè)MVVM框架。 特點(diǎn):簡(jiǎn)單易學(xué)、體積小、性能高。并且它的源碼耦合性非常低,了解它的過(guò)程也就是思想進(jìn)步的過(guò)程。 當(dāng)然,只學(xué)這一個(gè)框架,無(wú)法完成前端的全部工作,除了Vue之外,還...
摘要:官網(wǎng)地址聊天機(jī)器人插件開發(fā)實(shí)例教程一創(chuàng)建插件在系統(tǒng)技巧使你的更加專業(yè)前端掘金一個(gè)幫你提升技巧的收藏集。我會(huì)簡(jiǎn)單基于的簡(jiǎn)潔視頻播放器組件前端掘金使用和實(shí)現(xiàn)購(gòu)物車場(chǎng)景前端掘金本文是上篇文章的序章,一直想有機(jī)會(huì)再次實(shí)踐下。 2道面試題:輸入U(xiǎn)RL按回車&HTTP2 - 掘金通過(guò)幾輪面試,我發(fā)現(xiàn)真正那種問(wèn)答的技術(shù)面,寫一堆項(xiàng)目真不如去刷技術(shù)文章作用大,因此刷了一段時(shí)間的博客和掘金,整理下曾經(jīng)被...
閱讀 1339·2019-08-30 15:44
閱讀 1391·2019-08-29 18:42
閱讀 446·2019-08-29 13:59
閱讀 783·2019-08-28 17:58
閱讀 2823·2019-08-26 12:02
閱讀 2424·2019-08-23 18:40
閱讀 2416·2019-08-23 18:13
閱讀 3118·2019-08-23 16:27