# 前端 API

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

## API 调用约定

小程序 API 分三类：
- **事件监听 API**：以 `on` 开头，如 `wx.onSocketOpen`
- **同步 API**：以 `Sync` 结尾，如 `wx.setStorageSync`
- **异步 API**：大多数 API，支持回调和 Promise

```javascript
// 回调风格
wx.request({
  url: 'https://example.com/api',
  success(res) { console.log(res.data) },
  fail(err) { console.error(err) },
  complete() { /* 无论成功失败都执行 */ }
})

// Promise 风格（基础库 2.10.2+，除部分 API 外均支持）
const res = await wx.request({ url: 'https://example.com/api' })
// 注意：部分 API 不支持 Promise，如 wx.downloadFile、wx.connectSocket 等
```

## 路由

```javascript
// 保留当前页面，跳转（栈 +1，最多 10 层）
wx.navigateTo({
  url: '/pages/detail/detail?id=1&name=test',
  events: { /* EventChannel 监听 */ },
  success(res) { res.eventChannel.emit('data', {}) }
})

// 关闭当前页面，跳转
wx.redirectTo({ url: '/pages/other/other' })

// 关闭所有页面，打开
wx.reLaunch({ url: '/pages/index/index' })

// 跳转到 tabBar 页面（关闭其他非 tabBar 页面）
wx.switchTab({ url: '/pages/index/index' })
// ⚠️ switchTab 不支持带参数

// 返回
wx.navigateBack({ delta: 1 })
```

## 网络

### wx.request — HTTP 请求
```javascript
wx.request({
  url: 'https://example.com/api/data',
  method: 'POST',           // GET, POST, PUT, DELETE, OPTIONS, HEAD, TRACE, CONNECT
  data: { key: 'value' },
  header: {
    'content-type': 'application/json',
    'Authorization': 'Bearer token'
  },
  timeout: 60000,            // 超时时间(ms)
  dataType: 'json',          // 返回数据自动 JSON.parse
  responseType: 'text',      // text 或 arraybuffer
  enableHttp2: false,
  enableQuic: false,
  enableCache: false,
  success(res) {
    res.statusCode  // HTTP 状态码
    res.data        // 响应数据
    res.header      // 响应头
  },
  fail(err) {
    err.errMsg      // 错误信息
  }
})
```

**注意事项**：
- 需在小程序管理后台配置合法域名（request 合法域名）
- 默认超时 60s，可在 `app.json` 的 `networkTimeout.request` 配置
- 最大并发限制 10 个
- HTTPS 只支持 TLS 1.2+
- `data` 为 Object 时：GET 请求会序列化为 query string；POST 请求 header 为 `application/json` 时序列化为 JSON，为 `application/x-www-form-urlencoded` 时序列化为 query string

### wx.uploadFile — 上传文件
```javascript
wx.chooseImage({
  success(res) {
    wx.uploadFile({
      url: 'https://example.com/upload',
      filePath: res.tempFilePaths[0],
      name: 'file',
      formData: { user: 'test' },
      success(uploadRes) {
        console.log(uploadRes.data)
      }
    })
  }
})
```

### wx.downloadFile — 下载文件
```javascript
wx.downloadFile({
  url: 'https://example.com/file.pdf',
  success(res) {
    if (res.statusCode === 200) {
      wx.openDocument({ filePath: res.tempFilePath })
    }
  }
})
```

### WebSocket
```javascript
const socketTask = wx.connectSocket({
  url: 'wss://example.com/ws',
  header: { 'Authorization': 'Bearer token' }
})

socketTask.onOpen(() => {
  socketTask.send({ data: 'hello' })
})
socketTask.onMessage((res) => {
  console.log(res.data)
})
socketTask.onClose(() => {})
socketTask.onError((err) => {})
socketTask.close()
```

## 数据缓存

```javascript
// 异步
wx.setStorage({ key: 'key', data: 'value' })
wx.getStorage({
  key: 'key',
  success(res) { console.log(res.data) }
})
wx.removeStorage({ key: 'key' })
wx.clearStorage()
wx.getStorageInfo({
  success(res) {
    res.keys            // 所有 key
    res.currentSize     // 当前占用(KB)
    res.limitSize        // 限制大小(KB)
  }
})

// 同步
wx.setStorageSync('key', 'value')
const value = wx.getStorageSync('key')
wx.removeStorageSync('key')
wx.clearStorageSync()
```

**注意**：
- 单个 key 上限 1MB
- 总上限 10MB
- 隔离策略：同一小程序不同用户数据隔离

## 界面

### 交互反馈
```javascript
// Toast
wx.showToast({ title: '成功', icon: 'success', duration: 2000 })
wx.showToast({ title: '加载中', icon: 'loading' })
wx.showToast({ title: '自定义图标', icon: 'none' }) // 无图标，可显示两行文字
wx.hideToast()

// Loading
wx.showLoading({ title: '加载中', mask: true })
wx.hideLoading()

// Modal
wx.showModal({
  title: '提示',
  content: '确定删除？',
  confirmText: '确定',
  cancelText: '取消',
  success(res) {
    if (res.confirm) { /* 确定 */ }
    else if (res.cancel) { /* 取消 */ }
  }
})

// ActionSheet
wx.showActionSheet({
  itemList: ['选项A', '选项B', '选项C'],
  success(res) {
    console.log(res.tapIndex) // 0, 1, 2
  }
})
```

### 导航栏
```javascript
wx.setNavigationBarTitle({ title: '新标题' })
wx.setNavigationBarColor({
  frontColor: '#ffffff',  // 仅支持 #ffffff 和 #000000
  backgroundColor: '#ff0000',
  animation: { duration: 400, timingFunc: 'easeIn' }
})
wx.showNavigationBarLoading()
wx.hideNavigationBarLoading()
```

### 下拉刷新
```javascript
wx.startPullDownRefresh()  // 触发下拉刷新
wx.stopPullDownRefresh()   // 停止下拉刷新
```

### 滚动
```javascript
wx.pageScrollTo({
  scrollTop: 0,
  duration: 300
})
```

### TabBar
```javascript
wx.showTabBar()
wx.hideTabBar()
wx.setTabBarBadge({ index: 0, text: '1' })
wx.removeTabBarBadge({ index: 0 })
wx.showTabBarRedDot({ index: 0 })
wx.hideTabBarRedDot({ index: 0 })
wx.setTabBarItem({
  index: 0,
  text: '新文字',
  iconPath: '/images/new-icon.png',
  selectedIconPath: '/images/new-icon-active.png'
})
wx.setTabBarStyle({
  color: '#000',
  selectedColor: '#ff0000',
  backgroundColor: '#ffffff'
})
```

## 媒体

### 图片
```javascript
// 选择图片（从相册或拍照）
wx.chooseMedia({
  count: 9,
  mediaType: ['image'],
  sourceType: ['album', 'camera'],
  sizeType: ['original', 'compressed'],
  success(res) {
    res.tempFiles // [{ tempFilePath, size, ... }]
  }
})

// 预览图片
wx.previewImage({
  current: 'url',  // 当前显示图片的链接
  urls: ['url1', 'url2', 'url3']
})

// 获取图片信息
wx.getImageInfo({
  src: 'path/or/url',
  success(res) {
    res.width
    res.height
    res.path
    res.orientation
    res.type
  }
})

// 保存图片到相册
wx.saveImageToPhotosAlbum({
  filePath: 'tempFilePath',
  success() {}
})
```

## 位置

```javascript
// 获取位置（需要用户授权 scope.userLocation）
wx.getLocation({
  type: 'gcj02',  // wgs84 或 gcj02
  success(res) {
    res.latitude
    res.longitude
    res.speed
    res.accuracy
  }
})

// 打开地图选择位置
wx.chooseLocation({
  success(res) {
    res.name
    res.address
    res.latitude
    res.longitude
  }
})

// 打开内置地图查看位置
wx.openLocation({
  latitude: 23.099994,
  longitude: 113.324520,
  name: '位置名',
  address: '详细地址',
  scale: 18
})
```

## 文件系统

```javascript
const fs = wx.getFileSystemManager()

// 读文件
fs.readFile({
  filePath: `${wx.env.USER_DATA_PATH}/hello.txt`,
  encoding: 'utf8',
  success(res) { console.log(res.data) }
})

// 写文件
fs.writeFile({
  filePath: `${wx.env.USER_DATA_PATH}/hello.txt`,
  data: 'some text',
  encoding: 'utf8',
  success() {}
})

// 其他：appendFile, mkdir, rmdir, readdir, stat, unlink, rename, copyFile, access
```

## WXML 节点查询

```javascript
// SelectorQuery
const query = wx.createSelectorQuery()
query.select('#the-id').boundingClientRect((rect) => {
  rect.top    // 节点上边界坐标
  rect.right
  rect.bottom
  rect.left
  rect.width
  rect.height
})
query.selectViewport().scrollOffset((res) => {
  res.scrollTop
  res.scrollLeft
})
query.exec()

// 在组件中使用
const query = this.createSelectorQuery()
query.select('#the-id').boundingClientRect().exec(callback)

// IntersectionObserver（监听元素与视口交叉）
const observer = wx.createIntersectionObserver(this, { thresholds: [0, 0.5, 1] })
observer.relativeToViewport({ bottom: 100 })
observer.observe('.target-class', (res) => {
  res.intersectionRatio // 交叉比例
  res.intersectionRect  // 交叉区域
})
// 停止监听
observer.disconnect()
```

## 系统信息

```javascript
// 同步获取（推荐用新 API）
const windowInfo = wx.getWindowInfo()
// windowInfo.windowWidth / windowInfo.windowHeight / windowInfo.pixelRatio
// windowInfo.statusBarHeight / windowInfo.safeArea

const appBaseInfo = wx.getAppBaseInfo()
// appBaseInfo.SDKVersion / appBaseInfo.language / appBaseInfo.theme

const deviceInfo = wx.getDeviceInfo()
// deviceInfo.platform / deviceInfo.brand / deviceInfo.model / deviceInfo.system

// 旧 API（仍可用但不推荐）
const sysInfo = wx.getSystemInfoSync()
```

## 转发分享

```javascript
// 页面中定义 onShareAppMessage 即可开启转发
Page({
  onShareAppMessage(res) {
    if (res.from === 'button') {
      // 来自页面内转发按钮
    }
    return {
      title: '自定义转发标题',
      path: '/pages/index/index?id=123',
      imageUrl: '/images/share.png'
    }
  },
  onShareTimeline() {
    // 分享到朋友圈（基础库 2.11.3+）
    return {
      title: '朋友圈标题',
      query: 'id=123',
      imageUrl: '/images/share.png'
    }
  }
})
```

```xml
<!-- 页面内转发按钮 -->
<button open-type="share">转发</button>
```

## 在线查询

API 文档非常庞大，如需查看某个具体 API 的完整参数，可抓取：
- API 总览：https://developers.weixin.qq.com/miniprogram/dev/api/
- 具体 API：`https://developers.weixin.qq.com/miniprogram/dev/api/{分类}/{api名}.html`
  例如：https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
