← 全部文章
uni-app组件样式条件编译面试

uni-app 系列(三):组件、easycom、rpx 与条件编译

2026年8月3日 · 17 分钟

一、内置组件:为什么是 view / text

uni-app 提供一套跨端抽象组件,编译时翻译成各端真实组件。最常用的一批:

组件作用类比 HTML
<view>容器<div>
<text>文本(只有它能包纯文字<span>
<image>图片(注意有默认尺寸)<img>
<scroll-view>可滚动容器滚动 div
<swiper>轮播
<input>/<textarea>表单输入同名
<button>按钮(小程序里还能触发开放能力)<button>
<navigator>声明式跳转<a>

两个新手最常踩的坑:

  1. 纯文字必须包在 <text><view>你好</view> 在 App/小程序端可能有兼容问题或不能选中,规范写法是 <view><text>你好</text></view>
  2. <image> 有默认宽高(如 320×240),且默认 mode 不裁剪,实际用几乎都要显式设宽高 + mode="aspectFill"

二、easycom:组件免注册自动引入

传统 Vue 里用组件要 import + 注册。uni-app 的 easycom 让你啥都不用写,直接用——只要组件放在约定目录、且文件名符合规范。

规则:组件放在 components/组件名/组件名.vue,就能在任意页面直接用 <组件名 />,无需 import、无需 components 注册。

components/
  goods-card/
    goods-card.vue     ← 目录名与文件名一致
<template>
  <!-- 不用 import,直接用! -->
  <goods-card :item="data" />
</template>

好处:① 少写样板代码;② 按需编译——没用到的组件不会打进包里,对小程序包体积友好。自定义 easycom 匹配规则可在 pages.jsoneasycom 字段配置(常用于引入 UI 库组件)。

三、rpx:一套尺寸走遍所有屏幕

rpx(responsive pixel)是 uni-app 的响应式长度单位,核心规则:

无论什么设备,屏幕宽度恒定视为 750rpx。

所以如果设计稿宽 750px,稿子上标注多少 px,你就写多少 rpx,1:1 照搬。运行时按 设备实际宽度 / 750 的比例换算成物理像素,自动适配大小屏。

.card {
  width: 750rpx;    /* 满屏宽 */
  padding: 24rpx;
  font-size: 28rpx;
}

换算记忆:在 375pt 逻辑宽的手机上,750rpx = 375pt,即 2rpx = 1pt

什么时候还用 px? 需要"绝对不随屏幕缩放"的场景,比如 1px 的细边框(用 rpx 在大屏会变粗)。可结合媒体查询或直接写 1px

四、条件编译:uni-app 的杀手锏

多端难免有差异——某段代码只想在微信小程序跑、某个功能 App 才有。uni-app 用条件编译优雅解决:用特殊注释包裹,编译到指定平台时才保留。

语法(三种文件通用)

// #ifdef  平台   → 满足才编译
// #ifndef 平台   → 不满足才编译
// #endif        → 结束

不同文件用不同注释符:

// JS 里
// #ifdef MP-WEIXIN
uni.login({ provider: "weixin" });
// #endif
<!-- 模板里 -->
<!-- #ifdef APP-PLUS -->
<view>只有 App 显示</view>
<!-- #endif -->
/* 样式里 */
/* #ifdef H5 */
.box { cursor: pointer; }
/* #endif */

常用平台标识

标识含义
APP-PLUSApp(uni-app) / APP(uni-app x)
H5H5
MP-WEIXIN微信小程序
MP-ALIPAY支付宝小程序
MP-TOUTIAO抖音小程序
MP所有小程序

典型用法:抹平多端登录

export function login() {
  // #ifdef MP-WEIXIN
  return uni.login({ provider: "weixin" });
  // #endif
  // #ifdef MP-ALIPAY
  return uni.getAuthCode();
  // #endif
  // #ifdef H5
  return phoneLogin();
  // #endif
}

条件编译是"编译期裁剪"——不满足条件的代码根本不会进入产物,不是运行时 if 判断。所以微信包里不会包含支付宝的登录代码,既安全又减小体积。

五、样式的跨端注意点

  • 不是所有 CSS 都支持:小程序/App 端对 CSS 支持有限,复杂选择器(如 *、属性选择器、部分伪类)在小程序可能失效。
  • App 端(nvue)用的是原生排版,flex 是默认布局,部分 CSS 属性名不同,写法更接近 RN。
  • scoped 默认生效.vue 组件样式默认作用域隔离。
  • 全局样式写在 App.vue<style>;全局 SCSS 变量放 uni.scss(自动注入,无需 import)。

六、本阶段必须掌握的知识点

  • 内置组件用 <view>/<text>/<image> 等;纯文字必须包 <text><image> 要显式设宽高与 mode
  • easycom:组件按 components/名/名.vue 放置即可免注册直接用,且按需打包。
  • rpx:屏幕恒为 750rpx,设计稿 1:1 照搬,自动适配多屏;细边框等场景仍用 px。
  • 条件编译#ifdef / #ifndef / #endif + 平台标识,编译期裁剪多端差异代码。
  • 样式跨端差异:小程序 CSS 支持有限、nvue 走原生排版、scoped 默认开启、uni.scss 全局变量。

七、高频面试题

Q1:什么是 easycom?它有什么好处?

A:easycom 是 uni-app 的组件自动引入机制。只要组件放在 components/组件名/组件名.vue(目录名与文件名一致),在任何页面无需 import、无需在 components 里注册就能直接使用。好处有二:① 省去重复的引入/注册样板;② 按需编译,未被使用的组件不会打进最终包,对小程序体积敏感场景很友好。也可在 pages.jsoneasycom.custom 里自定义匹配规则来接入第三方 UI 库。

追问:easycom 会不会把所有组件都打包进去导致包变大?

A:不会。easycom 是按使用情况引入的——它在编译时扫描模板里实际用到的标签,只编译打包被引用的组件,没用到的不会进包。所以它对包体积是正向优化,而非负担。


Q2:rpx 是什么?和 px、%、vw 有什么区别?

A:rpx 是 uni-app 的响应式单位,把任何设备的屏幕宽度都视为 750rpx,按设备实际宽度等比换算成物理像素,因此能用一套数值适配所有屏宽,且可与设计稿(750 宽)1:1 对应。区别:px 是固定物理/逻辑像素,不随屏宽缩放;% 相对父元素;vw 相对视口宽度(1vw=1% 视口宽,和 rpx 思路接近但基准不同,rpx 基准恒为 750)。做整体等比布局用 rpx,需要固定不缩放(如 1px 边框)用 px。

追问:为什么有时候 1rpx 的边框在某些手机上不显示或显示为 0?

A:因为 rpx 换算到高分屏时可能不足 1 物理像素,被渲染引擎抹掉。细线场景建议用 1px,或用 transform: scale(0.5) 的 0.5px 边框方案,保证在各 DPR 设备上稳定显示。


Q3:条件编译是什么?和运行时的 if (平台) 判断有何本质区别?

A:条件编译用 // #ifdef 平台 ... // #endif 注释包裹代码,在编译阶段根据目标平台决定该段代码是否进入产物。与运行时 if 的本质区别在于:条件编译是编译期裁剪——不满足条件的代码根本不存在于最终包里,因此更安全(微信包不含支付宝逻辑)、更省体积、也不会有运行时判断开销;而运行时 if 是所有代码都打包进去、运行时再判断,无法裁剪掉无关平台代码,还可能因调用了目标端不存在的 API 而报错。

追问:条件编译能用在哪些地方?

A:模板、脚本、样式、甚至 pages.json/manifest.json 以及静态资源目录都支持。JS/TS 用 // #ifdef,模板用 <!-- #ifdef -->,CSS 用 /* #ifdef */。还能用 APP-PLUSMP-WEIXINMP(所有小程序)、H5 等标识,以及它们的组合。


Q4:为什么 uni-app 里 <view>你好</view> 不推荐,要写成 <view><text>你好</text></view>

A:因为在小程序和 App 端,<view> 是容器组件,直接放文本节点在部分端存在兼容问题(如文字无法长按选中、样式表现不一致)。<text>专门承载文本的组件,纯文字应放入 <text>,才能保证跨端一致的显示与交互(如可选中、user-select)。这也是 uni-app 组件抽象的规范约束。

相关水晶