移動端Vue2.x Picker的全局調用實現
什麼是Picker組件
對標PC端的Select標簽, 移動端的選擇框一般是在viewPort底部彈出
Picker組件存在的問題
- Picker通常以fixed佈局,但是我們在寫Picker組件時有遇到過該組件無法在viewport的底部彈出,而是在組件內部彈出,導致樣式混淆,不符合C端審美,造成以上問題的原因是因為[層疊上下文]的原因,fixed佈局並不是基於viewport為底板,而是當前的層疊上下文
- Picker若是放置在根組件下的話會造成數據流流向出現混淆,嵌套過深層級的組件無法很便利的觸發Picker的顯示與隱藏,需要結合狀態管理vuex來做處理或者通過透傳$listeners,這在一定程度上增加瞭開發者的心智負擔
解決思路
利用聲明式編程將Picker放置在Body下去使用, 可以較好的規避以上的兩個問題,例如利用以下方式調用picker的顯示與隱藏
this.$picker(組件選項, { wrapper: { props: {}, on: {} }, props: {}, on: {} })
選項解釋
- wrapper: picker函數編程參數
- props: 組件選項的選項配置
- on: 組件選項的時間綁定
解決方案
目錄劃分
– Components
– BaseUsedComponents
– Picker
– Picker.vue
– index.js
– main.js
描繪Picker容器
Picker.vue文件作用:
- 繪制Picker容器
- 利用transition內置組件結合css3的animation做動畫過渡
代碼如下:
<transition name="slideup"> <div class="picker" v-if="show"> <slot></slot> <div class="mask"></div> </div> </transition>
創建Picker
思路大綱
- 定義一個Picker函數, 該函數需要做以下幾點:
- 生成Picker的實例PickerInstance
- 將PickerInstance.show置為true
- 將Picker容器放入到body底部
- Picker組件生成需要使用防抖措施,不能在連續點擊下
- 將傳入的組件選項根據props與on屬性生成vnode,並且放置到默認插槽內
- 點擊mask元素會將Picker隱藏,這裡需要再定義一個hide方法
- hide方法需要做以下幾個問題
- 將實例下show屬性置為false
- 刪除body下的安插Picker容器
- 將實例置為Null,調用GC
Picker函數
- 調用create函數生成Picker實例
- 判斷實例是否存在
- 保留當前組件選項以及配置
- 更改Picker組件的show屬性彈出彈窗,並且安插到body下
create
- 創建一個el作為Picker的容器,安插到body下
- 在render函數裡,Picker將之前傳入的組件選項作為默認插槽放置到內部,並且自身作為當前實例的子組件充當根元素
- mounted函數裡獲取對應的transition時間作為之後hide時觸發實際
為什麼需要在requestAnimationFrame裡去取動畫時間, 而不是在mounted直接可以獲取?
組件的mounted函數是在初始化渲染後就會調用,而Toast組件通過設置showStatus去觸發transition的enter函數(雖然Toast組件mounted在之前就會被調用,但此時toast dom上不存在transition class),此時由於觸發的是data.setter函數,從而對Watcher進行派發更新,導致所有的操作都在nextTick(也就是微任務)裡執行, 所以調用順序是這樣的:
Toast組件Mounted -> 父組件Mounted(也就是現在所處的Mounted函數, 註意此時因為toast裡的transition沒有攜帶appear屬性,導致transition enter函數不會觸發,從而transition class不會被添加) -> nextTick() -> Toast組件update(v-show) -> transition(v-show觸發enter函數) -> toast dom增加瞭transition類名 -> window.getComputedStyle(toast)獲取toastDuration,我們也可以在nextTick裡獲取,介於transition active在動畫全過程都會有,並且requestAnimationFrame屬於瀏覽器重繪(painter)鉤子函數,比微任務還要靠後執行,所以在這裡獲取
show
- 獲取Picker的實例,Picker是作為該實例的根元素
- 標記Mounted屬性,表示已經安插
- 監聽show屬性,在show置為false時調用hide函數
- 安插到body下
hide
- 重置Mounted屬性為false
- 將show函數裡的定義的teardown監聽函數刪除掉,釋放內存
- 設置延時器作為刪除真實DOM的鉤子函數
為什麼采用setTimeout去刪除
使用監聽transtionend會有一個問題:
Vue本身在transition組件子節點裡監聽瞭transitionend(或者animationend)
動畫完成後就會刪除掉transition class, 那麼此時transition-property就會消失掉
根據文檔顯示, transition-property消失後將不觸發transition鉤子函數,繼而無法觸發
transitionend函數,導致remove可能會無法調用,留下之前的ToastConainer
remove
remove函數作用是刪除真實DOM、清除延時器、將timer以及Picker實例置為null, 調用GC
updateChildrenComponent
Picker組件完成後,發現更改傳入組件的裡的props沒有重新,所以這裡寫瞭一個手動觸發更新組件的函數,組件vnode有4個鉤子函數,prepatch是做為update時調用,值有兩個,第一個是上一次的vnode,而第二個就是更改後的vnode,所以我們在PickerCommand函數裡預暫瞭原先vnode以及Component,做為diff的舊vnode,調用此函數既可以更新組件
結束語
Picker組件隻是一個例子,還可以使用更多方法去實現。到此這篇關於移動端Vue2.x Picker的全局調用實現的文章就介紹到這瞭,更多相關Vue2.x Picker全局調用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- v-show和v-if的區別 及應用場景
- vue使用Vue.extend創建全局toast組件實例
- van-picker組件default-index屬性設置不生效踩坑及解決
- vue實現右側滑出層動畫
- Vue封裝全局toast組件的完整實例