Skip to main content

第二课:页面结构

小程序的模板语法约等于 vue 的模板语法

模块语言类似物学习内容
WXML微信标记语言HTML页面结构、数据绑定、条件/列表渲染
WXSS微信样式表CSS样式设置、rpx单位、自适应布局
JS/TS页面逻辑JS/TS页面生命周期、事件响应、数据交互
JSON配置语言JSON页面注册、导航栏标题、组件配置

WXML(WeiXin Markup Language) 是微信小程序的模板语言,作用类似于 HTML。它负责:

  • 描述页面结构
  • 渲染变量内容(数据绑定)
  • 控制结构逻辑(条件、循环等)

(一)基本语法和常用标签

标签功能类似 HTML
<view>容器(最常用)<div>
<text>文本显示<span>
<image>显示图片<img>
<button>按钮组件<button>
<input>输入框<input>
<scroll-view>可滚动区域<div style="overflow">

示例:

<!-- pages/example/example.wxml -->
<scroll-view class="scrollarea" scroll-y style="height: 100vh;">
  <view class="container">
    <text class="title">这是一个完整示例</text>

    <image class="banner" src="https://picsum.photos/400/200" mode="widthFix" />

    <button type="primary">主按钮</button>
    <button type="warn" size="mini" plain>警告按钮</button>
    <button loading>加载中按钮</button>
    <button disabled>禁用按钮</button>
  </view>
</scroll-view>

pages/example/example.wxss

.container {
  padding: 30rpx;
  text-align: center;
}
.title {
  font-size: 36rpx;
  margin-bottom: 20rpx;
}
.banner {
  width: 100%;
  margin-bottom: 20rpx;
}

image-20250324135741980


1. <view> 标签

  • <view> 是微信小程序中用于布局和结构组织的基础组件,作用相当于 HTML 中的 <div>
  • 几乎所有页面都由 <view> 组成,是构建页面结构的“砖块”
<view class="box">内容</view>
  • 可以加样式(通过 classstyle
  • 可以嵌套使用
  • 可以绑定事件(如 bindtap

常用属性

属性类型说明
classString应用的样式类名(对应 .wxss
styleString内联样式
idString元素标识,可用来查询或操作
hiddenBoolean是否隐藏该元素
hover-classString点击时应用的类名(类似按钮按下时的反馈)
bindtapFunction绑定点击事件

典型用法一: 页面布局容器

<view class="container">
  <view class="header">标题</view>
  <view class="body">内容部分</view>
</view>
.container {
  padding: 30rpx;
}
.header {
  font-size: 40rpx;
  font-weight: bold;
}
.body {
  font-size: 30rpx;
}

典型用法二: 响应点击事件

<view class="clickable" bindtap="onClick">点击我</view>
Page({
  onClick() {
    wx.showToast({
      title: '你点击了 View!'
    })
  }
})

典型用法三:条件渲染

<view wx:if="{{isShow}}">这是条件展示的 View</view>
Page({
  data: {
    isShow: true
  }
})

典型用法四:列表渲染

<view wx:for="{{items}}" wx:key="index">
  <view>{{index + 1}} - {{item}}</view>
</view>
Page({
  data: {
    items: ['苹果', '香蕉', '橘子']
  }
})

典型用法五:样式控制(响应式布局)

<view class="row">
  <view class="cell">1</view>
  <view class="cell">2</view>
  <view class="cell">3</view>
</view>
.row {
  display: flex;
  justify-content: space-around;
}
.cell {
  width: 100rpx;
  height: 100rpx;
  background-color: lightblue;
  text-align: center;
  line-height: 100rpx;
}

注意事项

  • <view> 本身没有样式,需要配合 CSS 使用。
  • view 没有滚动能力,如果需要可滚动容器,应使用 <scroll-view>
  • 如果你用 hover-class="hover",需要配合 CSS 样式:
.hover {
  background-color: #eee;
}

实战练习示例:点击切换 View 的显示状态

<view>
  <button bindtap="toggleShow">点击切换显示</button>

  <view wx:if="{{isVisible}}" class="box">我出现啦!</view>
</view>
Page({
  data: {
    isVisible: false
  },
  toggleShow() {
    this.setData({
      isVisible: !this.data.isVisible
    })
  }
})
.box {
  margin-top: 30rpx;
  padding: 20rpx;
  background-color: #f0f0f0;
  text-align: center;
}


2. <text> 标签

  • <text> 是微信小程序中用于显示纯文本内容的组件。
  • 相当于 HTML 中的 <span>
  • <view> 不同,它默认是行内元素,主要用于小段文字、标签、图标说明等。
<text>你好,小程序!</text>

也可以绑定变量:

<text>你好,{{name}}</text>
Page({
  data: {
    name: '开发者'
  }
})


常用属性

功能用法示例
绑定变量<text>{{name}}</text>
设置可复制<text selectable="true">
保留空格<text space="nbsp">
解码 HTML 字符<text decode="true">
控制行数(超长文字)<text number-of-lines="1">
<text selectable="true">这段文字可以被复制</text>
<text space="nbsp">空格测试:你 好 吗</text>
<text decode="true">使用转义:&lt;text&gt;显示为&lt;/text&gt;</text> //让转义字符被解析为正常字符。

示例:绑定数据、设置样式、控制行数

<view class="container">
  <text class="title">你好,{{name}}!</text>

  <text class="description" selectable="true" space="nbsp" decode="true">&nbsp;是一&nbsp;&nbsp;&nbsp;段带空格的、支持复制的文字。
  </text>

  <text class="cut" number-of-lines="1">
    这是一段非常长非常长非常长非常长的文字,你只能看到一行,后面的会被省略。
  </text>
</view>
Page({
  data: {
    name: '小程序开发者'
  }
})
.container {
  padding: 20rpx;
}
.title {
  font-size: 36rpx;
  font-weight: bold;
}
.description {
  margin-top: 20rpx;
  color: #666;
  font-size: 28rpx;
}
.cut {
  margin-top: 20rpx;
  width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

<text> vs <view>

对比项<text><view>
默认行为行内元素(类似 <span>块级容器(类似 <div>
是否能换行❌(默认不能)
是否用于布局
是否能嵌套✅(不能嵌套 <view>
是否能复制文本✅(需 selectable


3. <image> 标签

<image> 是微信小程序中用于显示图片的组件,功能非常丰富,不仅支持本地和网络图片,还能控制裁剪、缩放、加载错误、懒加载等行为。

<image src="图片地址" />

属性大全(附详细解释)

属性名类型说明示例
srcString图片路径(本地或网络)/images/logo.pnghttps://example.com/1.jpg
modeString图片裁剪与缩放模式(非常重要)aspectFitwidthFix
lazy-loadBoolean是否启用懒加载lazy-load="true"
show-menu-by-longpressBoolean长按图片是否弹出菜单(保存/识别)show-menu-by-longpress="true"
bindloadEvent图片加载成功触发bindload="onImgLoad"
binderrorEvent图片加载失败触发binderror="onImgError"
webpBoolean是否使用 webp 格式(只支持网络图)webp="true"(仅限 Android)
draggableBoolean是否可拖动(iOS有效)draggable="true"

重点属性:mode

mode 决定了图片在容器中的展示方式。它非常类似于 CSS 的 object-fit

模式名含义类似 CSS
scaleToFill不保持纵横比缩放,填满容器(默认)object-fit: fill
aspectFit保持纵横比,完整显示图片object-fit: contain
aspectFill保持纵横比,裁剪图片填满容器object-fit: cover
widthFix宽度不变,高度自动width: 100%; height: auto;
heightFix高度不变,宽度自动(需手动处理)无直接对应
top / bottom / center图片不缩放,定位显示某个部分CSS background-position

示例对比:

<!-- 保持比例缩放,完整显示 -->
<image src="/images/banner.jpg" mode="aspectFit" />

<!-- 裁剪图片铺满容器 -->
<image src="/images/banner.jpg" mode="aspectFill" />

<!-- 固定宽度,高度自适应 -->
<image src="/images/banner.jpg" mode="widthFix" style="width: 300rpx;" />

image-20250324141149370


加载事件绑定(onload / onerror)

可以用来监听页面图片是否成功加载:

<image src="https://example.com/1.jpg" bindload="onImgLoad" binderror="onImgError" />
Page({
  onImgLoad() {
    console.log("图片加载成功!")
  },
  onImgError() {
    console.log("图片加载失败!")
  }
})

在线图片 & 微信域名限制

  • 本地图片的路径都是相对于 miniprogram

  • 你可以直接使用在线图,例如 https://picsum.photos/200/300

  • 但如果你要在真机预览或上线版本使用,必须在微信后台 → 开发 → 开发设置 → 下载域名白名单中添加该域名。


完整示例

<view class="container">
  <text>展示三种图片模式:</text>

  <image src="https://picsum.photos/200/300" mode="aspectFit" style="width: 300rpx; height: 200rpx;" />
  <image src="https://picsum.photos/200/300" mode="aspectFill" style="width: 300rpx; height: 200rpx;" />
  <image src="https://picsum.photos/200/300" mode="widthFix" style="width: 300rpx;" />

  <text>加载失败测试:</text>
  <image src="https://invalid-url/image.jpg" binderror="onImgError" style="width: 300rpx; height: 200rpx;" />
</view>
Page({
  onImgError() {
    wx.showToast({
      title: '图片加载失败',
      icon: 'error'
    })
  }
})


4. <button> 标签

微信小程序中的 <button> 标签远比 HTML 的 <button> 功能丰富,集成了很多内置功能:

属性说明
type按钮样式类型:default(默认)、primary(蓝色)、warn(红色)
size尺寸:default / mini
plain是否镂空(只显示边框)
disabled是否禁用
loading是否显示加载中
formType表单按钮类型,如 submitreset
open-type用于授权/跳转等操作,例如 getUserInfocontactshare

示例:

<view class="container">
  <button type="primary">主按钮</button>
  <button type="warn" size="mini" plain>警告按钮</button>
  <button loading>加载中</button>
  <button disabled>禁用按钮</button>
</view>

5. <input> 标签

  • <input> 是微信小程序中用于**接收用户输入(单行文本)**的组件,类似 HTML 中的 <input type="text">
  • 它是用户与页面交互的核心组件之一,常用于昵称输入、搜索框、表单字段等。
<input placeholder="请输入昵称" bindinput="onInputChange" />
<text>你好,{{name}}</text>

读取输入内容

Page({
  data: {
    name: ''
  },
  onInputChange(e) {
    this.setData({
      name: e.detail.value
    })
  }
})

常用属性

属性类型说明示例
valueString输入框的初始值value="{{nickName}}"
placeholderString占位提示文字placeholder="请输入名称"
disabledBoolean是否禁用disabled="true"
passwordBoolean是否为密码输入(掩码显示)password="true"
typeString输入框类型(详见下方)type="number"
maxlengthNumber最大输入长度maxlength="20"
cursorNumber设置光标位置cursor="5"
focusBoolean是否自动获取焦点focus="true"
confirm-typeString设置回车键文字(仅小程序)confirm-type="search"
bindinputEvent输入过程中触发(建议用这个)bindinput="onInput"
bindblurEvent失去焦点时触发bindblur="onBlur"
bindconfirmEvent回车(确认)时触发bindconfirm="onConfirm"

type 可选值

类型用途
text默认文本输入
number数字输入
idcard身份证输入
digit带小数点数字
tel电话号码
nickname昵称输入(微信原生)
safe-password安全密码键盘(仅 iOS)
<input password="true" placeholder="请输入密码" />   //密码框
<input type="number" maxlength="6" placeholder="请输入6位验证码" /> //数字输入框 + 限制长度
<input focus="true" confirm-type="search" bindconfirm="onSearch" /> //自动聚焦 + 回车事件

Page({
  onSearch(e) {
    console.log("搜索内容:", e.detail.value)
  }
})


6. <scroll-view> 标签

  • <scroll-view> 是微信小程序提供的可滚动区域组件,用于处理内容超出容器时,支持垂直或水平方向的滚动
  • 适用于 内容较多的页面,例如:长列表、新闻流、商品展示、聊天记录等。
<scroll-view scroll-y="true" style="height: 300rpx;">
  <view class="content">这里是滚动区域的内容</view>
  <view class="content">这里是更多内容</view>
</scroll-view>

常用属性

属性类型说明示例
scroll-yBoolean是否启用纵向滚动scroll-y="true"
scroll-xBoolean是否启用横向滚动scroll-x="true"
scroll-into-viewString滚动到指定元素的 IDscroll-into-view="targetId"
scroll-topNumber初始位置的垂直偏移量scroll-top="100"
scroll-leftNumber初始位置的水平偏移量scroll-left="50"
upper-thresholdNumber上边界距离顶部的距离,单位 rpx。触发 bindscrolltoupper事件upper-threshold="50"
lower-thresholdNumber下边界距离底部的距离,单位 rpx。触发bindscrolltolower 事件lower-threshold="50"
bindscrollEvent滚动过程中触发,获取滚动的偏移量。bindscroll="onScroll"
bindscrolltolowerEvent滚动到下边界时触发bindscrolltolower="onScrollToLower"
bindscrolltoupperEvent滚动到上边界时触发bindscrolltoupper="onScrollToUpper"
<scroll-view bindscroll="onScroll" scroll-y="true" style="height: 300rpx;">
  <view class="content">更多内容...</view>
</scroll-view>
Page({
  onScroll(e) {
    console.log('滚动偏移量:', e.detail.scrollTop);
  }
})

示例:垂直滚动 + 无限加载

<scroll-view scroll-y="true" style="height: 400rpx;" bindscrolltolower="onScrollToLower">
  <view class="content" wx:for="{{items}}" wx:key="index">
    <text>{{item}}</text>
  </view>
</scroll-view>
Page({
  data: {
    items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']
  },
  onScrollToLower() {
    // 模拟加载更多数据
    const newItems = ['Item 6', 'Item 7', 'Item 8'];
    this.setData({
      items: this.data.items.concat(newItems)
    });
    wx.showToast({
      title: '加载更多',
      icon: 'none'
    });
  }
})

我们注意到默认 index.wxml 中最外层标签是<scroll-view> 而不是 <view>,这有什么好处呢?

<scroll-view> 是可以滚动的容器,类似于 HTML 中的 <div style="overflow: scroll; height: 100vh;"></div> , 它可以让内容在限定区域内上下或左右滚动。支持属性 scroll-y(纵向滚动)或 scroll-x(横向滚动)。可以搭配滚动条/吸顶导航栏/无限加载等功能。微信小程序的默认首页结构使用 <scroll-view scroll-y> 是为了:

  • 避免内容超出屏幕被裁剪。
  • 支持滚动操作,比如查看更多内容、滚动加载数据。
  • 更接近 App 级别的交互体验


(二) 数据绑定 {{变量名}}

从页面 JS 中的 data 绑定变量到页面上:

JS:

Page({
  data: {
    name: '小程序开发者'
  }
})

WXML:

<text>Hello, {{name}} 👋</text>

(三)条件渲染

wx:if / wx:elif / wx:else 用于控制内容是否显示:

<view wx:if="{{isLoggedIn}}">欢迎回来</view>
<view wx:else>请先登录</view>
Page({
  data: {
    isLoggedIn: false
  }
})

(四)列表渲染

wx:for 动态生成一组内容:

<view wx:for="{{items}}" wx:key="id">
  <text>{{index + 1}}. {{item.name}}</text>
</view>
Page({
  data: {
    items: [
      { id: 1, name: '苹果' },
      { id: 2, name: '香蕉' },
      { id: 3, name: '橘子' }
    ]
  }
})
  • wx:key="id":提高渲染效率,建议加上。
  • indexitem 是默认提供的变量。

(五)事件绑定

bindtap

<button bindtap="onClick">点我</button>
Page({
  onClick() {
    wx.showToast({
      title: '你点了我!'
    })
  }
})

(六)表单类标签

标签用途
<input />文本输入框
<picker />下拉选择器
<switch />开关按钮
<slider />滑动条
<form>表单容器,可搭配 bindsubmit

实战:注册/登录界面

要求如下:

做一个登录页面,需要包含居中Logo,用户名,密码,邮箱,性别(选择男或女),并有一个提交按钮,按钮下方还有一个连接指向“注册”(注册界面不需要完成)。点击提交按钮,按钮变成加载状态并延迟一秒(模拟内在逻辑处理),如果用户名和密码正确则弹出提示“登录成功”

项目结构:

miniprogram/
├─pages/
│ └─login/
│ ├─login.wxml
│ ├─login.wxss
│ └─login.ts