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/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ligang <bpcnlg@163.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,180 +1,186 @@
|
|
|
1
|
-
# one-screen-scale
|
|
2
|
-
|
|
3
|
-
基于 CSS `transform: scale()` 的一屏自适应方案。框架无关核心 + Vue 3 / React 开箱即用。
|
|
4
|
-
|
|
5
|
-
## 为什么用这个
|
|
6
|
-
|
|
7
|
-
- 🎯 **真正的"一屏"** — 内容不溢出、不滚动(contain 模式)
|
|
8
|
-
- 🧩 **零依赖核心** — 纯 JS,不绑定任何框架
|
|
9
|
-
- ⚡ **指令 / Hook 开箱即用** — Vue 3 和 React 都支持
|
|
10
|
-
- 🖥️ **Canvas 友好** — 通过反缩放补偿,ECharts 等 canvas 内容保持清晰
|
|
11
|
-
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
scaler.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
1
|
+
# one-screen-scale
|
|
2
|
+
|
|
3
|
+
基于 CSS `transform: scale()` 的一屏自适应方案。框架无关核心 + Vue 3 / React 开箱即用。
|
|
4
|
+
|
|
5
|
+
## 为什么用这个
|
|
6
|
+
|
|
7
|
+
- 🎯 **真正的"一屏"** — 内容不溢出、不滚动(contain 模式)
|
|
8
|
+
- 🧩 **零依赖核心** — 纯 JS,不绑定任何框架
|
|
9
|
+
- ⚡ **指令 / Hook 开箱即用** — Vue 3 和 React 都支持
|
|
10
|
+
- 🖥️ **Canvas 友好** — 通过反缩放补偿,ECharts 等 canvas 内容保持清晰
|
|
11
|
+
|
|
12
|
+
## 主要面向场景
|
|
13
|
+
|
|
14
|
+
- 使用了pxToViewport autoprefixer 或者类似的移动端自适应插件的h5网页
|
|
15
|
+
- 可以使用该插件在任何设备实现一屏自适应,如果是固定高度(一屏)则使用contain模式,如果是滚动高度则使用fixed-width模式
|
|
16
|
+
- 同时在pc端可以正常自适应显示同一个页面,从而无需再开发pc端对应页面
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install one-screen-scale
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 快速开始
|
|
25
|
+
|
|
26
|
+
### Vue 3 — 指令(最简)
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<template>
|
|
30
|
+
<div v-fit-screen class="page">
|
|
31
|
+
<h1>活动标题</h1>
|
|
32
|
+
<p>页面内容...</p>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
import { vFitScreen } from 'one-screen-scale'
|
|
38
|
+
</script>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Vue 3 — Composable(需要 scale 值,如 ECharts 补偿)
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<template>
|
|
45
|
+
<div ref="pageRef" class="page">
|
|
46
|
+
<div :style="{ transform: `scale(${inverseScale})` }">
|
|
47
|
+
<ECharts />
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup>
|
|
53
|
+
import { ref } from 'vue'
|
|
54
|
+
import { useFitScreen } from 'one-screen-scale'
|
|
55
|
+
|
|
56
|
+
const pageRef = ref(null)
|
|
57
|
+
const { scale, inverseScale } = useFitScreen(pageRef)
|
|
58
|
+
// inverseScale 可用于子元素反缩放补偿
|
|
59
|
+
</script>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### React
|
|
63
|
+
|
|
64
|
+
```jsx
|
|
65
|
+
import { useRef } from 'react'
|
|
66
|
+
import { useFitScreen } from 'one-screen-scale/react'
|
|
67
|
+
|
|
68
|
+
function App() {
|
|
69
|
+
const pageRef = useRef(null)
|
|
70
|
+
const { scale, inverseScale } = useFitScreen(pageRef)
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div ref={pageRef} className="page">
|
|
74
|
+
<h1>活动标题</h1>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 纯 JS / jQuery
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
import { createScaler } from 'one-screen-scale'
|
|
84
|
+
|
|
85
|
+
const scaler = createScaler(document.querySelector('.page'), {
|
|
86
|
+
mode: 'contain'
|
|
87
|
+
})
|
|
88
|
+
scaler.start()
|
|
89
|
+
|
|
90
|
+
// 销毁
|
|
91
|
+
scaler.stop()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 两种模式
|
|
95
|
+
|
|
96
|
+
| 模式 | 算法 | 效果 | 场景 |
|
|
97
|
+
|------|------|------|------|
|
|
98
|
+
| `contain`(默认) | `min(scaleX, scaleY)` | 内容完整可见,不溢出 | 活动页、落地页 |
|
|
99
|
+
| `fixed-width` | `visualWidth / innerWidth`(视口 ≤ visualWidth 时为 1) | 固定手机观感宽度,可滚动 | 规则页、长表单 |
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
// contain(默认)
|
|
103
|
+
createScaler(el)
|
|
104
|
+
|
|
105
|
+
// fixed-width
|
|
106
|
+
createScaler(el, { mode: 'fixed-width', visualWidth: 450 })
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## API
|
|
110
|
+
|
|
111
|
+
### 核心函数(框架无关)
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
calculateScale(options: ScaleOptions): number
|
|
115
|
+
|
|
116
|
+
applyScale(el: Element | string, scale: number, origin?: string): void
|
|
117
|
+
|
|
118
|
+
getPageScale(el?: Element | string): number // 默认查 .share-page
|
|
119
|
+
getInverseScale(el?: Element | string): number // 1 / getPageScale()
|
|
120
|
+
|
|
121
|
+
createScaler(el: Element | string, options?: ScalerOptions): ScalerInstance
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### ScalerInstance
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
{
|
|
128
|
+
start(): number // 启动缩放 + 监听 resize,返回当前 scale
|
|
129
|
+
stop(): void // 停止监听
|
|
130
|
+
refresh(): number // 手动重算
|
|
131
|
+
getScale(): number // 获取当前 scale
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### ScalerOptions
|
|
136
|
+
|
|
137
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
138
|
+
|------|------|--------|------|
|
|
139
|
+
| `mode` | `'contain' \| 'fixed-width'` | `'contain'` | 缩放模式 |
|
|
140
|
+
| `visualWidth` | `number` | `450` | fixed-width 模式目标视觉宽度 |
|
|
141
|
+
| `origin` | `string` | `'top center'` | transform-origin |
|
|
142
|
+
| `autoResize` | `boolean` | `true` | 自动监听窗口 resize |
|
|
143
|
+
|
|
144
|
+
### Vue
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// 指令
|
|
148
|
+
vFitScreen: Directive<HTMLElement, ScalerOptions>
|
|
149
|
+
|
|
150
|
+
// Composable
|
|
151
|
+
useFitScreen(ref: Ref, options?: ScalerOptions): {
|
|
152
|
+
scale: Ref<number>
|
|
153
|
+
inverseScale: Ref<number>
|
|
154
|
+
refresh: () => void
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### React
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { useFitScreen } from 'one-screen-scale/react'
|
|
162
|
+
|
|
163
|
+
useFitScreen(ref: RefObject, options?: ScalerOptions): {
|
|
164
|
+
scale: number
|
|
165
|
+
inverseScale: number
|
|
166
|
+
refresh: () => void
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Canvas / ECharts 模糊问题
|
|
171
|
+
|
|
172
|
+
CSS `transform: scale()` 缩放的是位图,canvas 内容会变糊。解决办法:对 canvas 容器做反缩放补偿。
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
// Vue composable 示例
|
|
176
|
+
const { inverseScale } = useFitScreen(pageRef)
|
|
177
|
+
|
|
178
|
+
// 在包裹层上应用反缩放
|
|
179
|
+
// <div :style="{ transform: `scale(${inverseScale})`, transformOrigin: 'top left' }">
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
反缩放后 canvas 以原生分辨率渲染,保持清晰。详情见 [Canvas 缩放补偿指南](https://github.com/nicepkg/one-screen-scale)。
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("vue");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({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
|
|
1
|
+
"use strict";var e=require("vue");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({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}function r(e,n,r="top center"){const i=t(e);i&&(i.style.transform=`scale(${n})`,i.style.transformOrigin=r)}function i(e){const n=t(e);if(!n)return 1;const r=window.getComputedStyle(n).transform;if(!r||"none"===r)return 1;const i=r.match(/matrix\(([^,]+),\s*[^,]+,\s*[^,]+,\s*([^,]+)/);if(i)return(parseFloat(i[1])+parseFloat(i[2]))/2;const o=r.match(/matrix3d\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\)/);if(o)return(parseFloat(o[1])+parseFloat(o[2]))/2;const s=r.match(/scale\(([^)]+)\)/);if(s){const e=s[1].split(",").map(e=>parseFloat(e.trim()));return e.length>=2?(e[0]+e[1])/2:e[0]}return 1}function o(e=".share-page"){const t=i(e);return t>0?1/t:1}function s(e,i={}){const o=t(e);if(!o)throw new Error("[one-screen-scale] element not found");const{mode:s="contain",visualWidth:c=450,origin:u="top center",autoResize:a=!0}=i;let l=1,d=null;function f(){const e=n({sourceWidth:o.offsetWidth,sourceHeight:o.offsetHeight,targetWidth:document.documentElement.clientWidth||window.innerWidth,targetHeight:window.innerHeight,mode:s,visualWidth:c});if(e!==l&&(l=e,r(o,e,u)),"fixed-width"===s&&e>0){const t=document.documentElement.clientWidth||window.innerWidth;o.style.width=`${t}px`,o.style.height=`${Math.round(window.innerHeight/e)}px`}return l}return{start:function(){return f(),a&&(d=()=>f(),window.addEventListener("resize",d)),l},stop:function(){d&&(window.removeEventListener("resize",d),d=null)},refresh:f,getScale:()=>l}}const c={mounted(e,t){const n=s(e,t.value||{});n.start(),e.__fitScreenScaler=n},updated(e,t){const n=e.__fitScreenScaler;n&&(t.value,n.refresh())},unmounted(e){const t=e.__fitScreenScaler;t&&(t.stop(),delete e.__fitScreenScaler)}};exports.applyScale=r,exports.calculateScale=n,exports.createScaler=s,exports.getInverseScale=o,exports.getPageScale=i,exports.useFitScreen=function(t,n={}){const r=e.ref(1),i=e.ref(1);let c=null,u=null;function a(e){if(!e)return;c=s(e,n);const t=c.start();r.value=t,i.value=o(e),u=()=>{r.value=c?.getScale?.()??1,i.value=o(e)},window.addEventListener("resize",u)}return e.onMounted(()=>{a(t?.value??t)}),t&&"object"==typeof t&&"value"in t&&e.watch(()=>t.value,e=>{e&&!c&&a(e)}),e.onUnmounted(()=>{u&&(window.removeEventListener("resize",u),u=null),c?.stop(),c=null}),{scale:r,inverseScale:i,refresh:()=>{const e=t?.value??t;if(!e||!c)return;const n=c.refresh();r.value=n,i.value=o(e)}}},exports.vFitScreen=c;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.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","targetRef","ref","inverseScale","onResize","setup","onMounted","watch","onUnmounted"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.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","targetRef","ref","inverseScale","onResize","setup","onMounted","watch","onUnmounted"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
// ===== 核心 =====
|
|
2
|
-
|
|
3
|
-
export interface ScaleOptions {
|
|
4
|
-
sourceWidth: number
|
|
5
|
-
sourceHeight: number
|
|
6
|
-
targetWidth?: number
|
|
7
|
-
targetHeight?: number
|
|
8
|
-
mode?: 'contain' | 'fixed-width'
|
|
9
|
-
visualWidth?: number
|
|
10
|
-
screenWidth?: number
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface ScalerOptions {
|
|
14
|
-
mode?: 'contain' | 'fixed-width'
|
|
15
|
-
visualWidth?: number
|
|
16
|
-
origin?: string
|
|
17
|
-
autoResize?: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ScalerInstance {
|
|
21
|
-
start: () => number
|
|
22
|
-
stop: () => void
|
|
23
|
-
refresh: () => number
|
|
24
|
-
getScale: () => number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function calculateScale(options: ScaleOptions): number
|
|
28
|
-
export function applyScale(el: HTMLElement | string, scale: number, origin?: string): void
|
|
29
|
-
export function getPageScale(el?: HTMLElement | string): number
|
|
30
|
-
export function getInverseScale(el?: HTMLElement | string): number
|
|
31
|
-
export function createScaler(el: HTMLElement | string, options?: ScalerOptions): ScalerInstance
|
|
32
|
-
|
|
33
|
-
// ===== Vue =====
|
|
34
|
-
|
|
35
|
-
import type { Ref, Directive } from 'vue'
|
|
36
|
-
|
|
37
|
-
export const vFitScreen: Directive<HTMLElement, ScalerOptions>
|
|
38
|
-
|
|
39
|
-
export function useFitScreen(
|
|
40
|
-
targetRef: Ref<HTMLElement | null> | HTMLElement,
|
|
41
|
-
options?: ScalerOptions
|
|
42
|
-
): {
|
|
43
|
-
scale: Ref<number>
|
|
44
|
-
inverseScale: Ref<number>
|
|
45
|
-
refresh: () => void
|
|
46
|
-
}
|
|
1
|
+
// ===== 核心 =====
|
|
2
|
+
|
|
3
|
+
export interface ScaleOptions {
|
|
4
|
+
sourceWidth: number
|
|
5
|
+
sourceHeight: number
|
|
6
|
+
targetWidth?: number
|
|
7
|
+
targetHeight?: number
|
|
8
|
+
mode?: 'contain' | 'fixed-width'
|
|
9
|
+
visualWidth?: number
|
|
10
|
+
// screenWidth?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ScalerOptions {
|
|
14
|
+
mode?: 'contain' | 'fixed-width'
|
|
15
|
+
visualWidth?: number
|
|
16
|
+
origin?: string
|
|
17
|
+
autoResize?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ScalerInstance {
|
|
21
|
+
start: () => number
|
|
22
|
+
stop: () => void
|
|
23
|
+
refresh: () => number
|
|
24
|
+
getScale: () => number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function calculateScale(options: ScaleOptions): number
|
|
28
|
+
export function applyScale(el: HTMLElement | string, scale: number, origin?: string): void
|
|
29
|
+
export function getPageScale(el?: HTMLElement | string): number
|
|
30
|
+
export function getInverseScale(el?: HTMLElement | string): number
|
|
31
|
+
export function createScaler(el: HTMLElement | string, options?: ScalerOptions): ScalerInstance
|
|
32
|
+
|
|
33
|
+
// ===== Vue =====
|
|
34
|
+
|
|
35
|
+
import type { Ref, Directive } from 'vue'
|
|
36
|
+
|
|
37
|
+
export const vFitScreen: Directive<HTMLElement, ScalerOptions>
|
|
38
|
+
|
|
39
|
+
export function useFitScreen(
|
|
40
|
+
targetRef: Ref<HTMLElement | null> | HTMLElement,
|
|
41
|
+
options?: ScalerOptions
|
|
42
|
+
): {
|
|
43
|
+
scale: Ref<number>
|
|
44
|
+
inverseScale: Ref<number>
|
|
45
|
+
refresh: () => void
|
|
46
|
+
}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ref as e,onMounted as t,watch as n,onUnmounted as r}from"vue";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({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
|
|
1
|
+
import{ref as e,onMounted as t,watch as n,onUnmounted as r}from"vue";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({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}function s(e,t,n="top center"){const r=i(e);r&&(r.style.transform=`scale(${t})`,r.style.transformOrigin=n)}function u(e){const t=i(e);if(!t)return 1;const n=window.getComputedStyle(t).transform;if(!n||"none"===n)return 1;const r=n.match(/matrix\(([^,]+),\s*[^,]+,\s*[^,]+,\s*([^,]+)/);if(r)return(parseFloat(r[1])+parseFloat(r[2]))/2;const o=n.match(/matrix3d\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\)/);if(o)return(parseFloat(o[1])+parseFloat(o[2]))/2;const s=n.match(/scale\(([^)]+)\)/);if(s){const e=s[1].split(",").map(e=>parseFloat(e.trim()));return e.length>=2?(e[0]+e[1])/2:e[0]}return 1}function c(e=".share-page"){const t=u(e);return t>0?1/t:1}function l(e,t={}){const n=i(e);if(!n)throw new Error("[one-screen-scale] element not found");const{mode:r="contain",visualWidth:u=450,origin:c="top center",autoResize:l=!0}=t;let a=1,d=null;function f(){const e=o({sourceWidth:n.offsetWidth,sourceHeight:n.offsetHeight,targetWidth:document.documentElement.clientWidth||window.innerWidth,targetHeight:window.innerHeight,mode:r,visualWidth:u});if(e!==a&&(a=e,s(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 a}return{start:function(){return f(),l&&(d=()=>f(),window.addEventListener("resize",d)),a},stop:function(){d&&(window.removeEventListener("resize",d),d=null)},refresh:f,getScale:()=>a}}const a={mounted(e,t){const n=l(e,t.value||{});n.start(),e.__fitScreenScaler=n},updated(e,t){const n=e.__fitScreenScaler;n&&(t.value,n.refresh())},unmounted(e){const t=e.__fitScreenScaler;t&&(t.stop(),delete e.__fitScreenScaler)}};function d(i,o={}){const s=e(1),u=e(1);let a=null,d=null;function f(e){if(!e)return;a=l(e,o);const t=a.start();s.value=t,u.value=c(e),d=()=>{s.value=a?.getScale?.()??1,u.value=c(e)},window.addEventListener("resize",d)}t(()=>{f(i?.value??i)}),i&&"object"==typeof i&&"value"in i&&n(()=>i.value,e=>{e&&!a&&f(e)}),r(()=>{d&&(window.removeEventListener("resize",d),d=null),a?.stop(),a=null});return{scale:s,inverseScale:u,refresh:()=>{const e=i?.value??i;if(!e||!a)return;const t=a.refresh();s.value=t,u.value=c(e)}}}export{s as applyScale,o as calculateScale,l as createScaler,c as getInverseScale,u as getPageScale,d as useFitScreen,a as vFitScreen};
|
|
2
2
|
//# sourceMappingURL=index.esm.js.map
|