@scqilin/phone-ui 手机外观组件库
写在最前面
最近开发一个移动端编辑器,我需要一个非常轻量的"手机壳"来把内容包起来用于预览与截图。于是做了 @scqilin/phone-ui
:一个零依赖、用原生 TypeScript 写的手机外观渲染库,核心目标是简单、可复用、易适配。我的目标很明确:
- 零依赖:能用在任何项目里,不管是 Vue、React 还是原生 JS。
- 纯粹:只做"手机外观"这一件事,保持轻量。
- 易用:API 简单,上手快。
✨ 特点
- 🚀 零依赖,纯 TypeScript + 动态样式注入
- 📱 内置 iPhone 16 全系列机型(16/Plus/Pro/Pro Max)
- 🎨 支持完全自定义外观(尺寸、颜色、按钮等)
- 💻 适用于任何前端项目
- 🎯 在线演示 可直接体验
📦 安装
bash
npm install @scqilin/phone-ui
🚀 快速开始
把下面这段代码扔进你的项目,就能看到效果。
HTML 结构:
html
<div id="phone-demo" style="width: 500px; height: 900px;"></div>
JS 调用:
javascript
import { createPhoneUI } from '@scqilin/phone-ui';
const container = document.getElementById('phone-demo');
// 方式一:使用预设机型
createPhoneUI({
container,
phoneType: 'iphone16pro'
});
// 方式二:完全自定义
createPhoneUI({
container,
width: 400,
height: 800,
frameColor: '#1a1a1a',
screenColor: '#ffffff',
showButtons: true
});
🤔 设计思路与权衡
1. 为什么是原生库,而不是 Vue/React 组件?
最开始我也想直接写个 Vue 组件,但很快发现,把核心做成原生库更灵活。
- 框架无关:原生实现意味着最大程度的复用。
- 关注点分离:核心库只管渲染,框架适配(如 Vue 组件)只管生命周期和数据流。这样结构更清晰,维护也更容易。
2. 样式隔离
为了避免污染宿主页面的样式,我没有让用户引入 CSS 文件,而是通过 JS 动态创建 <style>
标签 并注入到 head 中。所有样式都带上了 phone-ui-
前缀,并通过 CSS 变量暴露定制接口,比如 --phone-ui-frame-color
。
📖 API 文档
createPhoneUI(options)
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
container |
HTMLElement |
✅ | 渲染目标容器 |
phoneType |
string |
❌ | 机型名称,支持 'iphone16' , 'iphone16plus' , 'iphone16pro' , 'iphone16promax' |
width |
number |
❌ | 自定义宽度(phoneType 存在时无效) |
height |
number |
❌ | 自定义高度(phoneType 存在时无效) |
frameColor |
string |
❌ | 边框颜色,默认 '#1a1a1a' |
screenColor |
string |
❌ | 屏幕颜色,默认 '#ffffff' |
showButtons |
boolean |
❌ | 是否显示侧边按钮,默认 true |
borderRadius |
number |
❌ | 圆角大小,默认 30 |
📱 支持的机型
机型 | phoneType 值 |
尺寸 (宽×高) |
---|---|---|
iPhone 16 | 'iphone16' |
402×874 |
iPhone 16 Plus | 'iphone16plus' |
440×950 |
iPhone 16 Pro | 'iphone16pro' |
402×874 |
iPhone 16 Pro Max | 'iphone16promax' |
440×950 |
💡 常见问题
- 屏幕看不见/高度为0 :请确保传入的
container
元素有自己的尺寸(宽高)。 - 样式被覆盖 :检查宿主页面是否有更高优先级的选择器。可以尝试通过 CSS 变量覆盖颜色,或用
!important
。 - 按钮能点吗:不能,按钮仅为装饰。
📦 关于 Vue 的适配
我最初尝试在 Vue 项目里直接用这个原生库,但发现不太"顺手":
- 插槽不好用 :想用 Vue 的
<slot>
功能把内容放进"手机屏幕"里,操作起来很别扭。 - 生命周期问题 :必须在
onMounted
之后手动调用,在onBeforeUnmount
手动销毁,很繁琐。
为了解决这个问题,我另外写了一个轻量的 Vue 3 适配包,它做的事情很简单:
- 把原生库的 API 封装成一个真正的 Vue 组件。
- 用
onMounted
和onBeforeUnmount
管理生命周期。 - 把组件的默认插槽内容正确地渲染到手机屏幕里。
现在,在 Vue 里可以这样用:
vue
<template>
<PhoneUi phoneType="iphone16pro">
<!-- 这里的内容会自动放进手机屏幕 -->
<h1>Hello, Vue!</h1>
</PhoneUi>
</template>
<script setup>
// 假设你已经安装并配置了 vue 适配包
import PhoneUi from '@scqilin/phone-ui-vue';
</script>
这样就舒服多了。这个 Vue 适配包是独立的项目,你可以在这里找到它:
- Vue 适配包仓库 : github.com/scqilin/pho...
- 相关博文 : juejin.cn/post/753612...
🎉 结语
如果你对这个小项目感兴趣,或者希望支持其他机型,欢迎在 GitHub 上提 Issue 或 PR!