
amis 移动端适配实战仿原生 UI、useMobileUI 开关与 mobile 配置覆盖【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis导读本文聚焦 amis 低代码框架的移动端展现能力从 1.6.0 版本起 amis 默认在移动端使用仿原生 UI如日期选择从底部弹出同时提供useMobileUI属性用于全局或组件级关闭该效果并提供mobile配置属性用于在移动端覆盖任意节点的 schema 属性。读完本文你将掌握如何在 amis 中开启/关闭移动端原生 UI、如何针对移动端单独定制组件形态以及这些机制背后的源码实现原理。本文以 docs/zh-CN/extend/mobile.md 为主体并结合 amis-core 与 amis 渲染器源码进行佐证。移动端原生 UI默认开启的仿原生交互从 1.6.0 版本开始amis 默认在移动端下使用仿原生 UI 的展现方式。所谓“仿原生”指的是交互形态贴近手机系统原生控件最典型的例子就是日期选择器在移动端会从屏幕底部弹出而不是 PC 端的下拉浮层。在源码层面这一能力由 amis-core 统一控制packages/amis-core/src/factory.tsx 中的默认选项将useMobileUI置为trueexport const defaultOptions: RenderOptions { session: global, richTextToken: , useMobileUI: true, // 是否启用移动端原生 UI ... };在 packages/amis-core/src/index.tsx 中只要全局配置中useMobileUI ! false就会把根据当前环境判断出的mobileUI传递给所有渲染器// 默认将开启移动端原生 UI if (options.useMobileUI ! false) { props.mobileUI env.isMobile(); }渲染器拿到mobileUI后会切换交互形态。例如 packages/amis/src/renderers/Form/InputDate.tsx 中日期控件在mobileUI为真时把浮层容器指向env.getModalContainer即底部弹层DatePicker ... mobileUI{mobileUI} popOverContainer{ mobileUI ? env?.getModalContainer : rest.popOverContainer || env.getModalContainer } ... /这就是“日期选择会从底部弹出”的实现位置。由于仿原生 UI 是新开发的组件部分 amis PC 版本的高级配置功能尚不支持——比如 select 的搜索过滤等。如果需要这些能力可以通过useMobileUI属性关闭仿原生 UI让组件回退到 PC 形态。方式一全局关闭 useMobileUI在amis.embed的第四个参数options中设置useMobileUI: false即可全局关闭移动端仿原生 UIamis.embed( #root, { // amis schema }, { // 这里是初始 props }, { theme: antd, useMobileUI: false } );说明amis.embed的第三个参数是初始 props第四个参数是 options全局配置。useMobileUI放在第四个参数中作用于整个页面上的所有组件。对应的实现逻辑在 packages/amis-core/src/index.tsx当options.useMobileUI false时不再向 props 注入mobileUI各渲染器随之回退到 PC 交互形态。方式二针对某个组件关闭 useMobileUIuseMobileUI也可以作为 schema 属性写到任意组件节点上仅对该组件生效。例如让某个select组件不启用移动端原生 UI{ type: select, useMobileUI: false }从源码看这个组件级开关是在渲染层解析的。packages/amis-core/src/SchemaRenderer.tsx 中为每个渲染器组装 props 时做了如下处理mobileUI: schema.useMobileUI false ? false : rest.mobileUI也就是说只有当节点的 schema 里显式写了useMobileUI: false时该组件才关闭仿原生 UI否则继承全局传递下来的mobileUI。这样即可实现“大部分组件用原生 UI个别组件保留 PC 形态”的混排效果。移动端定制配置mobile 属性仅仅切换交互形态往往不够有时候我们需要在移动端展示完全不同的内容或属性。amis 提供了mobile属性在任意 schema 节点上写mobile移动端渲染时该节点的属性会被mobile中的值覆盖。在单个组件上覆盖以下示例在表单内的email输入框上配置了mobile移动端下该字段会被整体替换为手机号输入框{ type: form, body: [{ name: email, type: input-email, label: 邮箱, mobile: { name: phone, type: text, label: 电话, validations: { isPhoneNumber: true } } }] }在移动端预览时原来的“邮箱”输入框会变成“电话”输入框并附带手机号校验规则。这属于属性级别的整体覆盖mobile中的type、name、label、validations都会替换 PC 配置中的对应值。在父节点上覆盖替换任意子属性mobile属性可以出现在配置中的任意地方替换父节点的任意属性。前面的例子也可以写在form上通过覆盖body一次性替换整个表单体{ type: form, body: [{ name: email, type: input-email, label: 邮箱 }], mobile: { body: [{ name: phone, type: input-text, label: 电话, validations: { isPhoneNumber: true } }] } }这种写法适合移动端表单结构差异较大的场景PC 端展示完整字段移动端只保留核心字段或调整为更精简的布局。底层实现envOverwritemobile覆盖机制由 packages/amis-core/src/envOverwrite.ts 实现。核心函数envOverwrite会递归遍历整个 schema使用JSONValueMap比 schema 过滤器更深入可以覆盖到select的options等深层数据遇到带有mobile属性的对象时进行合并覆盖export const envOverwrite (schema: any, locale?: string, device?: string) { const isMobileDevice device mobile || isMobile; return JSONValueMap( schema, (value: any) { if (!isPlainObject(value)) { return value; } if (locale value[locale]) { const newValue Object.assign({}, value, value[locale]); delete newValue[locale]; return newValue; } else if (isMobileDevice value.mobile) { const newValue Object.assign({}, value, value.mobile); delete newValue.mobile; return newValue; } }, true ); };关键点深度覆盖注释中特别说明“不能用 addSchemaFilter因为还需要更深层的替换比如 select 里的 options”因此采用递归遍历的方式处理所有层级的节点合并语义Object.assign({}, value, value.mobile)表示mobile中的键值会覆盖原节点的同名键未写出的键则保留 PC 配置调用时机packages/amis-core/src/index.tsx 中在渲染前根据当前环境执行覆盖并注释强调“这个要在最前面做不然就无法覆盖 validations”// 根据环境覆盖 schema这个要在最前面做不然就无法覆盖 validations schema React.useMemo(() { schema envOverwrite(schema, locale, env.isMobile() ? mobile : pc); ... return schema; }, [schema, locale, options.replaceText]);判断机制按页面宽度而非设备类型注意amis 对移动端的判断是根据页面宽度和 CSS 保持一致所以即便是在 PC 上如果页面宽度很小也会切换到 mobile 配置。对应的源码实现位于 packages/amis-core/src/utils/helper.ts// isMobile根据media宽度判断是否是移动端 export function isMobile() { return (window as any).matchMedia?.((max-width: 768px)).matches; }也就是说判断标准是 CSS 媒体查询(max-width: 768px)只要视口宽度小于等于 768px无论实际设备是手机、平板还是缩窄了浏览器窗口的 PC都会被视为移动端并应用mobile覆盖配置。与之相对的packages/amis-core/src/utils/helper.ts 中还提供了基于 userAgent 的isMobileDevice()用于识别真实移动设备Android、iPhone、iPad 等但移动端 UI 的启用与否不依赖它而是完全跟随页面宽度。实际开发中可以利用这一点在 PC 上调试移动端效果把浏览器窗口或开发者工具的响应式模拟器宽度调到 768px 以下即可看到仿原生 UI 和mobile覆盖配置生效。移动端 UI 的实际表现印证除了日期选择器底部弹出mobileUI还会影响诸多组件的细节表现可从渲染器中看到CRUD 分页packages/amis/src/renderers/CRUD.tsx 中mobileUI为真时不展示“每页条数”文本标签仅保留更紧凑的分页交互并给根节点加上is-mobile样式类同文件 L2822CRUD2 移动模式packages/amis/src/renderers/CRUD2.tsx 在移动端且设置了mobileMode时表格模式会切换为卡片等更适合小屏的形态并支持下拉刷新同文件 L1786 的pullRefresh逻辑表单控件packages/amis/src/renderers/Form/InputDate.tsx 如前述浮层改为底部弹出容器。使用建议与注意事项按需关闭仿原生 UI 覆盖了大量表单控件若你的移动端页面需要 select 搜索过滤等高级功能优先用组件级useMobileUI: false做局部回退而不是全局关闭以保留移动端的原生操作手感mobile 覆盖要写全mobile采用浅合并语义Object.assign被覆盖的属性需要显式列出未列出的属性沿用 PC 配置判断跟随宽度由于按 768px 断点判断窄窗口的桌面浏览器同样会触发移动端形态设计移动端配置时应以宽度为唯一考量不要假设“移动端配置只在真机上出现”环境差异排查若移动端行为与预期不符可从两条链路排查——useMobileUI是否被全局或组件级关闭见 packages/amis-core/src/index.tsx 与 packages/amis-core/src/SchemaRenderer.tsx以及mobile覆盖是否在渲染前正确合并见 packages/amis-core/src/envOverwrite.ts。小结amis 的移动端适配由三个层次构成默认开启的仿原生 UIuseMobileUI全局/组件级控制、基于 768px 页面宽度的环境判断env.isMobile()、以及渲染前执行的mobile属性覆盖envOverwrite深度合并。理解这三层机制后你可以在同一份 JSON schema 下精确控制移动端与 PC 端各自的交互形态与展示内容实现“一份配置、多端适配”。【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考