DataV?全屏容器組件源碼解析
引言
數據可視化頁面一般在瀏覽器中進行全屏展示,全屏容器將根據屏幕比例及當前瀏覽器窗口大小,自動進行縮放處理。瀏覽器全屏后,全屏容器將充滿屏幕。
接下來我們來一起閱讀下DataV中關于全屏容器的源碼,看下它是如何實現的。
源碼閱讀(vue2版本)
它的源碼位置

看下它的DOM結構,很簡單
<div id="dv-full-screen-container" :ref="ref">
<template v-if="ready">
<slot></slot>
</template>
</div>
源碼分析
接下來重點看下它的JS實現,它的代碼中混入了autoResize.js,所以我們需要兩個文件一起看,不然會對突然出現的變量很奇怪。(如果覺得分開不便于閱讀,其實我們可以把它合在一起來閱讀,是一樣的)
梳理下它的執(zhí)行邏輯:
第1步、mounted(組件掛載時,這一時期可對dom進行操作)
mounted () {
const { autoResizeMixinInit } = this
autoResizeMixinInit()
},
第2步、autoResizeMixinInit函數
methods: {
async autoResizeMixinInit () {
const { initWH, getDebounceInitWHFun, bindDomResizeCallback, afterAutoResizeMixinInit } = this
await initWH(false)
getDebounceInitWHFun()
bindDomResizeCallback()
if (typeof afterAutoResizeMixinInit === 'function') afterAutoResizeMixinInit()
},
}
這其中調用了幾個函數,我們來看看這些函數的作用。
2.1、initWH函數
// 初始化寬高
initWH (resize = true) {
const { $nextTick, $refs, ref, onResize } = this
return new Promise(resolve => {
$nextTick(_ => {
const dom = this.dom = $refs[ref]
this.width = dom ? dom.clientWidth : 0
this.height = dom ? dom.clientHeight : 0
if (!dom) {
console.warn('DataV: Failed to get dom node, component rendering may be abnormal!')
} else if (!this.width || !this.height) {
console.warn('DataV: Component width or height is 0px, rendering abnormality may occur!')
}
if (typeof onResize === 'function' && resize) onResize()
resolve()
})
})
},
這個函數的作用很簡單,就是在DOM渲染成功后,獲取這個組件dom的寬高,返回一個Promise異步函數,作用就是:保證這個dom已經渲染好了,再去執(zhí)行其他函數。
2.1.1、onResize
onResize () {
const { setAppScale } = this
setAppScale()
}
resize為true,即窗口大小變化、dom的style改變時要重新設置dom的縮放比例。
2.2、getDebounceInitWHFun
getDebounceInitWHFun () {
const { initWH } = this
this.debounceInitWHFun = debounce(100, initWH)
},
獲取一個經過防抖的initWH函數。即debounceInitWHFun。
2.3、bindDomResizeCallback
// 監(jiān)聽dom元素變化
bindDomResizeCallback () {
const { dom, debounceInitWHFun } = this
this.domObserver = observerDomResize(dom, debounceInitWHFun)
window.addEventListener('resize', debounceInitWHFun)
},
很重要的一步,其中使用了observerDomResize來對這個組件dom進行監(jiān)聽。
需要監(jiān)聽的DOM變化:
- 窗口大小改變時觸發(fā)的事件
- dom的樣式改變時觸發(fā)
第一個直接使用window監(jiān)聽resize事件即可。
第二個對dom元素的監(jiān)聽,我們就需要使用MutationObserver來做了。
MutationObserver用來監(jiān)視 DOM 變動。DOM 的任何變動,比如節(jié)點的增減、屬性的變動、文本內容的變動都會觸發(fā)MutationObserver事件。
封裝一個observerDomResize函數來對dom的style屬性變化進行監(jiān)聽
export function observerDomResize (dom, callback) {
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
const observer = new MutationObserver(callback)
observer.observe(dom, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })
return observer
}
- attributes:屬性的變動
- attributeFilter:表示需要觀察的特定屬性
- attributeOldValue:布爾值,表示觀察attributes變動時,是否需要記錄變動前的屬性值。
2.4、afterAutoResizeMixinInit
afterAutoResizeMixinInit () {
const { initConfig, setAppScale } = this
initConfig()
setAppScale()
this.ready = true
},
組件dom節(jié)點渲染出來后,設置ready為true,再渲染插槽中的DOM元素。
2.4.1、initConfig
initConfig () {
const { dom } = this
// 當前屏幕分辨率
const { width, height } = screen
this.allWidth = width
dom.style.width = `${width}px`
dom.style.height = `${height}px`
},
作用:
- 獲取當前設備屏幕的分辨率
- 將這個分辨率寬高設置為組件DOM的寬高
2.4.2、setAppScale
setAppScale () {
const { allWidth, dom } = this
const currentWidth = document.body.clientWidth
dom.style.transform = `scale(${currentWidth / allWidth})`
},
它的作用是改變當前DOM的縮放比率。
縮放比率 = 當前窗口的可視寬度 / 當前設備的屏幕分辨率(寬度)
第3步、beforeDestroy(組件卸載時)
beforeDestroy () {
const { unbindDomResizeCallback } = this
unbindDomResizeCallback()
}
我們之前對于dom的style屬性和window的resize都做了監(jiān)聽,所以當我們組件卸載時這些監(jiān)聽事件也需要移除,如果不移除,那么到其他頁面,做這些操作,監(jiān)聽事件仍然存在,但其實我們已經不需要再對他監(jiān)聽了,反而會造成性能浪費。
3.1、unbindDomResizeCallback
unbindDomResizeCallback () {
let { domObserver, debounceInitWHFun } = this
if (!domObserver) return
domObserver.disconnect()
domObserver.takeRecords()
domObserver = null
window.removeEventListener('resize', debounceInitWHFun)
}
disconnect方法用來停止觀察。調用該方法后,DOM 再發(fā)生變動,也不會觸發(fā)觀察器。
takeRecords用來清除變動記錄,即不再處理未處理的變動。該方法返回變動記錄的數組。
小結
通過這個源碼閱讀,我們學習到了
1、函數的拆分(每個函數都只執(zhí)行一個功能)
2、使用對象解構賦值,避免濫用this去讀取data和methods中的數據和方法
3、使用MutationObserver來監(jiān)聽DOM的變動
其實在閱讀源碼時,也發(fā)現了一個小問題,就是使用mixin,會不利于代碼的閱讀,雖然他可以讓我們復用一部分代碼邏輯,但也增加了代碼的可閱讀性難度。(它的一些變量和方法的調用,需要我們多個文件來回尋找)
正好閱讀到一篇文章,vue3的自定義hook可以很好的解決mixin的問題,那么我們就用vue3來重寫下這個組件吧。
以上就是DataV 全屏容器組件源碼解析的詳細內容,更多關于DataV 全屏容器組件的資料請關注腳本之家其它相關文章!

