4、小程序组件开发:基础组件、表单组件与导航组件

说实话,小程序开发里最核心的活儿,就是跟组件打交道。你想想看,用户看到的每一个按钮、每一段文字、每一张图片,本质上都是组件的堆叠。我刚开始带团队做电商小程序时,有个新人把 viewdiv 用,结果样式全乱套了——嗯,这里面的门道还真不少。

今天这一章,咱们就把小程序里最常用的三类组件掰开揉碎讲清楚。我会结合自己踩过的坑,帮你把基础打扎实。

4.1 基础组件:view、text、image、button

基础组件就像乐高积木里的基础块。你搭任何页面都离不开它们。

4.1.1 view——万能的容器

view 是小程序里最常用的组件,没有之一。它相当于 HTML 里的 div,但功能更纯粹——就是做布局容器。

核心要点:

  • 默认是块级元素,独占一行
  • 支持 flex 布局,配合 display: flex 使用
  • 可以嵌套任意组件
<!-- 一个典型的商品卡片布局 -->
<view class="product-card">
  <view class="product-image">
    <image src="{{product.img}}" />
  </view>
  <view class="product-info">
    <text class="product-name">{{product.name}}</text>
    <text class="product-price">¥{{product.price}}</text>
  </view>
</view>

我个人习惯用 view 做所有区块的容器。但要注意,view 本身没有语义,别用它代替按钮或文本——那是其他组件的事。

小技巧:viewhover-class 属性,可以实现点击态效果。比如商品列表项,加个 hover-class="item-hover",用户体验会好很多。

4.1.2 text——文本的正确打开方式

很多新手喜欢用 view 直接放文字,这其实不对。小程序里,文本内容应该用 text 组件包裹。

为什么?因为 text 支持文本选中、支持 decode 属性解码转义字符,而且性能更好。我在项目中遇到过一个问题:用 view 显示长文本时,在低端安卓机上会出现闪烁——换成 text 后问题就解决了。

<!-- text 组件的正确用法 -->
<text selectable="true">这段文字可以被用户选中复制</text>

<!-- 解码转义字符 -->
<text decode="true">价格:&yen;99.00 &nbsp; 库存:&lt;10件&gt;</text>

注意: text 组件只能嵌套 text,不能嵌套 viewimage 等其他组件。我曾经看到有人把 image 塞进 text 里,结果图片死活不显示——嗯,这就是踩坑了。

4.1.3 image——图片加载有讲究

电商小程序里,图片是灵魂。但 image 组件有几个关键点你必须知道。

属性 说明 我的建议
src 图片地址 尽量用 HTTPS,别用 HTTP
mode 裁剪/缩放模式 商品图用 aspectFill,详情图用 widthFix
lazy-load 懒加载 列表页一定要开,性能提升明显
show-menu-by-longpress 长按识别二维码 看需求,不是必须的
<!-- 商品列表页的图片用法 -->
<image 
  src="{{item.thumb}}" 
  mode="aspectFill" 
  lazy-load="true"
  style="width: 100%; height: 200rpx;"
/>

<!-- 商品详情页的大图 -->
<image 
  src="{{detail.banner}}" 
  mode="widthFix"
  style="width: 100%;"
/>

我曾经在项目里犯过一个低级错误:商品列表的图片没开 lazy-load,结果一次性加载了 50 张图,页面卡得不行。后来加上懒加载,首屏速度提升了 40%。

4.1.4 button——不只是按钮

button 组件在小程序里很特殊。它不只是个按钮,还是很多能力的入口。

  • 获取用户信息:open-type="getUserInfo"
  • 获取手机号:open-type="getPhoneNumber"
  • 分享:open-type="share"
  • 打开客服:open-type="contact"
<!-- 电商里最常用的几个按钮 -->
<button type="primary" size="default">立即购买</button>
<button type="default" size="mini">加入购物车</button>
<button open-type="contact">联系客服</button>
<button open-type="share">分享给好友</button>

避坑指南: 我曾经在 iOS 上遇到 buttonborder-radius 失效的问题。后来发现是 button 默认有 border 样式,需要先重置 border: none 再设置圆角。嗯,这个坑我记了很久。

4.2 表单组件:input、picker、switch

表单组件是用户和系统交互的桥梁。电商里,收货地址、商品筛选、设置偏好都离不开它们。

4.2.1 input——输入框的细节

input 看似简单,但坑不少。我总结几个关键点:

  • 类型要明确: 数字键盘用 type="number",身份证用 type="idcard"
  • 密码框:password="true"
  • 占位符: placeholder 颜色可以自定义,用 placeholder-style
  • 输入事件: bindinput 实时获取,bindblur 失焦时获取
<!-- 收货地址表单 -->
<input 
  type="text" 
  placeholder="请输入收货人姓名" 
  placeholder-style="color: #999;"
  bindinput="onNameInput"
/>

<input 
  type="number" 
  maxlength="11"
  placeholder="请输入手机号"
  bindinput="onPhoneInput"
/>

<input 
  type="text" 
  placeholder="请输入详细地址"
  bindblur="onAddressBlur"
/>

注意: inputbindinput 事件返回的 event.detail.value 是实时值。如果你要做防抖处理(比如搜索框),记得用 setTimeout 控制频率。我见过有人直接拿实时值去请求接口,结果服务器被打爆了。

4.2.2 picker——选择器的妙用

picker 组件用来做选择,电商里最常见的场景就是选择商品规格(颜色、尺寸)。

模式 适用场景 示例
mode="selector" 单选列表 选择性别、支付方式
mode="multiSelector" 多列选择 选择省/市/区
mode="time" 选择时间 选择配送时间
mode="date" 选择日期 选择生日、预约日期
<!-- 商品规格选择 -->
<picker 
  mode="selector" 
  range="{{sizes}}" 
  bindchange="onSizeChange"
>
  <view class="picker-display">
    选择尺寸:{{selectedSize || '请选择'}}
  </view>
</picker>

<!-- 省市区三级联动 -->
<picker 
  mode="multiSelector" 
  range="{{regions}}" 
  bindchange="onRegionChange"
  bindcolumnchange="onColumnChange"
>
  <view class="picker-display">
    {{regionText || '请选择地区'}}
  </view>
</picker>

我个人习惯在 picker 外面包一层 view,用来做样式美化。因为 picker 本身只提供选择功能,样式需要自己写。

4.2.3 switch——开关组件

switch 组件用来做二选一,比如是否默认地址、是否开启推送。

<!-- 设置默认地址 -->
<view class="switch-row">
  <text>设为默认地址</text>
  <switch 
    checked="{{isDefault}}" 
    color="#07c160"
    bindchange="onDefaultChange"
  />
</view>

小技巧: switchcolor 属性可以自定义开关颜色。电商里我一般用品牌色,比如绿色或橙色,视觉上更统一。

4.3 导航组件:navigator

小程序里页面跳转,navigator 是官方推荐的方式。它比 wx.navigateTo 更直观,而且支持声明式写法。

4.3.1 基本用法

<!-- 跳转到商品详情页 -->
<navigator url="/pages/detail/detail?id={{item.id}}">
  <view class="product-item">
    <image src="{{item.thumb}}" />
    <text>{{item.name}}</text>
  </view>
</navigator>

<!-- 跳转到 tabBar 页面 -->
<navigator url="/pages/cart/cart" open-type="switchTab">
  <button>去购物车</button>
</navigator>

4.3.2 open-type 详解

open-type 说明 使用场景
navigate 保留当前页,跳转新页 商品列表 → 商品详情
redirect 关闭当前页,跳转新页 登录页 → 首页
switchTab 跳转到 tabBar 页面 任意页 → 购物车
reLaunch 关闭所有页,打开新页 退出登录 → 首页
navigateBack 返回上一页 详情页 → 列表页

注意: 页面栈最多 10 层。如果你用 navigate 一直跳转,超过 10 层后页面会卡死。我建议在深层跳转时用 redirect 代替,或者用 reLaunch 重置页面栈。

4.3.3 传参技巧

通过 navigator 传参,参数会拼在 URL 后面。但要注意:

  • 参数值要编码:encodeURIComponent 处理特殊字符
  • 对象要序列化:JSON.stringify 转成字符串
  • 接收时解码: 在目标页的 onLoad 里用 decodeURIComponentJSON.parse
<!-- 传递复杂对象 -->
<navigator 
  url="/pages/detail/detail?product={{encodeURIComponent(JSON.stringify(item))}}">
  <view>查看详情</view>
</navigator>

<!-- 接收参数 -->
// Page 的 onLoad 里
onLoad(options) {
  const product = JSON.parse(decodeURIComponent(options.product));
  this.setData({ product });
}

嗯,这里要提醒一下:别传太大的对象,URL 长度有限制。我一般只传 ID,然后在目标页重新请求数据——这样更安全,也更容易维护。


好了,这一章的内容就到这里。基础组件、表单组件、导航组件,这三类组件你掌握了,小程序页面开发的基本功就算打牢了。下一章我们会深入组件的自定义开发,到时候会更有意思。

本章小结:

  • view 做容器,text 放文字,image 记得开懒加载
  • button 是能力入口,open-type 要记牢
  • 表单组件注意类型和事件,picker 的多列选择有点绕
  • navigator 跳转注意页面栈,传参要编码解码

公众号:蓝海资料掘金营,微信deep3321