From eb054031d2a8979f2683527ace978bb0034e12a0 Mon Sep 17 00:00:00 2001 From: Waleed Khaled Date: Mon, 5 Sep 2022 18:02:50 +0400 Subject: [PATCH] fix(useDevicePixelRatio): more efficient mechanism (#2044) Co-authored-by: Anthony Fu --- packages/core/useDevicePixelRatio/demo.vue | 1 + packages/core/useDevicePixelRatio/index.md | 2 +- packages/core/useDevicePixelRatio/index.ts | 53 +++++++++------------- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/packages/core/useDevicePixelRatio/demo.vue b/packages/core/useDevicePixelRatio/demo.vue index 5e369a57651..fe8e8917801 100644 --- a/packages/core/useDevicePixelRatio/demo.vue +++ b/packages/core/useDevicePixelRatio/demo.vue @@ -10,4 +10,5 @@ const code = stringify(pixelRatio) diff --git a/packages/core/useDevicePixelRatio/index.md b/packages/core/useDevicePixelRatio/index.md index 1dc274689be..c7aaadb50b0 100644 --- a/packages/core/useDevicePixelRatio/index.md +++ b/packages/core/useDevicePixelRatio/index.md @@ -6,7 +6,7 @@ category: Sensors Reactively track [`window.devicePixelRatio`](https://developer.mozilla.org/ru/docs/Web/API/Window/devicePixelRatio) > -> NOTE: there is no event listener for `window.devicePixelRatio` change. So this function uses [`Testing media queries programmatically (window.matchMedia)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) as described in [this example](https://stackoverflow.com/questions/28905420/window-devicepixelratio-change-listener/29653772#29653772), but unlike the example this function subscribes to **several** pixelRatio scales (taken from [mydevice.io](https://www.mydevice.io/)) to detect any `window.devicePixelRatio` change. +> NOTE: there is no event listener for `window.devicePixelRatio` change. So this function uses [`Testing media queries programmatically (window.matchMedia)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) applying the same mechanism as described in [this example](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes). ## Usage diff --git a/packages/core/useDevicePixelRatio/index.ts b/packages/core/useDevicePixelRatio/index.ts index b93b2523bb6..b0e6f596864 100644 --- a/packages/core/useDevicePixelRatio/index.ts +++ b/packages/core/useDevicePixelRatio/index.ts @@ -1,24 +1,7 @@ -import { ref, watch } from 'vue-demi' -import { useEventListener } from '../useEventListener' -import { useMediaQuery } from '../useMediaQuery' -import type { ConfigurableWindow } from '../_configurable' -import { defaultWindow } from '../_configurable' - -// device pixel ratio statistics from https://www.mydevice.io/ -const DEVICE_PIXEL_RATIO_SCALES = [ - 1, - 1.325, - 1.4, - 1.5, - 1.8, - 2, - 2.4, - 2.5, - 2.75, - 3, - 3.5, - 4, -] +import { ref } from 'vue-demi' +import { type Fn, tryOnScopeDispose } from '@vueuse/shared' +import { type ConfigurableWindow, defaultWindow } from '../_configurable' + /** * Reactively track `window.devicePixelRatio`. * @@ -34,21 +17,27 @@ export function useDevicePixelRatio({ } } - const pixelRatio = ref(window.devicePixelRatio) + const pixelRatio = ref(1) - const handleDevicePixelRatio = () => { - pixelRatio.value = window.devicePixelRatio - } + const cleanups: Fn[] = [] - useEventListener(window, 'resize', handleDevicePixelRatio, { passive: true }) + const cleanup = () => { + cleanups.map(i => i()) + cleanups.length = 0 + } - DEVICE_PIXEL_RATIO_SCALES.forEach((dppx) => { - // listen mql events in both sides - const mqlMin = useMediaQuery(`screen and (min-resolution: ${dppx}dppx)`) - const mqlMax = useMediaQuery(`screen and (max-resolution: ${dppx}dppx)`) + const observe = () => { + pixelRatio.value = window.devicePixelRatio + cleanup() + const media = window.matchMedia(`(resolution: ${pixelRatio.value}dppx)`) + media.addEventListener('change', observe, { once: true }) + cleanups.push(() => { + media.removeEventListener('change', observe) + }) + } - watch([mqlMin, mqlMax], handleDevicePixelRatio) - }) + observe() + tryOnScopeDispose(cleanup) return { pixelRatio } }