one-screen-scale 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +186 -180
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +46 -46
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/react.cjs.js +1 -1
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.d.ts +19 -19
- package/dist/react.esm.js +1 -1
- package/dist/react.esm.js.map +1 -1
- package/package.json +71 -71
- package/src/composables.js +67 -67
- package/src/core.js +160 -156
- package/src/directives.js +34 -34
- package/src/index.d.ts +46 -46
- package/src/index.js +14 -14
- package/src/react.d.ts +19 -19
- package/src/react.js +46 -46
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/core.js","../src/directives.js","../src/composables.js"],"sourcesContent":["/**\n * 一屏自适应缩放 — 核心算法(框架无关)\n *\n * 两种模式:\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\n */\n\n// ---------- helpers ----------\n\nfunction resolveEl(el) {\n if (!el) return null\n if (typeof el === 'string') return document.querySelector(el)\n if (el instanceof HTMLElement) return el\n // Vue ref / React ref\n if (el.value instanceof HTMLElement) return el.value\n if (el.current instanceof HTMLElement) return el.current\n return null\n}\n\n// ---------- scale calculation ----------\n\nexport function calculateScale({\n sourceWidth,\n sourceHeight,\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\n mode = 'contain',\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\n screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\n}) {\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\n\n let scale\n\n if (mode === 'fixed-width') {\n if(screenWidth < visualWidth){\n scale = 1\n }else{\n scale = visualWidth / Math.max(targetWidth, screenWidth)\n }\n } else {\n const sx = targetWidth / sourceWidth\n const sy = targetHeight / sourceHeight\n scale = Math.min(sx, sy)\n }\n\n return scale\n}\n\n// ---------- apply / read ----------\n\nexport function applyScale(el, scale, origin = 'top center') {\n const target = resolveEl(el)\n if (!target) return\n target.style.transform = `scale(${scale})`\n target.style.transformOrigin = origin\n}\n\nexport function getPageScale(el) {\n const target = resolveEl(el)\n if (!target) return 1\n\n const style = window.getComputedStyle(target)\n const t = style.transform\n if (!t || t === 'none') return 1\n\n // matrix(a, b, c, d, e, f) — 2d\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\n\n // matrix3d — 3d\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\n\n // scale(x, y) or scale(s)\n const sm = t.match(/scale\\(([^)]+)\\)/)\n if (sm) {\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\n }\n\n return 1\n}\n\nexport function getInverseScale(el = '.share-page') {\n const s = getPageScale(el)\n return s > 0 ? 1 / s : 1\n}\n\n// ---------- scaler instance ----------\n\nexport function createScaler(el, options = {}) {\n const target = resolveEl(el)\n if (!target) throw new Error('[one-screen-scale] element not found')\n\n const {\n mode = 'contain',\n visualWidth = 450,\n origin = 'top center',\n autoResize = true\n } = options\n\n let currentScale = 1\n let handler = null\n\n function compute() {\n const sw = target.offsetWidth\n const sh = target.offsetHeight\n const tw = window.innerWidth\n const th = window.innerHeight\n\n return calculateScale({\n sourceWidth: sw,\n sourceHeight: sh,\n targetWidth: tw,\n targetHeight: th,\n mode,\n visualWidth,\n screenWidth: window.screen.width\n })\n }\n\n function refresh() {\n const next = compute()\n if (next !== currentScale) {\n currentScale = next\n applyScale(target, next, origin)\n\n // fixed-width 模式:反向补偿高度\n if (mode === 'fixed-width' && next > 0) {\n target.style.width = `${Math.max(window.innerWidth, window.screen.width)}px`\n target.style.height = `${Math.round(window.innerHeight / next)}px`\n }\n }\n return currentScale\n }\n\n function start() {\n refresh()\n if (autoResize) {\n handler = () => refresh()\n window.addEventListener('resize', handler)\n }\n return currentScale\n }\n\n function stop() {\n if (handler) {\n window.removeEventListener('resize', handler)\n handler = null\n }\n }\n\n return { start, stop, refresh, getScale: () => currentScale }\n}\n","/**\n * Vue 3 指令\n * v-fit-screen 页面级缩放\n * v-compensate 组件级反缩放补偿\n */\nimport { createScaler } from './core.js'\n\n// ---- v-fit-screen ----\n\nexport const vFitScreen = {\n mounted(el, binding) {\n const options = binding.value || {}\n const scaler = createScaler(el, options)\n scaler.start()\n el.__fitScreenScaler = scaler\n },\n\n updated(el, binding) {\n const scaler = el.__fitScreenScaler\n if (scaler) {\n const options = binding.value || {}\n // 简单处理:重新 refresh\n scaler.refresh()\n }\n },\n\n unmounted(el) {\n const scaler = el.__fitScreenScaler\n if (scaler) {\n scaler.stop()\n delete el.__fitScreenScaler\n }\n }\n}\n","/**\n * Vue 3 Composable\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\n */\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\nimport { createScaler, getInverseScale } from './core.js'\n\nexport function useFitScreen(targetRef, options = {}) {\n const scale = ref(1)\n const inverseScale = ref(1)\n\n let scaler = null\n let onResize = null\n\n function setup(el) {\n if (!el) return\n scaler = createScaler(el, options)\n const s = scaler.start()\n scale.value = s\n inverseScale.value = getInverseScale(el)\n\n onResize = () => {\n scale.value = scaler?.getScale?.() ?? 1\n inverseScale.value = getInverseScale(el)\n }\n window.addEventListener('resize', onResize)\n }\n\n function teardown() {\n if (onResize) {\n window.removeEventListener('resize', onResize)\n onResize = null\n }\n scaler?.stop()\n scaler = null\n }\n\n // 处理 ref 初始有值的情况\n onMounted(() => {\n const el = targetRef?.value ?? targetRef\n setup(el)\n })\n\n // 处理 ref 延迟赋值的情况(异步挂载)\n if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {\n watch(\n () => targetRef.value,\n (el) => {\n if (el && !scaler) setup(el)\n }\n )\n }\n\n onUnmounted(() => {\n teardown()\n })\n\n const refresh = () => {\n const el = targetRef?.value ?? targetRef\n if (!el || !scaler) return\n const s = scaler.refresh()\n scale.value = s\n inverseScale.value = getInverseScale(el)\n }\n\n return { scale, inverseScale, refresh }\n}\n"],"names":["resolveEl","el","document","querySelector","HTMLElement","value","current","calculateScale","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","mode","visualWidth","screenWidth","screen","width","scale","Math","max","sx","sy","min","applyScale","origin","target","style","transform","transformOrigin","getPageScale","t","getComputedStyle","m2","match","parseFloat","m3","sm","vals","split","map","v","trim","length","getInverseScale","s","createScaler","options","Error","autoResize","currentScale","handler","refresh","next","offsetWidth","offsetHeight","height","round","start","addEventListener","stop","removeEventListener","getScale","vFitScreen","mounted","binding","scaler","__fitScreenScaler","updated","unmounted","useFitScreen","targetRef","ref","inverseScale","onResize","setup","onMounted","watch","onUnmounted"],"mappings":"qEAUA,SAASA,EAAUC,GACjB,OAAKA,EACa,iBAAPA,EAAwBC,SAASC,cAAcF,GACtDA,aAAcG,YAAoBH,EAElCA,EAAGI,iBAAiBD,YAAoBH,EAAGI,MAC3CJ,EAAGK,mBAAmBF,YAAoBH,EAAGK,QAC1C,KANS,IAOlB,CAIO,SAASC,GAAeC,YAC7BA,EAAWC,aACXA,EAAYC,YACZA,GAAiC,oBAAXC,OAAyBA,OAAOC,WAAa,MAAKC,aACxEA,GAAkC,oBAAXF,OAAyBA,OAAOG,YAAc,MAAKC,KAC1EA,EAAO,UAASC,YAChBA,EAAc,IAAGC,YACjBA,GAAiC,oBAAXN,OAAyBA,OAAOO,OAAOC,MAAQ,QAErE,IAAKX,IAAgBC,GAAgBD,GAAe,GAAKC,GAAgB,EAAG,OAAO,EAEnF,IAAIW,EAEJ,GAAa,gBAATL,EAEAK,EADCH,EAAcD,EACP,EAEAA,EAAcK,KAAKC,IAAIZ,EAAaO,OAEzC,CACL,MAAMM,EAAKb,EAAcF,EACnBgB,EAAKX,EAAeJ,EAC1BW,EAAQC,KAAKI,IAAIF,EAAIC,EACtB,CAED,OAAOJ,CACT,CAIO,SAASM,EAAWzB,EAAImB,EAAOO,EAAS,cAC7C,MAAMC,EAAS5B,EAAUC,GACpB2B,IACLA,EAAOC,MAAMC,UAAY,SAASV,KAClCQ,EAAOC,MAAME,gBAAkBJ,EACjC,CAEO,SAASK,EAAa/B,GAC3B,MAAM2B,EAAS5B,EAAUC,GACzB,IAAK2B,EAAQ,OAAO,EAEpB,MACMK,EADQtB,OAAOuB,iBAAiBN,GACtBE,UAChB,IAAKG,GAAW,SAANA,EAAc,OAAO,EAG/B,MAAME,EAAKF,EAAEG,MAAM,gDACnB,GAAID,EAAI,OAAQE,WAAWF,EAAG,IAAME,WAAWF,EAAG,KAAO,EAGzD,MAAMG,EAAKL,EAAEG,MAAM,mHACnB,GAAIE,EAAI,OAAQD,WAAWC,EAAG,IAAMD,WAAWC,EAAG,KAAO,EAGzD,MAAMC,EAAKN,EAAEG,MAAM,oBACnB,GAAIG,EAAI,CACN,MAAMC,EAAOD,EAAG,GAAGE,MAAM,KAAKC,IAAIC,GAAKN,WAAWM,EAAEC,SACpD,OAAOJ,EAAKK,QAAU,GAAKL,EAAK,GAAKA,EAAK,IAAM,EAAIA,EAAK,EAC1D,CAED,OAAO,CACT,CAEO,SAASM,EAAgB7C,EAAK,eACnC,MAAM8C,EAAIf,EAAa/B,GACvB,OAAO8C,EAAI,EAAI,EAAIA,EAAI,CACzB,CAIO,SAASC,EAAa/C,EAAIgD,EAAU,IACzC,MAAMrB,EAAS5B,EAAUC,GACzB,IAAK2B,EAAQ,MAAM,IAAIsB,MAAM,wCAE7B,MAAMnC,KACJA,EAAO,UAASC,YAChBA,EAAc,IAAGW,OACjBA,EAAS,aAAYwB,WACrBA,GAAa,GACXF,EAEJ,IAAIG,EAAe,EACfC,EAAU,KAmBd,SAASC,IACP,MAAMC,EAZChD,EAAe,CACpBC,YANSoB,EAAO4B,YAOhB/C,aANSmB,EAAO6B,aAOhB/C,YANSC,OAAOC,WAOhBC,aANSF,OAAOG,YAOhBC,OACAC,cACAC,YAAaN,OAAOO,OAAOC,QAgB7B,OAVIoC,IAASH,IACXA,EAAeG,EACf7B,EAAWE,EAAQ2B,EAAM5B,GAGZ,gBAATZ,GAA0BwC,EAAO,IACnC3B,EAAOC,MAAMV,MAAQ,GAAGE,KAAKC,IAAIX,OAAOC,WAAYD,OAAOO,OAAOC,WAClES,EAAOC,MAAM6B,OAAS,GAAGrC,KAAKsC,MAAMhD,OAAOG,YAAcyC,SAGtDH,CACR,CAkBD,MAAO,CAAEQ,MAhBT,WAME,OALAN,IACIH,IACFE,EAAU,IAAMC,IAChB3C,OAAOkD,iBAAiB,SAAUR,IAE7BD,CACR,EASeU,KAPhB,WACMT,IACF1C,OAAOoD,oBAAoB,SAAUV,GACrCA,EAAU,KAEb,EAEqBC,UAASU,SAAU,IAAMZ,EACjD,CClJY,MAACa,EAAa,CACxB,OAAAC,CAAQjE,EAAIkE,GACV,MACMC,EAASpB,EAAa/C,EADZkE,EAAQ9D,OAAS,CAAE,GAEnC+D,EAAOR,QACP3D,EAAGoE,kBAAoBD,CACxB,EAED,OAAAE,CAAQrE,EAAIkE,GACV,MAAMC,EAASnE,EAAGoE,kBACdD,IACcD,EAAQ9D,MAExB+D,EAAOd,UAEV,EAED,SAAAiB,CAAUtE,GACR,MAAMmE,EAASnE,EAAGoE,kBACdD,IACFA,EAAON,cACA7D,EAAGoE,kBAEb,GCzBI,SAASG,EAAaC,EAAWxB,EAAU,IAChD,MAAM7B,EAAQsD,EAAI,GACZC,EAAeD,EAAI,GAEzB,IAAIN,EAAS,KACTQ,EAAW,KAEf,SAASC,EAAM5E,GACb,IAAKA,EAAI,OACTmE,EAASpB,EAAa/C,EAAIgD,GAC1B,MAAMF,EAAIqB,EAAOR,QACjBxC,EAAMf,MAAQ0C,EACd4B,EAAatE,MAAQyC,EAAgB7C,GAErC2E,EAAW,KACTxD,EAAMf,MAAQ+D,GAAQJ,cAAgB,EACtCW,EAAatE,MAAQyC,EAAgB7C,IAEvCU,OAAOkD,iBAAiB,SAAUe,EACnC,CAYDE,EAAU,KAERD,EADWJ,GAAWpE,OAASoE,KAK7BA,GAAkC,iBAAdA,GAA0B,UAAWA,GAC3DM,EACE,IAAMN,EAAUpE,MACfJ,IACKA,IAAOmE,GAAQS,EAAM5E,KAK/B+E,EAAY,KAxBNJ,IACFjE,OAAOoD,oBAAoB,SAAUa,GACrCA,EAAW,MAEbR,GAAQN,OACRM,EAAS,OA+BX,MAAO,CAAEhD,QAAOuD,eAAcrB,QARd,KACd,MAAMrD,EAAKwE,GAAWpE,OAASoE,EAC/B,IAAKxE,IAAOmE,EAAQ,OACpB,MAAMrB,EAAIqB,EAAOd,UACjBlC,EAAMf,MAAQ0C,EACd4B,EAAatE,MAAQyC,EAAgB7C,IAIzC"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/core.js","../src/directives.js","../src/composables.js"],"sourcesContent":["/**\r\n * 一屏自适应缩放 — 核心算法(框架无关)\r\n *\r\n * 两种模式:\r\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\r\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\r\n */\r\n\r\n// ---------- helpers ----------\r\n\r\nfunction resolveEl(el) {\r\n if (!el) return null\r\n if (typeof el === 'string') return document.querySelector(el)\r\n if (el instanceof HTMLElement) return el\r\n // Vue ref / React ref\r\n if (el.value instanceof HTMLElement) return el.value\r\n if (el.current instanceof HTMLElement) return el.current\r\n return null\r\n}\r\n\r\n// ---------- scale calculation ----------\r\n\r\nexport function calculateScale({\r\n sourceWidth,\r\n sourceHeight,\r\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\r\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\r\n mode = 'contain',\r\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\r\n // screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\r\n}) {\r\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\r\n\r\n let scale\r\n\r\n if (mode === 'fixed-width') {\r\n // if(screenWidth < visualWidth){\r\n // scale = 1\r\n // }else{\r\n // scale = visualWidth / Math.max(targetWidth, screenWidth)\r\n // }\r\n // 只用视口宽:视口比目标宽才缩小,否则 1:1(保持清晰)\r\n scale = targetWidth > visualWidth ? visualWidth / targetWidth : 1\r\n } else {\r\n const sx = targetWidth / sourceWidth\r\n const sy = targetHeight / sourceHeight\r\n scale = Math.min(sx, sy)\r\n }\r\n\r\n return scale\r\n}\r\n\r\n// ---------- apply / read ----------\r\n\r\nexport function applyScale(el, scale, origin = 'top center') {\r\n const target = resolveEl(el)\r\n if (!target) return\r\n target.style.transform = `scale(${scale})`\r\n target.style.transformOrigin = origin\r\n}\r\n\r\nexport function getPageScale(el) {\r\n const target = resolveEl(el)\r\n if (!target) return 1\r\n\r\n const style = window.getComputedStyle(target)\r\n const t = style.transform\r\n if (!t || t === 'none') return 1\r\n\r\n // matrix(a, b, c, d, e, f) — 2d\r\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\r\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\r\n\r\n // matrix3d — 3d\r\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\r\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\r\n\r\n // scale(x, y) or scale(s)\r\n const sm = t.match(/scale\\(([^)]+)\\)/)\r\n if (sm) {\r\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\r\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\r\n }\r\n\r\n return 1\r\n}\r\n\r\nexport function getInverseScale(el = '.share-page') {\r\n const s = getPageScale(el)\r\n return s > 0 ? 1 / s : 1\r\n}\r\n\r\n// ---------- scaler instance ----------\r\n\r\nexport function createScaler(el, options = {}) {\r\n const target = resolveEl(el)\r\n if (!target) throw new Error('[one-screen-scale] element not found')\r\n\r\n const {\r\n mode = 'contain',\r\n visualWidth = 450,\r\n origin = 'top center',\r\n autoResize = true\r\n } = options\r\n\r\n let currentScale = 1\r\n let handler = null\r\n\r\n function compute() {\r\n const sw = target.offsetWidth\r\n const sh = target.offsetHeight\r\n const tw = document.documentElement.clientWidth || window.innerWidth\r\n const th = window.innerHeight\r\n\r\n return calculateScale({\r\n sourceWidth: sw,\r\n sourceHeight: sh,\r\n targetWidth: tw,\r\n targetHeight: th,\r\n mode,\r\n visualWidth,\r\n // screenWidth: window.screen.width\r\n })\r\n }\r\n\r\n function refresh() {\r\n const next = compute()\r\n if (next !== currentScale) {\r\n currentScale = next\r\n applyScale(target, next, origin)\r\n }\r\n\r\n // fixed-width 模式:反向补偿高度\r\n if (mode === 'fixed-width' && next > 0) {\r\n // target.style.width = `${Math.max(window.innerWidth, window.screen.width)}px`\r\n const viewportWidth = document.documentElement.clientWidth || window.innerWidth\r\n target.style.width = `${viewportWidth}px`\r\n target.style.height = `${Math.round(window.innerHeight / next)}px`\r\n }\r\n return currentScale\r\n }\r\n\r\n function start() {\r\n refresh()\r\n if (autoResize) {\r\n handler = () => refresh()\r\n window.addEventListener('resize', handler)\r\n }\r\n return currentScale\r\n }\r\n\r\n function stop() {\r\n if (handler) {\r\n window.removeEventListener('resize', handler)\r\n handler = null\r\n }\r\n }\r\n\r\n return { start, stop, refresh, getScale: () => currentScale }\r\n}\r\n","/**\r\n * Vue 3 指令\r\n * v-fit-screen 页面级缩放\r\n * v-compensate 组件级反缩放补偿\r\n */\r\nimport { createScaler } from './core.js'\r\n\r\n// ---- v-fit-screen ----\r\n\r\nexport const vFitScreen = {\r\n mounted(el, binding) {\r\n const options = binding.value || {}\r\n const scaler = createScaler(el, options)\r\n scaler.start()\r\n el.__fitScreenScaler = scaler\r\n },\r\n\r\n updated(el, binding) {\r\n const scaler = el.__fitScreenScaler\r\n if (scaler) {\r\n const options = binding.value || {}\r\n // 简单处理:重新 refresh\r\n scaler.refresh()\r\n }\r\n },\r\n\r\n unmounted(el) {\r\n const scaler = el.__fitScreenScaler\r\n if (scaler) {\r\n scaler.stop()\r\n delete el.__fitScreenScaler\r\n }\r\n }\r\n}\r\n","/**\r\n * Vue 3 Composable\r\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\r\n */\r\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\r\nimport { createScaler, getInverseScale } from './core.js'\r\n\r\nexport function useFitScreen(targetRef, options = {}) {\r\n const scale = ref(1)\r\n const inverseScale = ref(1)\r\n\r\n let scaler = null\r\n let onResize = null\r\n\r\n function setup(el) {\r\n if (!el) return\r\n scaler = createScaler(el, options)\r\n const s = scaler.start()\r\n scale.value = s\r\n inverseScale.value = getInverseScale(el)\r\n\r\n onResize = () => {\r\n scale.value = scaler?.getScale?.() ?? 1\r\n inverseScale.value = getInverseScale(el)\r\n }\r\n window.addEventListener('resize', onResize)\r\n }\r\n\r\n function teardown() {\r\n if (onResize) {\r\n window.removeEventListener('resize', onResize)\r\n onResize = null\r\n }\r\n scaler?.stop()\r\n scaler = null\r\n }\r\n\r\n // 处理 ref 初始有值的情况\r\n onMounted(() => {\r\n const el = targetRef?.value ?? targetRef\r\n setup(el)\r\n })\r\n\r\n // 处理 ref 延迟赋值的情况(异步挂载)\r\n if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {\r\n watch(\r\n () => targetRef.value,\r\n (el) => {\r\n if (el && !scaler) setup(el)\r\n }\r\n )\r\n }\r\n\r\n onUnmounted(() => {\r\n teardown()\r\n })\r\n\r\n const refresh = () => {\r\n const el = targetRef?.value ?? targetRef\r\n if (!el || !scaler) return\r\n const s = scaler.refresh()\r\n scale.value = s\r\n inverseScale.value = getInverseScale(el)\r\n }\r\n\r\n return { scale, inverseScale, refresh }\r\n}\r\n"],"names":["resolveEl","el","document","querySelector","HTMLElement","value","current","calculateScale","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","mode","visualWidth","scale","sx","sy","Math","min","applyScale","origin","target","style","transform","transformOrigin","getPageScale","t","getComputedStyle","m2","match","parseFloat","m3","sm","vals","split","map","v","trim","length","getInverseScale","s","createScaler","options","Error","autoResize","currentScale","handler","refresh","next","offsetWidth","offsetHeight","documentElement","clientWidth","viewportWidth","width","height","round","start","addEventListener","stop","removeEventListener","getScale","vFitScreen","mounted","binding","scaler","__fitScreenScaler","updated","unmounted","useFitScreen","targetRef","ref","inverseScale","onResize","setup","onMounted","watch","onUnmounted"],"mappings":"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"}
|
package/dist/react.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react");function t(e){return e?"string"==typeof e?document.querySelector(e):e instanceof HTMLElement?e:e.value instanceof HTMLElement?e.value:e.current instanceof HTMLElement?e.current:null:null}function n(e,n={}){const r=t(e);if(!r)throw new Error("[one-screen-scale] element not found");const{mode:i="contain",visualWidth:o=450,origin:s="top center",autoResize:
|
|
1
|
+
"use strict";var e=require("react");function t(e){return e?"string"==typeof e?document.querySelector(e):e instanceof HTMLElement?e:e.value instanceof HTMLElement?e.value:e.current instanceof HTMLElement?e.current:null:null}function n(e,n={}){const r=t(e);if(!r)throw new Error("[one-screen-scale] element not found");const{mode:i="contain",visualWidth:o=450,origin:s="top center",autoResize:u=!0}=n;let c=1,d=null;function l(){return function({sourceWidth:e,sourceHeight:t,targetWidth:n=("undefined"!=typeof window?window.innerWidth:1920),targetHeight:r=("undefined"!=typeof window?window.innerHeight:1080),mode:i="contain",visualWidth:o=450}){if(!e||!t||e<=0||t<=0)return 1;let s;if("fixed-width"===i)s=n>o?o/n:1;else{const i=n/e,o=r/t;s=Math.min(i,o)}return s}({sourceWidth:r.offsetWidth,sourceHeight:r.offsetHeight,targetWidth:document.documentElement.clientWidth||window.innerWidth,targetHeight:window.innerHeight,mode:i,visualWidth:o})}function f(){const e=l();if(e!==c&&(c=e,function(e,n,r="top center"){const i=t(e);i&&(i.style.transform=`scale(${n})`,i.style.transformOrigin=r)}(r,e,s)),"fixed-width"===i&&e>0){const t=document.documentElement.clientWidth||window.innerWidth;r.style.width=`${t}px`,r.style.height=`${Math.round(window.innerHeight/e)}px`}return c}return{start:function(){return f(),u&&(d=()=>f(),window.addEventListener("resize",d)),c},stop:function(){d&&(window.removeEventListener("resize",d),d=null)},refresh:f,getScale:()=>c}}exports.useFitScreen=function(t,r={}){const[i,o]=e.useState(1),[s,u]=e.useState(1),c=e.useRef(null);return e.useEffect(()=>{const e=t?.current??t;if(!e)return;const i=n(e,r);c.current=i;const s=i.start();o(s),u(s>0?1/s:1);const d=()=>{const e=i.getScale();o(e),u(e>0?1/e:1)};return window.addEventListener("resize",d),()=>{window.removeEventListener("resize",d),i.stop(),c.current=null}},[t]),{scale:i,inverseScale:s,refresh:e.useCallback(()=>{if(!(t?.current??t)||!c.current)return;const e=c.current.refresh();o(e),u(e>0?1/e:1)},[t])}};
|
|
2
2
|
//# sourceMappingURL=react.cjs.js.map
|
package/dist/react.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.cjs.js","sources":["../src/core.js","../src/react.js"],"sourcesContent":["/**\n * 一屏自适应缩放 — 核心算法(框架无关)\n *\n * 两种模式:\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\n */\n\n// ---------- helpers ----------\n\nfunction resolveEl(el) {\n if (!el) return null\n if (typeof el === 'string') return document.querySelector(el)\n if (el instanceof HTMLElement) return el\n // Vue ref / React ref\n if (el.value instanceof HTMLElement) return el.value\n if (el.current instanceof HTMLElement) return el.current\n return null\n}\n\n// ---------- scale calculation ----------\n\nexport function calculateScale({\n sourceWidth,\n sourceHeight,\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\n mode = 'contain',\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\n screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\n}) {\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\n\n let scale\n\n if (mode === 'fixed-width') {\n if(screenWidth < visualWidth){\n
|
|
1
|
+
{"version":3,"file":"react.cjs.js","sources":["../src/core.js","../src/react.js"],"sourcesContent":["/**\r\n * 一屏自适应缩放 — 核心算法(框架无关)\r\n *\r\n * 两种模式:\r\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\r\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\r\n */\r\n\r\n// ---------- helpers ----------\r\n\r\nfunction resolveEl(el) {\r\n if (!el) return null\r\n if (typeof el === 'string') return document.querySelector(el)\r\n if (el instanceof HTMLElement) return el\r\n // Vue ref / React ref\r\n if (el.value instanceof HTMLElement) return el.value\r\n if (el.current instanceof HTMLElement) return el.current\r\n return null\r\n}\r\n\r\n// ---------- scale calculation ----------\r\n\r\nexport function calculateScale({\r\n sourceWidth,\r\n sourceHeight,\r\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\r\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\r\n mode = 'contain',\r\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\r\n // screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\r\n}) {\r\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\r\n\r\n let scale\r\n\r\n if (mode === 'fixed-width') {\r\n // if(screenWidth < visualWidth){\r\n // scale = 1\r\n // }else{\r\n // scale = visualWidth / Math.max(targetWidth, screenWidth)\r\n // }\r\n // 只用视口宽:视口比目标宽才缩小,否则 1:1(保持清晰)\r\n scale = targetWidth > visualWidth ? visualWidth / targetWidth : 1\r\n } else {\r\n const sx = targetWidth / sourceWidth\r\n const sy = targetHeight / sourceHeight\r\n scale = Math.min(sx, sy)\r\n }\r\n\r\n return scale\r\n}\r\n\r\n// ---------- apply / read ----------\r\n\r\nexport function applyScale(el, scale, origin = 'top center') {\r\n const target = resolveEl(el)\r\n if (!target) return\r\n target.style.transform = `scale(${scale})`\r\n target.style.transformOrigin = origin\r\n}\r\n\r\nexport function getPageScale(el) {\r\n const target = resolveEl(el)\r\n if (!target) return 1\r\n\r\n const style = window.getComputedStyle(target)\r\n const t = style.transform\r\n if (!t || t === 'none') return 1\r\n\r\n // matrix(a, b, c, d, e, f) — 2d\r\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\r\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\r\n\r\n // matrix3d — 3d\r\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\r\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\r\n\r\n // scale(x, y) or scale(s)\r\n const sm = t.match(/scale\\(([^)]+)\\)/)\r\n if (sm) {\r\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\r\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\r\n }\r\n\r\n return 1\r\n}\r\n\r\nexport function getInverseScale(el = '.share-page') {\r\n const s = getPageScale(el)\r\n return s > 0 ? 1 / s : 1\r\n}\r\n\r\n// ---------- scaler instance ----------\r\n\r\nexport function createScaler(el, options = {}) {\r\n const target = resolveEl(el)\r\n if (!target) throw new Error('[one-screen-scale] element not found')\r\n\r\n const {\r\n mode = 'contain',\r\n visualWidth = 450,\r\n origin = 'top center',\r\n autoResize = true\r\n } = options\r\n\r\n let currentScale = 1\r\n let handler = null\r\n\r\n function compute() {\r\n const sw = target.offsetWidth\r\n const sh = target.offsetHeight\r\n const tw = document.documentElement.clientWidth || window.innerWidth\r\n const th = window.innerHeight\r\n\r\n return calculateScale({\r\n sourceWidth: sw,\r\n sourceHeight: sh,\r\n targetWidth: tw,\r\n targetHeight: th,\r\n mode,\r\n visualWidth,\r\n // screenWidth: window.screen.width\r\n })\r\n }\r\n\r\n function refresh() {\r\n const next = compute()\r\n if (next !== currentScale) {\r\n currentScale = next\r\n applyScale(target, next, origin)\r\n }\r\n\r\n // fixed-width 模式:反向补偿高度\r\n if (mode === 'fixed-width' && next > 0) {\r\n // target.style.width = `${Math.max(window.innerWidth, window.screen.width)}px`\r\n const viewportWidth = document.documentElement.clientWidth || window.innerWidth\r\n target.style.width = `${viewportWidth}px`\r\n target.style.height = `${Math.round(window.innerHeight / next)}px`\r\n }\r\n return currentScale\r\n }\r\n\r\n function start() {\r\n refresh()\r\n if (autoResize) {\r\n handler = () => refresh()\r\n window.addEventListener('resize', handler)\r\n }\r\n return currentScale\r\n }\r\n\r\n function stop() {\r\n if (handler) {\r\n window.removeEventListener('resize', handler)\r\n handler = null\r\n }\r\n }\r\n\r\n return { start, stop, refresh, getScale: () => currentScale }\r\n}\r\n","/**\r\n * React hook\r\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\r\n */\r\nimport { useRef, useState, useEffect, useCallback } from 'react'\r\nimport { createScaler } from './core.js'\r\n\r\nexport function useFitScreen(targetRef, options = {}) {\r\n const [scale, setScale] = useState(1)\r\n const [inverseScale, setInverseScale] = useState(1)\r\n const scalerRef = useRef(null)\r\n\r\n useEffect(() => {\r\n const el = targetRef?.current ?? targetRef\r\n if (!el) return\r\n\r\n const scaler = createScaler(el, options)\r\n scalerRef.current = scaler\r\n const s = scaler.start()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n\r\n const onResize = () => {\r\n const s = scaler.getScale()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n }\r\n window.addEventListener('resize', onResize)\r\n\r\n return () => {\r\n window.removeEventListener('resize', onResize)\r\n scaler.stop()\r\n scalerRef.current = null\r\n }\r\n }, [targetRef])\r\n\r\n const refresh = useCallback(() => {\r\n const el = targetRef?.current ?? targetRef\r\n if (!el || !scalerRef.current) return\r\n const s = scalerRef.current.refresh()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n }, [targetRef])\r\n\r\n return { scale, inverseScale, refresh }\r\n}\r\n"],"names":["resolveEl","el","document","querySelector","HTMLElement","value","current","createScaler","options","target","Error","mode","visualWidth","origin","autoResize","currentScale","handler","compute","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","scale","sx","sy","Math","min","calculateScale","offsetWidth","offsetHeight","documentElement","clientWidth","refresh","next","style","transform","transformOrigin","applyScale","viewportWidth","width","height","round","start","addEventListener","stop","removeEventListener","getScale","targetRef","setScale","useState","inverseScale","setInverseScale","scalerRef","useRef","useEffect","scaler","s","onResize","useCallback"],"mappings":"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"}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
// ===== React =====
|
|
2
|
-
|
|
3
|
-
import type { RefObject } from 'react'
|
|
4
|
-
|
|
5
|
-
export interface ScalerOptions {
|
|
6
|
-
mode?: 'contain' | 'fixed-width'
|
|
7
|
-
visualWidth?: number
|
|
8
|
-
origin?: string
|
|
9
|
-
autoResize?: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function useFitScreen(
|
|
13
|
-
targetRef: RefObject<HTMLElement | null> | HTMLElement,
|
|
14
|
-
options?: ScalerOptions
|
|
15
|
-
): {
|
|
16
|
-
scale: number
|
|
17
|
-
inverseScale: number
|
|
18
|
-
refresh: () => void
|
|
19
|
-
}
|
|
1
|
+
// ===== React =====
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface ScalerOptions {
|
|
6
|
+
mode?: 'contain' | 'fixed-width'
|
|
7
|
+
visualWidth?: number
|
|
8
|
+
origin?: string
|
|
9
|
+
autoResize?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useFitScreen(
|
|
13
|
+
targetRef: RefObject<HTMLElement | null> | HTMLElement,
|
|
14
|
+
options?: ScalerOptions
|
|
15
|
+
): {
|
|
16
|
+
scale: number
|
|
17
|
+
inverseScale: number
|
|
18
|
+
refresh: () => void
|
|
19
|
+
}
|
package/dist/react.esm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useState as e,useRef as
|
|
1
|
+
import{useState as e,useRef as t,useEffect as n,useCallback as r}from"react";function i(e){return e?"string"==typeof e?document.querySelector(e):e instanceof HTMLElement?e:e.value instanceof HTMLElement?e.value:e.current instanceof HTMLElement?e.current:null:null}function o(e,t={}){const n=i(e);if(!n)throw new Error("[one-screen-scale] element not found");const{mode:r="contain",visualWidth:o=450,origin:c="top center",autoResize:s=!0}=t;let u=1,d=null;function l(){return function({sourceWidth:e,sourceHeight:t,targetWidth:n=("undefined"!=typeof window?window.innerWidth:1920),targetHeight:r=("undefined"!=typeof window?window.innerHeight:1080),mode:i="contain",visualWidth:o=450}){if(!e||!t||e<=0||t<=0)return 1;let c;if("fixed-width"===i)c=n>o?o/n:1;else{const i=n/e,o=r/t;c=Math.min(i,o)}return c}({sourceWidth:n.offsetWidth,sourceHeight:n.offsetHeight,targetWidth:document.documentElement.clientWidth||window.innerWidth,targetHeight:window.innerHeight,mode:r,visualWidth:o})}function f(){const e=l();if(e!==u&&(u=e,function(e,t,n="top center"){const r=i(e);r&&(r.style.transform=`scale(${t})`,r.style.transformOrigin=n)}(n,e,c)),"fixed-width"===r&&e>0){const t=document.documentElement.clientWidth||window.innerWidth;n.style.width=`${t}px`,n.style.height=`${Math.round(window.innerHeight/e)}px`}return u}return{start:function(){return f(),s&&(d=()=>f(),window.addEventListener("resize",d)),u},stop:function(){d&&(window.removeEventListener("resize",d),d=null)},refresh:f,getScale:()=>u}}function c(i,c={}){const[s,u]=e(1),[d,l]=e(1),f=t(null);n(()=>{const e=i?.current??i;if(!e)return;const t=o(e,c);f.current=t;const n=t.start();u(n),l(n>0?1/n:1);const r=()=>{const e=t.getScale();u(e),l(e>0?1/e:1)};return window.addEventListener("resize",r),()=>{window.removeEventListener("resize",r),t.stop(),f.current=null}},[i]);return{scale:s,inverseScale:d,refresh:r(()=>{if(!(i?.current??i)||!f.current)return;const e=f.current.refresh();u(e),l(e>0?1/e:1)},[i])}}export{c as useFitScreen};
|
|
2
2
|
//# sourceMappingURL=react.esm.js.map
|
package/dist/react.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.esm.js","sources":["../src/core.js","../src/react.js"],"sourcesContent":["/**\n * 一屏自适应缩放 — 核心算法(框架无关)\n *\n * 两种模式:\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\n */\n\n// ---------- helpers ----------\n\nfunction resolveEl(el) {\n if (!el) return null\n if (typeof el === 'string') return document.querySelector(el)\n if (el instanceof HTMLElement) return el\n // Vue ref / React ref\n if (el.value instanceof HTMLElement) return el.value\n if (el.current instanceof HTMLElement) return el.current\n return null\n}\n\n// ---------- scale calculation ----------\n\nexport function calculateScale({\n sourceWidth,\n sourceHeight,\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\n mode = 'contain',\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\n screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\n}) {\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\n\n let scale\n\n if (mode === 'fixed-width') {\n if(screenWidth < visualWidth){\n
|
|
1
|
+
{"version":3,"file":"react.esm.js","sources":["../src/core.js","../src/react.js"],"sourcesContent":["/**\r\n * 一屏自适应缩放 — 核心算法(框架无关)\r\n *\r\n * 两种模式:\r\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\r\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\r\n */\r\n\r\n// ---------- helpers ----------\r\n\r\nfunction resolveEl(el) {\r\n if (!el) return null\r\n if (typeof el === 'string') return document.querySelector(el)\r\n if (el instanceof HTMLElement) return el\r\n // Vue ref / React ref\r\n if (el.value instanceof HTMLElement) return el.value\r\n if (el.current instanceof HTMLElement) return el.current\r\n return null\r\n}\r\n\r\n// ---------- scale calculation ----------\r\n\r\nexport function calculateScale({\r\n sourceWidth,\r\n sourceHeight,\r\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\r\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\r\n mode = 'contain',\r\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\r\n // screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\r\n}) {\r\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\r\n\r\n let scale\r\n\r\n if (mode === 'fixed-width') {\r\n // if(screenWidth < visualWidth){\r\n // scale = 1\r\n // }else{\r\n // scale = visualWidth / Math.max(targetWidth, screenWidth)\r\n // }\r\n // 只用视口宽:视口比目标宽才缩小,否则 1:1(保持清晰)\r\n scale = targetWidth > visualWidth ? visualWidth / targetWidth : 1\r\n } else {\r\n const sx = targetWidth / sourceWidth\r\n const sy = targetHeight / sourceHeight\r\n scale = Math.min(sx, sy)\r\n }\r\n\r\n return scale\r\n}\r\n\r\n// ---------- apply / read ----------\r\n\r\nexport function applyScale(el, scale, origin = 'top center') {\r\n const target = resolveEl(el)\r\n if (!target) return\r\n target.style.transform = `scale(${scale})`\r\n target.style.transformOrigin = origin\r\n}\r\n\r\nexport function getPageScale(el) {\r\n const target = resolveEl(el)\r\n if (!target) return 1\r\n\r\n const style = window.getComputedStyle(target)\r\n const t = style.transform\r\n if (!t || t === 'none') return 1\r\n\r\n // matrix(a, b, c, d, e, f) — 2d\r\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\r\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\r\n\r\n // matrix3d — 3d\r\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\r\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\r\n\r\n // scale(x, y) or scale(s)\r\n const sm = t.match(/scale\\(([^)]+)\\)/)\r\n if (sm) {\r\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\r\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\r\n }\r\n\r\n return 1\r\n}\r\n\r\nexport function getInverseScale(el = '.share-page') {\r\n const s = getPageScale(el)\r\n return s > 0 ? 1 / s : 1\r\n}\r\n\r\n// ---------- scaler instance ----------\r\n\r\nexport function createScaler(el, options = {}) {\r\n const target = resolveEl(el)\r\n if (!target) throw new Error('[one-screen-scale] element not found')\r\n\r\n const {\r\n mode = 'contain',\r\n visualWidth = 450,\r\n origin = 'top center',\r\n autoResize = true\r\n } = options\r\n\r\n let currentScale = 1\r\n let handler = null\r\n\r\n function compute() {\r\n const sw = target.offsetWidth\r\n const sh = target.offsetHeight\r\n const tw = document.documentElement.clientWidth || window.innerWidth\r\n const th = window.innerHeight\r\n\r\n return calculateScale({\r\n sourceWidth: sw,\r\n sourceHeight: sh,\r\n targetWidth: tw,\r\n targetHeight: th,\r\n mode,\r\n visualWidth,\r\n // screenWidth: window.screen.width\r\n })\r\n }\r\n\r\n function refresh() {\r\n const next = compute()\r\n if (next !== currentScale) {\r\n currentScale = next\r\n applyScale(target, next, origin)\r\n }\r\n\r\n // fixed-width 模式:反向补偿高度\r\n if (mode === 'fixed-width' && next > 0) {\r\n // target.style.width = `${Math.max(window.innerWidth, window.screen.width)}px`\r\n const viewportWidth = document.documentElement.clientWidth || window.innerWidth\r\n target.style.width = `${viewportWidth}px`\r\n target.style.height = `${Math.round(window.innerHeight / next)}px`\r\n }\r\n return currentScale\r\n }\r\n\r\n function start() {\r\n refresh()\r\n if (autoResize) {\r\n handler = () => refresh()\r\n window.addEventListener('resize', handler)\r\n }\r\n return currentScale\r\n }\r\n\r\n function stop() {\r\n if (handler) {\r\n window.removeEventListener('resize', handler)\r\n handler = null\r\n }\r\n }\r\n\r\n return { start, stop, refresh, getScale: () => currentScale }\r\n}\r\n","/**\r\n * React hook\r\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\r\n */\r\nimport { useRef, useState, useEffect, useCallback } from 'react'\r\nimport { createScaler } from './core.js'\r\n\r\nexport function useFitScreen(targetRef, options = {}) {\r\n const [scale, setScale] = useState(1)\r\n const [inverseScale, setInverseScale] = useState(1)\r\n const scalerRef = useRef(null)\r\n\r\n useEffect(() => {\r\n const el = targetRef?.current ?? targetRef\r\n if (!el) return\r\n\r\n const scaler = createScaler(el, options)\r\n scalerRef.current = scaler\r\n const s = scaler.start()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n\r\n const onResize = () => {\r\n const s = scaler.getScale()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n }\r\n window.addEventListener('resize', onResize)\r\n\r\n return () => {\r\n window.removeEventListener('resize', onResize)\r\n scaler.stop()\r\n scalerRef.current = null\r\n }\r\n }, [targetRef])\r\n\r\n const refresh = useCallback(() => {\r\n const el = targetRef?.current ?? targetRef\r\n if (!el || !scalerRef.current) return\r\n const s = scalerRef.current.refresh()\r\n setScale(s)\r\n setInverseScale(s > 0 ? 1 / s : 1)\r\n }, [targetRef])\r\n\r\n return { scale, inverseScale, refresh }\r\n}\r\n"],"names":["resolveEl","el","document","querySelector","HTMLElement","value","current","createScaler","options","target","Error","mode","visualWidth","origin","autoResize","currentScale","handler","compute","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","scale","sx","sy","Math","min","calculateScale","offsetWidth","offsetHeight","documentElement","clientWidth","refresh","next","style","transform","transformOrigin","applyScale","viewportWidth","width","height","round","start","addEventListener","stop","removeEventListener","getScale","useFitScreen","targetRef","setScale","useState","inverseScale","setInverseScale","scalerRef","useRef","useEffect","scaler","s","onResize","useCallback"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "one-screen-scale",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Transform:scale 实现的一屏自适应方案。框架无关核心 + Vue/React 开箱即用",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "https://github.com/request-stack/one-screen-scale.git"
|
|
8
|
-
},
|
|
9
|
-
"type": "module",
|
|
10
|
-
"main": "dist/index.cjs.js",
|
|
11
|
-
"module": "dist/index.esm.js",
|
|
12
|
-
"types": "dist/index.d.ts",
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"types": "./dist/index.d.ts",
|
|
16
|
-
"import": "./dist/index.esm.js",
|
|
17
|
-
"require": "./dist/index.cjs.js"
|
|
18
|
-
},
|
|
19
|
-
"./react": {
|
|
20
|
-
"types": "./dist/react.d.ts",
|
|
21
|
-
"import": "./dist/react.esm.js",
|
|
22
|
-
"require": "./dist/react.cjs.js"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"files": [
|
|
26
|
-
"dist",
|
|
27
|
-
"src",
|
|
28
|
-
"README.md",
|
|
29
|
-
"LICENSE"
|
|
30
|
-
],
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "rollup -c && node -e \"var f=require('fs');f.copyFileSync('src/index.d.ts','dist/index.d.ts');f.copyFileSync('src/react.d.ts','dist/react.d.ts')\"",
|
|
33
|
-
"test": "vitest run",
|
|
34
|
-
"test:watch": "vitest"
|
|
35
|
-
},
|
|
36
|
-
"keywords": [
|
|
37
|
-
"one-screen",
|
|
38
|
-
"adaptive-scale",
|
|
39
|
-
"responsive",
|
|
40
|
-
"viewport",
|
|
41
|
-
"transform-scale",
|
|
42
|
-
"fit-screen",
|
|
43
|
-
"h5-scale",
|
|
44
|
-
"vue3",
|
|
45
|
-
"react",
|
|
46
|
-
"auto-scale"
|
|
47
|
-
],
|
|
48
|
-
"author": "李港",
|
|
49
|
-
"license": "MIT",
|
|
50
|
-
"peerDependencies": {
|
|
51
|
-
"vue": "^3.0.0",
|
|
52
|
-
"react": ">=16.8.0"
|
|
53
|
-
},
|
|
54
|
-
"peerDependenciesMeta": {
|
|
55
|
-
"vue": {
|
|
56
|
-
"optional": true
|
|
57
|
-
},
|
|
58
|
-
"react": {
|
|
59
|
-
"optional": true
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"@rollup/plugin-commonjs": "^24.0.0",
|
|
64
|
-
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
65
|
-
"@rollup/plugin-terser": "^0.4.0",
|
|
66
|
-
"jsdom": "^29.0.1",
|
|
67
|
-
"rollup": "^3.0.0",
|
|
68
|
-
"vitest": "^1.0.0"
|
|
69
|
-
},
|
|
70
|
-
"dependencies": {}
|
|
71
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "one-screen-scale",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Transform:scale 实现的一屏自适应方案。框架无关核心 + Vue/React 开箱即用",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/request-stack/one-screen-scale.git"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"module": "dist/index.esm.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.esm.js",
|
|
17
|
+
"require": "./dist/index.cjs.js"
|
|
18
|
+
},
|
|
19
|
+
"./react": {
|
|
20
|
+
"types": "./dist/react.d.ts",
|
|
21
|
+
"import": "./dist/react.esm.js",
|
|
22
|
+
"require": "./dist/react.cjs.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "rollup -c && node -e \"var f=require('fs');f.copyFileSync('src/index.d.ts','dist/index.d.ts');f.copyFileSync('src/react.d.ts','dist/react.d.ts')\"",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"one-screen",
|
|
38
|
+
"adaptive-scale",
|
|
39
|
+
"responsive",
|
|
40
|
+
"viewport",
|
|
41
|
+
"transform-scale",
|
|
42
|
+
"fit-screen",
|
|
43
|
+
"h5-scale",
|
|
44
|
+
"vue3",
|
|
45
|
+
"react",
|
|
46
|
+
"auto-scale"
|
|
47
|
+
],
|
|
48
|
+
"author": "李港",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"vue": "^3.0.0",
|
|
52
|
+
"react": ">=16.8.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"vue": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"react": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@rollup/plugin-commonjs": "^24.0.0",
|
|
64
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
65
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
66
|
+
"jsdom": "^29.0.1",
|
|
67
|
+
"rollup": "^3.0.0",
|
|
68
|
+
"vitest": "^1.0.0"
|
|
69
|
+
},
|
|
70
|
+
"dependencies": {}
|
|
71
|
+
}
|
package/src/composables.js
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vue 3 Composable
|
|
3
|
-
* useFitScreen(ref, options) → { scale, inverseScale, refresh }
|
|
4
|
-
*/
|
|
5
|
-
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
|
6
|
-
import { createScaler, getInverseScale } from './core.js'
|
|
7
|
-
|
|
8
|
-
export function useFitScreen(targetRef, options = {}) {
|
|
9
|
-
const scale = ref(1)
|
|
10
|
-
const inverseScale = ref(1)
|
|
11
|
-
|
|
12
|
-
let scaler = null
|
|
13
|
-
let onResize = null
|
|
14
|
-
|
|
15
|
-
function setup(el) {
|
|
16
|
-
if (!el) return
|
|
17
|
-
scaler = createScaler(el, options)
|
|
18
|
-
const s = scaler.start()
|
|
19
|
-
scale.value = s
|
|
20
|
-
inverseScale.value = getInverseScale(el)
|
|
21
|
-
|
|
22
|
-
onResize = () => {
|
|
23
|
-
scale.value = scaler?.getScale?.() ?? 1
|
|
24
|
-
inverseScale.value = getInverseScale(el)
|
|
25
|
-
}
|
|
26
|
-
window.addEventListener('resize', onResize)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function teardown() {
|
|
30
|
-
if (onResize) {
|
|
31
|
-
window.removeEventListener('resize', onResize)
|
|
32
|
-
onResize = null
|
|
33
|
-
}
|
|
34
|
-
scaler?.stop()
|
|
35
|
-
scaler = null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 处理 ref 初始有值的情况
|
|
39
|
-
onMounted(() => {
|
|
40
|
-
const el = targetRef?.value ?? targetRef
|
|
41
|
-
setup(el)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
// 处理 ref 延迟赋值的情况(异步挂载)
|
|
45
|
-
if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {
|
|
46
|
-
watch(
|
|
47
|
-
() => targetRef.value,
|
|
48
|
-
(el) => {
|
|
49
|
-
if (el && !scaler) setup(el)
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
onUnmounted(() => {
|
|
55
|
-
teardown()
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const refresh = () => {
|
|
59
|
-
const el = targetRef?.value ?? targetRef
|
|
60
|
-
if (!el || !scaler) return
|
|
61
|
-
const s = scaler.refresh()
|
|
62
|
-
scale.value = s
|
|
63
|
-
inverseScale.value = getInverseScale(el)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return { scale, inverseScale, refresh }
|
|
67
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Vue 3 Composable
|
|
3
|
+
* useFitScreen(ref, options) → { scale, inverseScale, refresh }
|
|
4
|
+
*/
|
|
5
|
+
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
|
6
|
+
import { createScaler, getInverseScale } from './core.js'
|
|
7
|
+
|
|
8
|
+
export function useFitScreen(targetRef, options = {}) {
|
|
9
|
+
const scale = ref(1)
|
|
10
|
+
const inverseScale = ref(1)
|
|
11
|
+
|
|
12
|
+
let scaler = null
|
|
13
|
+
let onResize = null
|
|
14
|
+
|
|
15
|
+
function setup(el) {
|
|
16
|
+
if (!el) return
|
|
17
|
+
scaler = createScaler(el, options)
|
|
18
|
+
const s = scaler.start()
|
|
19
|
+
scale.value = s
|
|
20
|
+
inverseScale.value = getInverseScale(el)
|
|
21
|
+
|
|
22
|
+
onResize = () => {
|
|
23
|
+
scale.value = scaler?.getScale?.() ?? 1
|
|
24
|
+
inverseScale.value = getInverseScale(el)
|
|
25
|
+
}
|
|
26
|
+
window.addEventListener('resize', onResize)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function teardown() {
|
|
30
|
+
if (onResize) {
|
|
31
|
+
window.removeEventListener('resize', onResize)
|
|
32
|
+
onResize = null
|
|
33
|
+
}
|
|
34
|
+
scaler?.stop()
|
|
35
|
+
scaler = null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 处理 ref 初始有值的情况
|
|
39
|
+
onMounted(() => {
|
|
40
|
+
const el = targetRef?.value ?? targetRef
|
|
41
|
+
setup(el)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// 处理 ref 延迟赋值的情况(异步挂载)
|
|
45
|
+
if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {
|
|
46
|
+
watch(
|
|
47
|
+
() => targetRef.value,
|
|
48
|
+
(el) => {
|
|
49
|
+
if (el && !scaler) setup(el)
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onUnmounted(() => {
|
|
55
|
+
teardown()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const refresh = () => {
|
|
59
|
+
const el = targetRef?.value ?? targetRef
|
|
60
|
+
if (!el || !scaler) return
|
|
61
|
+
const s = scaler.refresh()
|
|
62
|
+
scale.value = s
|
|
63
|
+
inverseScale.value = getInverseScale(el)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { scale, inverseScale, refresh }
|
|
67
|
+
}
|