设备模拟器
设备模拟器在一个有边界的工作台中切换手机、平板和桌面视口,并为三类设备呈现对应的硬件外壳。浏览器模式使用真实尺寸的 iframe,原生模式则把安全参数交给可信宿主启动 a3s-webview。
预览尺寸 393 × 852。 a3s-webview --url …复制命令 示例 index.html入口 main.js
<section
class="device-simulator"
data-device="phone"
data-orientation="portrait"
>
<header>
<select data-device-simulator-select aria-label="Device preset">
<option
value="phone"
data-kind="phone"
data-orientation="portrait"
data-width="393"
data-height="852"
>
Phone · 393 × 852
</option>
<option
value="desktop"
data-kind="desktop"
data-orientation="landscape"
data-width="1440"
data-height="900"
>
Desktop · 1440 × 900
</option>
<option value="custom">Custom</option>
</select>
<input
type="number"
min="240"
max="4000"
value="393"
data-device-simulator-width
/>
<input
type="number"
min="180"
max="3000"
value="852"
data-device-simulator-height
/>
<div
role="group"
aria-label="Orientation"
data-device-simulator-orientation
>
<button
type="button"
aria-pressed="true"
data-device-simulator-orientation-value="portrait"
>
Portrait
</button>
<button
type="button"
aria-pressed="false"
data-device-simulator-orientation-value="landscape"
>
Landscape
</button>
</div>
<form data-device-simulator-navigation>
<input
type="text"
inputmode="url"
value="https://example.com"
data-device-simulator-url
/>
<button type="submit">Open</button>
<button type="button" data-device-simulator-refresh>Refresh</button>
</form>
</header>
<div data-device-simulator-workspace>
<div data-device-simulator-canvas>
<div data-device-simulator-frame>
<iframe
title="Application preview"
src="https://example.com"
data-device-simulator-preview
></iframe>
<span hidden data-device-simulator-screen-status></span>
</div>
</div>
</div>
<footer>
<output aria-live="polite" data-device-simulator-status></output>
<code data-device-simulator-command></code>
<button type="button" data-device-simulator-copy-command>
Copy native command
</button>
<button type="button" data-device-simulator-native>
Open native preview
</button>
</footer>
</section>
<script type="module">
import "@a3s-lab/ui/runtime";
import "@a3s-lab/ui/device-simulator";
</script>import "@a3s-lab/ui/a3s.css";
import "@a3s-lab/ui/all";
手机外壳包含金属边框、传感器区和底部手势区,平板外壳包含窄边框与摄像头;笔记本使用屏幕边框、铰链和底座,桌面显示器则呈现下巴与支架。整套外壳会和设备一起缩放以适配工作区,iframe 内部仍保持所选 CSS viewport 的精确宽高。
模拟器不会伪装 User-Agent、设备像素比、触控能力,也不会向目标页面注入安全区变量,同时不会模拟网络限速或系统浏览器差异。目标页面还必须允许被 iframe 嵌入;受 X-Frame-Options 或 CSP frame-ancestors 限制的页面应改用原生预览。
用法
加载运行时与设备模拟器控制器。完整样式包已包含结构层和 Harness 视觉层。
< section
class = "device-simulator"
data-device = "phone"
data-orientation = "portrait"
>
< header >
< select data-device-simulator-select aria-label = "Device preset" >
< option
value = "phone"
data-kind = "phone"
data-orientation = "portrait"
data-width = "393"
data-height = "852"
>
Phone · 393 × 852
</ option >
< option
value = "desktop"
data-kind = "desktop"
data-orientation = "landscape"
data-width = "1440"
data-height = "900"
>
Desktop · 1440 × 900
</ option >
< option value = "custom" >Custom</ option >
</ select >
< input
type = "number"
min = "240"
max = "4000"
value = "393"
data-device-simulator-width
/>
< input
type = "number"
min = "180"
max = "3000"
value = "852"
data-device-simulator-height
/>
< div
role = "group"
aria-label = "Orientation"
data-device-simulator-orientation
>
< button
type = "button"
aria-pressed = "true"
data-device-simulator-orientation-value = "portrait"
>
Portrait
</ button >
< button
type = "button"
aria-pressed = "false"
data-device-simulator-orientation-value = "landscape"
>
Landscape
</ button >
</ div >
< form data-device-simulator-navigation >
< input
type = "text"
inputmode = "url"
value = "https://example.com"
data-device-simulator-url
/>
< button type = "submit" >Open</ button >
< button type = "button" data-device-simulator-refresh >Refresh</ button >
</ form >
</ header >
< div data-device-simulator-workspace >
< div data-device-simulator-canvas >
< div data-device-simulator-frame >
< iframe
title = "Application preview"
src = "https://example.com"
data-device-simulator-preview
></ iframe >
< span hidden data-device-simulator-screen-status ></ span >
</ div >
</ div >
</ div >
< footer >
< output aria-live = "polite" data-device-simulator-status ></ output >
< code data-device-simulator-command ></ code >
< button type = "button" data-device-simulator-copy-command >
Copy native command
</ button >
< button type = "button" data-device-simulator-native >
Open native preview
</ button >
</ footer >
</ section >
< script type = "module" >
import "@a3s-lab/ui/runtime" ;
import "@a3s-lab/ui/device-simulator" ;
</ script >
使用完整运行时包时,写法等价于 import "@a3s-lab/ui/all"。
参数
自定义宽高会限制在和 a3s-webview 一致的范围内。修改自定义输入后,控制器会选择值为 custom 的选项并派发尺寸变化事件。
JavaScript API
初始化后,根元素提供以下方法:
尺寸变化会派发 a3s:device-change,URL 导航会派发 a3s:device-navigate。原生预览使用可取消、可冒泡且可跨 Shadow DOM 的 a3s:device-preview-request 事件,detail 包含 { executable, args, url, width, height, title, command }。
可信宿主应调用 preventDefault() 表示已经接管,并直接使用结构化 args。不要重新解析仅供显示和复制的 command 字符串。
const simulator = document .querySelector ( ".device-simulator" );
simulator .addEventListener ( "a3s:device-preview-request" , async (event) => {
if ( ! window .trustedPreviewHost) return ;
event .preventDefault ();
const { executable , args } = event .detail;
await window . trustedPreviewHost .launch ({ executable , args });
});
网页控制器不会直接执行本机程序。没有可信宿主时,“原生预览”只会把等价命令复制到剪贴板。
状态与变体
data-state="loading" 在 iframe 导航期间显示加载状态。
data-state="ready" 表示尺寸或预览已经同步。
data-state="error" 表示 URL 无效或复制失败,并在状态输出中说明恢复方式。
手机、平板、笔记本和桌面显示器使用不同的边框、传感器、底座或支架;iframe 始终使用输入框中的真实 CSS 像素尺寸。
file: URL 可交给原生宿主;浏览器是否允许 iframe 打开本地文件由浏览器安全策略决定。
可访问性
为根组件、预设选择器、方向按钮组、URL 输入和 iframe 提供可访问名称。方向按钮使用 aria-pressed,状态输出使用 aria-live="polite"。工作区保持独立滚动,键盘焦点不会被缩放后的 iframe 框体重排。自定义尺寸必须保留数值输入的 min、max 与清楚标签。