DataV 全屏容器组件源码解析

 更新时间:2023年04月07日 14:17:01   作者:叁两  
这篇文章主要为大家介绍了DataV 全屏容器组件源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

数据可视化页面一般在浏览器中进行全屏展示,全屏容器将根据屏幕比例及当前浏览器窗口大小,自动进行缩放处理。浏览器全屏后,全屏容器将充满屏幕。

接下来我们来一起阅读下DataV中关于全屏容器的源码,看下它是如何实现的。

源码阅读(vue2版本)

它的源码位置

看下它的DOM结构,很简单

<div id="dv-full-screen-container" :ref="ref">
    <template v-if="ready">
      <slot></slot>
    </template>
</div>

源码分析

接下来重点看下它的JS实现,它的代码中混入了autoResize.js,所以我们需要两个文件一起看,不然会对突然出现的变量很奇怪。(如果觉得分开不便于阅读,其实我们可以把它合在一起来阅读,是一样的)

梳理下它的执行逻辑:

第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已经渲染好了,再去执行其他函数。

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

    // 监听dom元素变化
    bindDomResizeCallback () {
      const { dom, debounceInitWHFun } = this
      this.domObserver = observerDomResize(dom, debounceInitWHFun)
      window.addEventListener('resize', debounceInitWHFun)
    },

很重要的一步,其中使用了observerDomResize来对这个组件dom进行监听。

需要监听的DOM变化:

  • 窗口大小改变时触发的事件
  • dom的样式改变时触发

第一个直接使用window监听resize事件即可。

第二个对dom元素的监听,我们就需要使用MutationObserver来做了。

MutationObserver用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动都会触发MutationObserver事件。

封装一个observerDomResize函数来对dom的style属性变化进行监听

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节点渲染出来后,设置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都做了监听,所以当我们组件卸载时这些监听事件也需要移除,如果不移除,那么到其他页面,做这些操作,监听事件仍然存在,但其实我们已经不需要再对他监听了,反而会造成性能浪费。

3.1、unbindDomResizeCallback

    unbindDomResizeCallback () {
      let { domObserver, debounceInitWHFun } = this
      if (!domObserver) return
      domObserver.disconnect()
      domObserver.takeRecords()
      domObserver = null
      window.removeEventListener('resize', debounceInitWHFun)
    }

disconnect方法用来停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器。

takeRecords用来清除变动记录,即不再处理未处理的变动。该方法返回变动记录的数组。

小结

通过这个源码阅读,我们学习到了

1、函数的拆分(每个函数都只执行一个功能)

2、使用对象解构赋值,避免滥用this去读取data和methods中的数据和方法

3、使用MutationObserver来监听DOM的变动

其实在阅读源码时,也发现了一个小问题,就是使用mixin,会不利于代码的阅读,虽然他可以让我们复用一部分代码逻辑,但也增加了代码的可阅读性难度。(它的一些变量和方法的调用,需要我们多个文件来回寻找)

正好阅读到一篇文章,vue3的自定义hook可以很好的解决mixin的问题,那么我们就用vue3来重写下这个组件吧。

以上就是DataV 全屏容器组件源码解析的详细内容,更多关于DataV 全屏容器组件的资料请关注脚本之家其它相关文章!

相关文章

  • vue实现自定义el-table穿梭框功能

    vue实现自定义el-table穿梭框功能

    这篇文章主要介绍了vue实现自定义el-table穿梭框功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • 解决Vue watch里调用方法的坑

    解决Vue watch里调用方法的坑

    这篇文章主要介绍了解决Vue watch里调用方法的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • Vue监听器简单使用及注意事项说明

    Vue监听器简单使用及注意事项说明

    这篇文章主要介绍了Vue监听器简单使用及注意事项说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Vue 通过自定义指令回顾v-内置指令(小结)

    Vue 通过自定义指令回顾v-内置指令(小结)

    这篇文章主要介绍了Vue 通过自定义指令回顾v-内置指令(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • Vue3使用TypeIt实现文字打字机效果的代码示例

    Vue3使用TypeIt实现文字打字机效果的代码示例

    在现代网页设计中,文字打字机效果是一种非常流行的动画效果,能够吸引用户的注意力并提升用户体验,本文将介绍如何在 Vue 3 中使用 TypeIt 库实现文字打字机效果,并分享一些实用的技巧和示例,需要的朋友可以参考下
    2025-01-01
  • 深入理解vue-loader如何使用

    深入理解vue-loader如何使用

    本篇文章主要介绍了vue-loader,vue-loader是webpack下loader插件 可以把.vue文件输出成组件,有兴趣的可以了解一下
    2017-06-06
  • 使用Vue3和Vite实现对低版本浏览器的兼容

    使用Vue3和Vite实现对低版本浏览器的兼容

    在使用Vite和Vue3构建的JavaScript项目中,确保对低版本浏览器的兼容性是一个重要的考虑因素,以下是一些具体的解决方案和步骤,可以帮助你实现这一目标,需要的朋友可以参考下
    2024-11-11
  • vue中字典的使用

    vue中字典的使用

    这篇文章主要介绍了vue中字典的使用,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • vue如何实现自定义底部菜单栏

    vue如何实现自定义底部菜单栏

    这篇文章主要介绍了vue如何实现自定义底部菜单栏,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • webpack中的optimization配置示例详解

    webpack中的optimization配置示例详解

    这篇文章主要介绍了webpack中的optimization配置详解,主要就是根据不同的策略来分割打包出来的bundle,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02

最新评论