# 内置组件

> 官方文档：https://developers.weixin.qq.com/miniprogram/dev/component/

## 视图容器

### view
基础视图容器，类似 HTML 的 `<div>`。
```xml
<view class="container" hover-class="hover" hover-stay-time="400">
  内容
</view>
```
| 属性 | 类型 | 说明 |
|------|------|------|
| hover-class | string | 按下去的样式类，none 为不设置 |
| hover-stop-propagation | boolean | 阻止祖先节点出现点击态 |
| hover-start-time | number | 按住后多久出现点击态(ms)，默认 50 |
| hover-stay-time | number | 松开后点击态保留时间(ms)，默认 400 |

### scroll-view
可滚动视图区域。
```xml
<!-- 纵向滚动需设置固定高度 -->
<scroll-view
  scroll-y
  style="height: 300px;"
  bindscrolltolower="loadMore"
  bindscroll="onScroll"
  scroll-into-view="{{toView}}"
  scroll-top="{{scrollTop}}"
  refresher-enabled="{{true}}"
  bindrefresherrefresh="onRefresh"
>
  <view id="item1">A</view>
  <view id="item2">B</view>
  <view id="item3">C</view>
</scroll-view>
```
| 属性 | 类型 | 说明 |
|------|------|------|
| scroll-x | boolean | 允许横向滚动 |
| scroll-y | boolean | 允许纵向滚动 |
| upper-threshold | number | 距顶部/左边多远时触发 scrolltoupper(px)，默认 50 |
| lower-threshold | number | 距底部/右边多远时触发 scrolltolower(px)，默认 50 |
| scroll-top | number | 设置竖向滚动条位置 |
| scroll-into-view | string | 滚动到某子元素（id） |
| scroll-with-animation | boolean | 滚动动画过渡 |
| enable-back-to-top | boolean | iOS 点击状态栏回到顶部 |
| refresher-enabled | boolean | 开启自定义下拉刷新（2.10.1+） |
| refresher-triggered | boolean | 设置刷新状态 |
| enhanced | boolean | 增强模式（2.12.0+，支持 scroll-into-view 动画等） |

### swiper / swiper-item
滑块视图容器（轮播图）。
```xml
<swiper
  indicator-dots="{{true}}"
  autoplay="{{true}}"
  interval="{{3000}}"
  duration="{{500}}"
  circular="{{true}}"
  bindchange="swiperChange"
>
  <swiper-item wx:for="{{imgUrls}}" wx:key="*this">
    <image src="{{item}}" mode="aspectFill"/>
  </swiper-item>
</swiper>
```

### movable-area / movable-view
可拖拽区域。
```xml
<movable-area style="height: 200px; width: 200px; background: red;">
  <movable-view direction="all" style="height: 50px; width: 50px; background: blue;">
    text
  </movable-view>
</movable-area>
```

### cover-view / cover-image
覆盖在原生组件（map、video、canvas、camera、live-player、live-pusher）之上的视图。

## 基础内容

### text
```xml
<text selectable="{{true}}" space="ensp" decode="{{true}}">
  Hello &nbsp; World
</text>
```
- `selectable`：文本是否可选
- `space`：显示连续空格（ensp/emsp/nbsp）
- `decode`：是否解码（`&nbsp;` `&lt;` 等）
- **注意**：`<text>` 组件内只支持嵌套 `<text>`

### rich-text
```xml
<rich-text nodes="{{htmlNodes}}"></rich-text>
```
```javascript
data: {
  htmlNodes: '<div class="div_class"><h5>标题</h5><p>段落</p></div>'
  // 也支持 nodes 数组格式
}
```

### icon
```xml
<icon type="success" size="23" color="green"/>
```
type 可选：success, success_no_circle, info, warn, waiting, cancel, download, search, clear

### progress
```xml
<progress percent="80" show-info stroke-width="3" activeColor="#00CC00"/>
```

## 表单组件

### button
```xml
<button
  type="primary"
  size="default"
  loading="{{isLoading}}"
  disabled="{{isDisabled}}"
  open-type="getPhoneNumber"
  bindgetphonenumber="getPhoneNumber"
>
  获取手机号
</button>
```
| open-type | 说明 |
|-----------|------|
| contact | 打开客服会话 |
| share | 触发转发 |
| getPhoneNumber | 获取手机号（需配合 bindgetphonenumber） |
| getUserInfo | 已废弃（2.27.1+） |
| launchApp | 打开 APP |
| openSetting | 打开授权设置页 |
| chooseAvatar | 获取用户头像（基础库 2.21.2+） |
| agreePrivacyAuthorization | 同意隐私协议（2.33.2+） |

### input
```xml
<input
  type="text"
  placeholder="请输入"
  value="{{inputValue}}"
  bindinput="onInput"
  bindfocus="onFocus"
  bindblur="onBlur"
  bindconfirm="onConfirm"
  maxlength="140"
  confirm-type="send"
  adjust-position="{{true}}"
/>
```
| type | 说明 |
|------|------|
| text | 文本 |
| number | 数字 |
| idcard | 身份证 |
| digit | 带小数点数字 |
| nickname | 昵称输入（基础库 2.21.2+） |
| safe-password | 密码安全输入 |

### textarea
```xml
<textarea
  value="{{content}}"
  placeholder="请输入内容"
  maxlength="-1"
  auto-height
  bindinput="onInput"
  bindblur="onBlur"
  show-confirm-bar="{{false}}"
/>
```

### picker
```xml
<!-- 普通选择器 -->
<picker mode="selector" range="{{array}}" bindchange="pickerChange">
  <view>当前选择：{{array[index]}}</view>
</picker>

<!-- 多列选择器 -->
<picker mode="multiSelector" range="{{multiArray}}" bindchange="multiChange" bindcolumnchange="columnChange">
  <view>{{multiArray[0][multiIndex[0]]}} - {{multiArray[1][multiIndex[1]]}}</view>
</picker>

<!-- 时间选择器 -->
<picker mode="time" value="{{time}}" start="09:00" end="21:00" bindchange="timeChange">
  <view>{{time}}</view>
</picker>

<!-- 日期选择器 -->
<picker mode="date" value="{{date}}" start="2020-01-01" end="2030-12-31" bindchange="dateChange">
  <view>{{date}}</view>
</picker>

<!-- 省市区选择器 -->
<picker mode="region" value="{{region}}" bindchange="regionChange">
  <view>{{region[0]}} - {{region[1]}} - {{region[2]}}</view>
</picker>
```

### form
```xml
<form bindsubmit="formSubmit" bindreset="formReset">
  <input name="username" placeholder="用户名"/>
  <switch name="agree" checked/>
  <slider name="age" show-value/>
  <button form-type="submit">提交</button>
  <button form-type="reset">重置</button>
</form>
```
```javascript
formSubmit(e) {
  e.detail.value // { username: '...', agree: true, age: 50 }
}
```

### 其他表单组件
- `checkbox-group` + `checkbox`
- `radio-group` + `radio`
- `slider`
- `switch`
- `label`（绑定表单控件）

## 导航

### navigator
```xml
<navigator url="/pages/detail/detail?id=1" open-type="navigate">
  跳转到详情
</navigator>

<navigator url="/pages/index/index" open-type="switchTab">
  切换到首页 Tab
</navigator>

<navigator open-type="navigateBack" delta="1">
  返回上一页
</navigator>
```

## 媒体组件

### image
```xml
<image
  src="{{imgUrl}}"
  mode="aspectFill"
  lazy-load
  show-menu-by-longpress
  binderror="imgError"
  bindload="imgLoad"
/>
```
| mode | 说明 |
|------|------|
| scaleToFill | 不保持比例缩放，填满 |
| aspectFit | 保持比例，完整显示（可能留白） |
| aspectFill | 保持比例，填满（可能裁剪） |
| widthFix | 宽度不变，高度自适应 |
| heightFix | 高度不变，宽度自适应（2.10.3+） |
| top/bottom/center/left/right | 不缩放，显示对应区域 |

**注意**：image 默认宽 320px、高 240px。

### video
```xml
<video
  src="{{videoUrl}}"
  controls
  autoplay="{{false}}"
  loop="{{false}}"
  muted="{{false}}"
  initial-time="0"
  show-fullscreen-btn
  show-play-btn
  enable-progress-gesture
  bindplay="onPlay"
  bindpause="onPause"
  bindended="onEnded"
  binderror="onError"
/>
```

### camera
```xml
<camera
  device-position="back"
  flash="auto"
  bindscancode="onScanCode"
  style="width: 100%; height: 300px;"
/>
```

## 地图

### map
```xml
<map
  longitude="{{longitude}}"
  latitude="{{latitude}}"
  scale="16"
  markers="{{markers}}"
  polyline="{{polyline}}"
  show-location
  style="width: 100%; height: 300px;"
  bindmarkertap="onMarkerTap"
  bindregionchange="onRegionChange"
/>
```

## 画布

### canvas
```xml
<!-- 新版 Canvas 2D（推荐，基础库 2.9.0+） -->
<canvas type="2d" id="myCanvas" style="width: 300px; height: 200px;"/>
```
```javascript
const query = wx.createSelectorQuery()
query.select('#myCanvas')
  .fields({ node: true, size: true })
  .exec((res) => {
    const canvas = res[0].node
    const ctx = canvas.getContext('2d')
    const dpr = wx.getWindowInfo().pixelRatio
    canvas.width = res[0].width * dpr
    canvas.height = res[0].height * dpr
    ctx.scale(dpr, dpr)
    ctx.fillRect(0, 0, 100, 100)
  })
```

## 开放能力组件

### web-view
```xml
<!-- 承载网页的容器，会自动铺满整个小程序页面 -->
<web-view src="https://mp.weixin.qq.com/"></web-view>
```
- 需要在小程序管理后台配置业务域名
- 个人类型小程序暂不支持

### open-data（已限制）
```xml
<!-- 基础库 2.0.1+ 起，大部分 type 已不再返回真实数据 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
```

## 在线查询

组件文档非常详细，如需查看某个具体组件的完整属性和事件，可抓取：
- 组件总览：https://developers.weixin.qq.com/miniprogram/dev/component/
- 具体组件：`https://developers.weixin.qq.com/miniprogram/dev/component/{组件名}.html`
  例如：https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html
