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<HTMLElement | null>(); const autoBindRef = once((ref: HTMLElement | ComponentPublicInstance) => { 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 useMutationObserver
To 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!