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