六维教程

uni-app 样式开发

uni-app 的样式写法基本就是普通 CSS,但有两个移动端特有的重点,rpx 响应式单位多端适配的布局方式,掌握了它们,一套样式就能在手机、平板、网页上都有合理的表现。

rpx 响应式单位

rpx(responsive pixel)是 uni-app 特有的尺寸单位,规则只有一条,750rpx 永远等于屏幕宽度

换算公式,1rpx = 屏幕宽度 / 750。屏幕越宽,1rpx 对应的实际像素越多,所以同一套 rpx 尺寸在不同设备上会自动缩放。

举两个实际例子:

设备 屏幕宽度 375rpx 的实际宽度
手机(宽 375px) 375px 187.5px(正好一半)
平板(宽 750px) 750px 375px(正好一半)

无论什么设备,375rpx 都占屏幕的一半,这就是响应式。

常见单位对比

单位 说明
rpx 响应式单位,750rpx = 屏幕宽度,布局首选
px 固定像素,不随屏幕缩放,适合 1px 边框等场景
% 相对父元素百分比,搭配 rpx 使用
vw/vh 视口宽高的百分比,H5 端常用,小程序端支持有限

提示:字体大小也建议用 rpx 或固定 px,不要在字体上依赖 vw,不同端表现不一致。

Flex 弹性布局

移动端布局首选 Flex,uni-app 在所有平台都完整支持,不用担心兼容问题。

用之前那篇的商品卡片举例,横向排布用 flex-direction: row,纵向排布用 column

.goods-card {
  display: flex;              /* 开启弹性布局 */
  align-items: center;        /* 子项垂直居中 */
  justify-content: space-between; /* 子项两端对齐,中间留空 */
}

一个简单的口诀,父容器 display: flex 加方向,子元素用 flex: 1 占满剩余空间,绝大多数的布局都能搞定:

.goods-info {
  flex: 1;  /* 占据剩余全部空间 */
}

局部样式与全局样式

局部样式

组件里的 <style scoped> 只对当前组件生效,这是默认写法和最佳实践,避免类名冲突:

<style scoped>
.title {
  color: #333;
}
</style>

全局样式

写在 App.vue<style> 里,不写 scoped,所有页面都会生效,适合放公共工具类和全局字体:

<style>
page {
  background-color: #f5f5f5;
}
.flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>

注意page 是特殊选择器,相当于页面的根节点,设置页面背景色要靠它,直接给 view 设置背景色是盖不满整屏的。

pages.json 里的 globalStyle 不是 CSS

容易混淆的一点,pages.json 里的 globalStyle 配置的是窗口和导航栏外观,不是写 CSS 的地方:

{
  "globalStyle": {
    "navigationBarTitleText": "我的应用",
    "navigationBarBackgroundColor": "#007AFF",
    "navigationBarTextStyle": "white",
    "backgroundColor": "#F5F5F5",
    "enablePullDownRefresh": true
  }
}
配置项 作用
navigationBarTitleText 导航栏标题文字
navigationBarBackgroundColor 导航栏背景色
navigationBarTextStyle 导航栏文字颜色
backgroundColor 下拉时露出的背景色
enablePullDownRefresh 是否开启下拉刷新

uni.scss 全局样式变量

结构篇里介绍过 uni.scss,这里讲它的核心价值,全局变量共享

uni.scss 中定义变量:

$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-font-size-base: 28rpx;

任意组件的 <style lang="scss"> 里直接使用,不用 import:

<style lang="scss" scoped>
.btn {
  background-color: $uni-color-primary;
  font-size: $uni-font-size-base;
}
</style>

好处是主题色改一处,全应用生效。项目默认的 uni.scss 里已经带了一套官方变量($uni-color-primary 等),可以直接用。

动态样式

除了静态 class,还经常根据数据动态切换样式,两种写法:

<!-- 类名绑定 -->
<view :class="isVip ? 'vip' : 'normal'">会员状态</view>

<!-- 内联样式绑定 -->
<view :style="{ color: isVip ? '#f5a623' : '#333' }">会员状态</view>

注意动态样式建议用对象语法,单位用 rpx 时需要写成字符串:

<view :style="{ width: progress + 'rpx' }">进度条</view>

综合示例:商品列表页

用 rpx + Flex 做一个两列商品列表,验证多端适配效果:

<template>
  <view class="page">
    <view class="goods-grid">
      <view class="goods-card" v-for="item in goodsList" :key="item.id">
        <image class="goods-img" :src="item.img" mode="aspectFill"></image>
        <text class="goods-name">{{ item.name }}</text>
        <text class="goods-price">¥{{ item.price }}</text>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref } from 'vue'

const goodsList = ref(
  [1, 2, 3, 4].map((i) => ({
    id: i,
    name: '商品' + i,
    price: 99 + i,
    img: '/static/goods' + i + '.png'
  }))
)
</script>

<style scoped>
.page {
  padding: 20rpx;
  background-color: #f5f5f5;
}
.goods-grid {
  display: flex;
  flex-wrap: wrap;          /* 换行,两列布局的关键 */
  justify-content: space-between;
}
.goods-card {
  width: 345rpx;            /* (750 - 20*2 - 20) / 2,正好两列 */
  margin-bottom: 20rpx;
  padding: 16rpx;
  border-radius: 16rpx;
  background-color: #fff;
}
.goods-img {
  width: 100%;
  height: 345rpx;
  border-radius: 12rpx;
}
.goods-name {
  display: block;
  margin-top: 12rpx;
  font-size: 28rpx;
  color: #333;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;  /* 超长省略号 */
}
.goods-price {
  display: block;
  margin-top: 8rpx;
  color: #ff5000;
  font-size: 32rpx;
  font-weight: bold;
}
</style>

width: 345rpx 是这么算的,屏幕 750rpx,左右内边距各 20rpx,两列间隔 20rpx,(750 - 40 - 20) / 2 = 345。在手机上看到两列,在更宽的设备上依然保持两列并自动放大,这就是 rpx 的适配效果。

总结

知识点 要点
rpx 750rpx = 屏幕宽度,布局尺寸首选
Flex 所有平台完整支持,移动端布局主力
局部样式 组件内 <style scoped>,默认做法
全局样式 App.vue 的非 scoped style,page 设置背景色
globalStyle pages.json 里配导航栏外观,不是 CSS
uni.scss 全局变量,主题色改一处全应用生效
动态样式 :class:style 对象语法

一句话总结:布局尺寸用 rpx,结构排布用 Flex,样式写在 scoped 里,公共的东西放 App.vue 和 uni.scss,动态变化用 :class:style,这套组合能应对绝大多数移动端页面。

上一篇
uni-app 内置组件(下)
下一篇
uni-app 网络请求