SoFunction
Updated on 2025-04-05

Detailed explanation of the full-screen container component of vue3 hook refactoring DataV

Preface

In the previous article, we carefully read the source code of DataV's full-screen container component. First, let's sort out its implementation logic.

  • Get the component dom and get its visible width and height
  • Get the resolution of the device screen as the width and height of the dom
  • The dom is scaled according to the width of the current viewport/screen resolution width as the scale ratio
  • Listen to the change of style element and resize of the dom element. If it changes, execute 3
  • Recycle listening events when component is destroyed

accomplish

Create Components

<template>
  <div  :ref="autoBindRef">
    <slot></slot>
  </div>
</template>
<script setup lang="ts">
import { useAutoResize } from '@/hooks/useAutoResize'
const { autoBindRef } = useAutoResize()
</script>

Customize a hook, export an autoBindRef binding ref

Custom hook files

import { ref } from 'vue';
export function useAutoResize() {
    let domRef = ref<HTMLElement | null>();
    function autoBindRef() {
    }
    return {
        autoBindRef
    }
}

1. Bind domRef

Make sure to get the dom element first so that the logic can continue to go down.

Create a function to detect and get the correct dom element

function getRefDom(ref: HTMLElement | ComponentPublicInstance): HTMLElement | null {
  // ref points to dom, then ref returns  // isElement checks whether the specified value is a DOM element  if (isElement(ref)) {
    return ref as HTMLElement
  }
  // If ref points to component instance, get the dom element through $el  if (isElement((ref as ComponentPublicInstance).$el)) {
    return (ref as ComponentPublicInstance).$el
  }
  return null
}

Automatically bind component domRef

export function useAutoResize() {
    let domRef = ref&lt;HTMLElement | null&gt;();
    const autoBindRef = once((ref: HTMLElement | ComponentPublicInstance) =&gt;  {
        const  dom = getRefDom(ref);
        if(!dom) {
            ("Binding component domRef failed!")
            return;
        }
         = dom;
    })
    return {
        autoBindRef
    }
}

2. Initialization

export function useAutoResize() {
    onMounted(() => {
        initDom()
        initConifg()
    })
}

During the mounted period, the dom has been mounted, so the dom element needs to be obtained in this cycle.

2.1. Initialize the dom

function initDom(dom:HTMLElement) {
    const { clientWidth = 0, clientHeight = 0 } = dom || {}
    if(!dom) {
        ("Failed to obtain the dom node, component rendering may be abnormal!")
        return
    } else if(!clientWidth || !clientHeight) {
        ("The component width or height is 0px, and a rendering exception may occur!")
        return
    }
    // Set the scaling ratio    if(typeof setAppSacle === 'function') setAppScale(dom)
}

2.2. Initialize the device

After obtaining the dom, set the screen resolution, width and height of the obtained device to the dom.

function initConfig(dom:HTMLElement) {
    const { width, height } = screen || {}
     = `${width}px`;
     = `${height}px`;
}

2.3. Set the zoom effect

function setAppScale(dom:HTMLElement){
    const currentWidth = ;
    const { width } = screen || {};
     = `scale(${currentWidth / width})`;
}

This function is triggered when the dom element changes/window size changes.

3. Listen/remove events

It is necessary to monitor changes in dom elements and window size at the same time

dom element monitoring

Here we useMutationObserverTo monitor the changes of dom elements

function observerDomResize(dom: HTMLElement, callback: () => void) {
    const observer = new MutationObserver(callback);
    (dom, {
        attributes: true,
        attributeFilter: ['style'],
        attributeOldValue: true,
    })
    return observer
}

Set up listening during mounted cycle

export function useAutoResize() {
    const handleInitDom = () => {
        initDom()
    }
    onMounted(() => {
        initDom()
        initConifg()
        observerDomResize(, handleInitDom)
        ('resize', handleInitDom);
    })
}

But if we write this directly, it will frequently call the handleInitDom function, causing performance waste, so use the anti-shake function to wrap the event handling function handleInitDom before calling it.

export function useAutoResize() {
    const domSizeEffectDisposer: (() => void)[] = [];
    const debounceInitDomFun = debounce(handleInitDom, 300)
    onMounted(() => {
        initDom()
        initConifg()
        observerDomResize(, debounceInitDomFun)
        ('resize', debounceInitDomFun);
        (
          () => {
            if (!observer) return
            ();
            ();
            observer = null;
          },
          () => {
            ('resize', debounceInitDomFun);
          }
        );
    })
}

After listening for an event, you must clear the component when it is uninstalled.

onUnmounted(() => {
    (disposer => disposer())
  })

summary

In this way, we complete the packaging of a full-screen container component of vue3. Custom hooks are really delicious ~

The above is the detailed explanation of the full-screen container component of vue3 hook to refactor DataV. For more information about vue3 hook to refactor DataV, please pay attention to my other related articles!