mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-12 16:40:40 +08:00
refactor: 架构升级
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
---
|
||||
name: Manifest.json Configuration
|
||||
description: App configuration, permissions, and platform-specific settings
|
||||
---
|
||||
|
||||
# Manifest.json Configuration
|
||||
|
||||
`manifest.json` is the application configuration file, defining app name, icon, permissions, and platform-specific settings.
|
||||
|
||||
## Basic Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "My App",
|
||||
"appid": "__UNI__XXXXXXX",
|
||||
"description": "App description",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": 100,
|
||||
"locale": "auto",
|
||||
"debug": false
|
||||
}
|
||||
```
|
||||
|
||||
### Basic Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| name | String | App name |
|
||||
| appid | String | DCloud app ID |
|
||||
| description | String | App description |
|
||||
| versionName | String | Version name (1.0.0) |
|
||||
| versionCode | Number | Version code (integer) |
|
||||
| locale | String | Default language |
|
||||
| debug | Boolean | Debug mode |
|
||||
| networkTimeout | Object | Network timeout settings |
|
||||
| uniStatistics | Object | Statistics configuration |
|
||||
|
||||
## Network Timeout
|
||||
|
||||
```json
|
||||
{
|
||||
"networkTimeout": {
|
||||
"request": 60000,
|
||||
"connectSocket": 60000,
|
||||
"uploadFile": 60000,
|
||||
"downloadFile": 60000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## App Configuration (app-plus)
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"autoclose": true,
|
||||
"waiting": true
|
||||
},
|
||||
"screenOrientation": ["portrait-primary"],
|
||||
"modules": {
|
||||
"OAuth": {},
|
||||
"Payment": {},
|
||||
"Push": {}
|
||||
},
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.INTERNET\" />"
|
||||
],
|
||||
"minSdkVersion": 21,
|
||||
"targetSdkVersion": 30
|
||||
},
|
||||
"ios": {
|
||||
"capabilities": {
|
||||
"entitlements": {
|
||||
"com.apple.developer.push": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"sdkConfigs": {
|
||||
"payment": {
|
||||
"alipay": {},
|
||||
"weixin": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"optimization": {
|
||||
"subPackages": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Splash Screen
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| alwaysShowBeforeRender | Boolean | Show until first page renders |
|
||||
| autoclose | Boolean | Auto close splash screen |
|
||||
| waiting | Boolean | Show loading indicator |
|
||||
|
||||
## Mini-Program Configuration
|
||||
|
||||
### WeChat (mp-weixin)
|
||||
|
||||
```json
|
||||
{
|
||||
"mp-weixin": {
|
||||
"appid": "wx1234567890",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"postcss": true,
|
||||
"minified": true
|
||||
},
|
||||
"usingComponents": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "Your location is needed"
|
||||
}
|
||||
},
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Alipay (mp-alipay)
|
||||
|
||||
```json
|
||||
{
|
||||
"mp-alipay": {
|
||||
"appid": "2021...",
|
||||
"allowsAlignRight": true,
|
||||
"component2": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Baidu (mp-baidu)
|
||||
|
||||
```json
|
||||
{
|
||||
"mp-baidu": {
|
||||
"appid": "12345678",
|
||||
"navigationBarForceEnable": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Douyin (mp-toutiao)
|
||||
|
||||
```json
|
||||
{
|
||||
"mp-toutiao": {
|
||||
"appid": "tt...",
|
||||
"setting": {
|
||||
"es6": true,
|
||||
"minified": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## H5 Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"h5": {
|
||||
"title": "My App",
|
||||
"template": "index.html",
|
||||
"router": {
|
||||
"mode": "hash",
|
||||
"base": "./"
|
||||
},
|
||||
"optimization": {
|
||||
"treeShaking": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"publicPath": "./",
|
||||
"devServer": {
|
||||
"port": 8080,
|
||||
"disableHostCheck": true
|
||||
},
|
||||
"sdkConfigs": {
|
||||
"maps": {
|
||||
"qqmap": {
|
||||
"key": "..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vue Configuration
|
||||
|
||||
### Vue 2
|
||||
|
||||
```json
|
||||
{
|
||||
"vueVersion": "2",
|
||||
"sassImplementationName": "dart-sass"
|
||||
}
|
||||
```
|
||||
|
||||
### Vue 3
|
||||
|
||||
```json
|
||||
{
|
||||
"vueVersion": "3"
|
||||
}
|
||||
```
|
||||
|
||||
## Permission Configuration
|
||||
|
||||
### Android Permissions
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.INTERNET\" />",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\" />",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
|
||||
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### iOS Privacy Descriptions
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"distribute": {
|
||||
"ios": {
|
||||
"privacyDescription": {
|
||||
"NSCameraUsageDescription": "Camera access is needed for scanning QR codes",
|
||||
"NSPhotoLibraryUsageDescription": "Photo access is needed for uploading images",
|
||||
"NSLocationWhenInUseUsageDescription": "Location is needed for finding nearby stores"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Common Module Configuration
|
||||
|
||||
### OAuth (Login)
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"modules": {
|
||||
"OAuth": {}
|
||||
},
|
||||
"distribute": {
|
||||
"sdkConfigs": {
|
||||
"oauth": {
|
||||
"weixin": {
|
||||
"appid": "wx...",
|
||||
"appsecret": "...",
|
||||
"UniversalLinks": "https://..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Payment
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"modules": {
|
||||
"Payment": {}
|
||||
},
|
||||
"distribute": {
|
||||
"sdkConfigs": {
|
||||
"payment": {
|
||||
"alipay": {},
|
||||
"weixin": {
|
||||
"appid": "wx..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Push Notifications
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"modules": {
|
||||
"Push": {}
|
||||
},
|
||||
"distribute": {
|
||||
"sdkConfigs": {
|
||||
"push": {
|
||||
"unipush": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Share
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"modules": {
|
||||
"Share": {}
|
||||
},
|
||||
"distribute": {
|
||||
"sdkConfigs": {
|
||||
"share": {
|
||||
"weixin": {
|
||||
"appid": "wx..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Statistics Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"uniStatistics": {
|
||||
"enable": true
|
||||
},
|
||||
"app-plus": {
|
||||
"uniStatistics": {
|
||||
"enable": true
|
||||
}
|
||||
},
|
||||
"mp-weixin": {
|
||||
"uniStatistics": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/collocation/manifest.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/collocation/manifest-app.md
|
||||
-->
|
||||
@@ -0,0 +1,270 @@
|
||||
---
|
||||
name: Pages.json Configuration
|
||||
description: Page routing, tab bar, and global style configuration
|
||||
---
|
||||
|
||||
# Pages.json Configuration
|
||||
|
||||
`pages.json` is the global configuration file for uni-app, defining page routes, window styles, native navigation bar, and tab bar.
|
||||
|
||||
## Basic Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Home"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "#F8F8F8"
|
||||
},
|
||||
"tabBar": {
|
||||
"list": [
|
||||
{ "pagePath": "pages/index/index", "text": "Home" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Root Properties
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| pages | Array | Yes | Page routes |
|
||||
| globalStyle | Object | No | Default window style |
|
||||
| tabBar | Object | No | Tab bar configuration |
|
||||
| condition | Object | No | Launch mode (dev only) |
|
||||
| subPackages | Array | No | Sub-packages |
|
||||
| preloadRule | Object | No | Preload rules (MP) |
|
||||
| easycom | Object | No | Auto component import |
|
||||
| leftWindow/topWindow/rightWindow | Object | No | Multi-window (H5) |
|
||||
|
||||
## Pages Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Home",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/detail/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Detail",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Page Style Options
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| navigationBarTitleText | String | Navigation title |
|
||||
| navigationBarTextStyle | String | Title color: black/white |
|
||||
| navigationBarBackgroundColor | HexColor | Nav background |
|
||||
| navigationStyle | String | default/custom |
|
||||
| enablePullDownRefresh | Boolean | Enable pull refresh |
|
||||
| backgroundColor | HexColor | Background color |
|
||||
| backgroundTextStyle | String | dark/light |
|
||||
| onReachBottomDistance | Number | Bottom distance (px) |
|
||||
| disableScroll | Boolean | Disable scroll (MP) |
|
||||
| usingComponents | Object | Using custom components |
|
||||
|
||||
## Global Style
|
||||
|
||||
Applied to all pages unless overridden.
|
||||
|
||||
```json
|
||||
{
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "My App",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"backgroundTextStyle": "dark",
|
||||
"enablePullDownRefresh": false,
|
||||
"onReachBottomDistance": 50,
|
||||
"rpxCalcMaxDeviceWidth": 960,
|
||||
"rpxCalcBaseDeviceWidth": 375,
|
||||
"rpxCalcIncludeWidth": 750
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tab Bar Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"tabBar": {
|
||||
"color": "#7A7E83",
|
||||
"selectedColor": "#3cc51f",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "black",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "Home",
|
||||
"iconPath": "static/image/home.png",
|
||||
"selectedIconPath": "static/image/home-active.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/category/category",
|
||||
"text": "Category",
|
||||
"iconPath": "static/image/cat.png",
|
||||
"selectedIconPath": "static/image/cat-active.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/cart/cart",
|
||||
"text": "Cart",
|
||||
"iconPath": "static/image/cart.png",
|
||||
"selectedIconPath": "static/image/cart-active.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/user/user",
|
||||
"text": "User",
|
||||
"iconPath": "static/image/user.png",
|
||||
"selectedIconPath": "static/image/user-active.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tab Bar Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| color | HexColor | Unselected text color |
|
||||
| selectedColor | HexColor | Selected text color |
|
||||
| backgroundColor | HexColor | Background color |
|
||||
| borderStyle | String | black/white |
|
||||
| list | Array | Tab items (2-5 items) |
|
||||
| position | String | bottom/top |
|
||||
|
||||
### Tab Item Properties
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| pagePath | String | Yes | Page path |
|
||||
| text | String | Yes | Tab text |
|
||||
| iconPath | String | No | Icon path (81x81px) |
|
||||
| selectedIconPath | String | No | Selected icon |
|
||||
|
||||
### Custom Tab Bar (WeChat/QQ/Douyin)
|
||||
|
||||
```json
|
||||
{
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
"list": [
|
||||
{ "pagePath": "pages/index/index", "text": "Home" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create `custom-tab-bar/index` component in root.
|
||||
|
||||
## Sub-packages
|
||||
|
||||
Split app into smaller chunks for faster loading.
|
||||
|
||||
```json
|
||||
{
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "packageA",
|
||||
"pages": [
|
||||
{ "path": "pages/cat/cat" },
|
||||
{ "path": "pages/dog/dog" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "packageB",
|
||||
"pages": [
|
||||
{ "path": "pages/apple/apple" },
|
||||
{ "path": "pages/banana/banana" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"preloadRule": {
|
||||
"pages/index/index": {
|
||||
"network": "all",
|
||||
"packages": ["packageA"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## EasyCom (Auto Component Import)
|
||||
|
||||
```json
|
||||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this config, components are auto-imported without registration.
|
||||
|
||||
## Conditional Compilation in Config
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "Home"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black"
|
||||
},
|
||||
"condition": {
|
||||
"current": 0,
|
||||
"list": [
|
||||
{
|
||||
"name": "test",
|
||||
"path": "pages/test/test",
|
||||
"query": "id=1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mp-weixin": {
|
||||
"appid": "wx...",
|
||||
"setting": {
|
||||
"urlCheck": false
|
||||
}
|
||||
},
|
||||
"app-plus": {
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/collocation/pages.md
|
||||
-->
|
||||
@@ -0,0 +1,250 @@
|
||||
---
|
||||
name: Form Components
|
||||
description: Input, selection, and form control components
|
||||
---
|
||||
|
||||
# Form Components
|
||||
|
||||
## input
|
||||
|
||||
Single-line text input.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<input
|
||||
v-model="inputValue"
|
||||
type="text"
|
||||
placeholder="Enter text"
|
||||
:maxlength="100"
|
||||
:focus="true"
|
||||
@input="onInput"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| value | String | | Input value |
|
||||
| type | String | text | Input type: text/number/idcard/digit/tel |
|
||||
| password | Boolean | false | Password input |
|
||||
| placeholder | String | | Placeholder text |
|
||||
| placeholder-style | String | | Placeholder inline styles |
|
||||
| placeholder-class | String | | Placeholder CSS class |
|
||||
| maxlength | Number | 140 | Max character length |
|
||||
| cursor-spacing | Number | 0 | Cursor distance from keyboard bottom (px) |
|
||||
| focus | Boolean | false | Auto focus |
|
||||
| confirm-type | String | done | Return key type: send/search/next/go/done |
|
||||
| confirm-hold | Boolean | false | Keep keyboard open after confirm |
|
||||
|
||||
**Events:**
|
||||
- `@input` - Input value change
|
||||
- `@focus` - Input focused
|
||||
- `@blur` - Input blurred
|
||||
- `@confirm` - Confirm button clicked
|
||||
- `@keyboardheightchange` - Keyboard height changed
|
||||
|
||||
## textarea
|
||||
|
||||
Multi-line text input.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<textarea
|
||||
v-model="content"
|
||||
placeholder="Enter content"
|
||||
:maxlength="500"
|
||||
:auto-height="true"
|
||||
:show-confirm-bar="false"
|
||||
@linechange="onLineChange"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Additional Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| auto-height | Boolean | false | Auto adjust height |
|
||||
| fixed | Boolean | false | Fixed position when scrolling |
|
||||
| cursor | Number | | Cursor position |
|
||||
| show-confirm-bar | Boolean | true | Show recommendation bar (WeChat) |
|
||||
| selection-start | Number | -1 | Selection start position |
|
||||
| selection-end | Number | -1 | Selection end position |
|
||||
|
||||
## picker
|
||||
|
||||
Selection from predefined options.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Selector mode -->
|
||||
<picker mode="selector" :range="options" :value="selected" @change="onChange">
|
||||
<view>Selected: {{ options[selected] }}</view>
|
||||
</picker>
|
||||
|
||||
<!-- Multi-selector -->
|
||||
<picker mode="multiSelector" :range="multiOptions" @change="onMultiChange">
|
||||
<view>Multi-select</view>
|
||||
</picker>
|
||||
|
||||
<!-- Date picker -->
|
||||
<picker mode="date" :value="date" :start="startDate" :end="endDate" @change="onDateChange">
|
||||
<view>Date: {{ date }}</view>
|
||||
</picker>
|
||||
|
||||
<!-- Region picker -->
|
||||
<picker mode="region" :value="region" @change="onRegionChange">
|
||||
<view>Region: {{ region.join('-') }}</view>
|
||||
</picker>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: ['Option 1', 'Option 2', 'Option 3'],
|
||||
selected: 0,
|
||||
multiOptions: [['A', 'B'], ['1', '2', '3']],
|
||||
date: '2024-01-01',
|
||||
startDate: '2020-01-01',
|
||||
endDate: '2025-12-31',
|
||||
region: ['Beijing', 'Beijing', 'Dongcheng']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(e) {
|
||||
this.selected = e.detail.value
|
||||
},
|
||||
onDateChange(e) {
|
||||
this.date = e.detail.value
|
||||
},
|
||||
onRegionChange(e) {
|
||||
this.region = e.detail.value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**Mode-specific Properties:**
|
||||
|
||||
| Mode | Properties |
|
||||
|------|------------|
|
||||
| selector | range, range-key |
|
||||
| multiSelector | range, range-key |
|
||||
| time | start, end |
|
||||
| date | start, end, fields (year/month/day) |
|
||||
| region | custom-item, disable-sub-districts |
|
||||
|
||||
## picker-view
|
||||
|
||||
Embedded picker view (inline, not popup).
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<picker-view :value="value" @change="onChange">
|
||||
<picker-view-column>
|
||||
<view v-for="item in years" :key="item">{{ item }}年</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view v-for="item in months" :key="item">{{ item }}月</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</template>
|
||||
```
|
||||
|
||||
## radio / checkbox
|
||||
|
||||
Selection controls.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Radio group -->
|
||||
<radio-group @change="onRadioChange">
|
||||
<label v-for="item in items" :key="item.value">
|
||||
<radio :value="item.value" :checked="item.checked" color="#007AFF" />
|
||||
{{ item.name }}
|
||||
</label>
|
||||
</radio-group>
|
||||
|
||||
<!-- Checkbox group -->
|
||||
<checkbox-group @change="onCheckboxChange">
|
||||
<label v-for="item in items" :key="item.value">
|
||||
<checkbox :value="item.value" :checked="item.checked" color="#007AFF" />
|
||||
{{ item.name }}
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</template>
|
||||
```
|
||||
|
||||
**radio/checkbox Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| value | String | | Identifier value |
|
||||
| checked | Boolean | false | Selected state |
|
||||
| disabled | Boolean | false | Disabled state |
|
||||
| color | Color | | Selected color |
|
||||
|
||||
## switch
|
||||
|
||||
Toggle switch.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<switch
|
||||
:checked="isOn"
|
||||
:disabled="false"
|
||||
type="switch"
|
||||
color="#007AFF"
|
||||
@change="onSwitchChange"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| checked | Boolean | false | Checked state |
|
||||
| disabled | Boolean | false | Disabled state |
|
||||
| type | String | switch | Style: switch/checkbox |
|
||||
| color | Color | | Switch color when on |
|
||||
|
||||
## slider
|
||||
|
||||
Range slider input.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<slider
|
||||
:value="50"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:show-value="true"
|
||||
:disabled="false"
|
||||
activeColor="#007AFF"
|
||||
backgroundColor="#e9e9e9"
|
||||
block-size="28"
|
||||
@change="onChange"
|
||||
@changing="onChanging"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/input.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/textarea.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/picker.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/radio.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/checkbox.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/switch.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/slider.md
|
||||
-->
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
name: Core Framework
|
||||
description: UniApp core framework concepts, project structure, and platform overview
|
||||
---
|
||||
|
||||
# UniApp Core Framework
|
||||
|
||||
UniApp is a Vue.js-based cross-platform framework for developing applications that run on iOS, Android, HarmonyOS, Web, and various mini-program platforms (WeChat, Alipay, Baidu, Douyin, etc.).
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
project-root/
|
||||
├── pages/ # Page files
|
||||
│ └── index/
|
||||
│ └── index.vue # Page component
|
||||
├── components/ # Reusable components
|
||||
├── static/ # Static assets (images, fonts)
|
||||
├── App.vue # Application root component
|
||||
├── main.js # Application entry
|
||||
├── manifest.json # App configuration
|
||||
├── pages.json # Page routing config
|
||||
└── uni.scss # Global SCSS variables
|
||||
```
|
||||
|
||||
## Platform Support
|
||||
|
||||
| Platform | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| App | APP-PLUS | iOS/Android native apps |
|
||||
| App nvue | APP-PLUS-NVUE | Native rendering pages |
|
||||
| H5 | H5 / WEB | Web applications |
|
||||
| WeChat Mini Program | MP-WEIXIN | WeChat MP |
|
||||
| Alipay | MP-ALIPAY | Alipay MP |
|
||||
| Baidu | MP-BAIDU | Baidu Smart Program |
|
||||
| Douyin | MP-TOUTIAO | ByteDance MP |
|
||||
| QQ | MP-QQ | QQ Mini Program |
|
||||
| Kuaishou | MP-KUAISHOU | Kuaishou MP |
|
||||
| HarmonyOS | APP-HARMONY | HarmonyOS Next |
|
||||
|
||||
## Condition Compilation
|
||||
|
||||
Handle platform differences using special comment syntax:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<!-- #ifdef APP-PLUS -->
|
||||
<text>App only content</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<text>WeChat MP only</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifndef H5 -->
|
||||
<text>All platforms except H5</text>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
getPlatform() {
|
||||
// #ifdef APP-PLUS
|
||||
return 'App'
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
return 'Web'
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* #ifdef APP-PLUS */
|
||||
.app-style { padding: 20px; }
|
||||
/* #endif */
|
||||
</style>
|
||||
```
|
||||
|
||||
## Platform Values Reference
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| VUE3 / VUE2 | Vue version |
|
||||
| UNI-APP-X | UniApp X project |
|
||||
| APP-PLUS | App (JS engine) |
|
||||
| APP-PLUS-NVUE / APP-NVUE | App nvue pages |
|
||||
| APP-ANDROID | Android platform |
|
||||
| APP-IOS | iOS platform |
|
||||
| APP-HARMONY | HarmonyOS Next |
|
||||
| H5 / WEB | Web platform |
|
||||
| MP-WEIXIN | WeChat Mini Program |
|
||||
| MP-ALIPAY | Alipay Mini Program |
|
||||
| MP-BAIDU | Baidu Smart Program |
|
||||
| MP-TOUTIAO | Douyin Mini Program |
|
||||
| MP-LARK | Feishu Mini Program |
|
||||
| MP-QQ | QQ Mini Program |
|
||||
| MP-KUAISHOU | Kuaishou Mini Program |
|
||||
| MP-HARMONY | HarmonyOS Meta Service |
|
||||
|
||||
## API Promise Support
|
||||
|
||||
UniApp APIs support Promise when no callback is provided:
|
||||
|
||||
```javascript
|
||||
// Promise style
|
||||
uni.request({ url: 'https://api.example.com' })
|
||||
.then(res => console.log(res))
|
||||
.catch(err => console.error(err))
|
||||
|
||||
// Async/await
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await uni.request({ url: 'https://api.example.com' })
|
||||
return res.data
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Synchronous APIs (ending in `Sync`), `create*` methods, and `*Manager` methods do not support Promise.
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/README.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/tutorial/platform.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/README.md
|
||||
-->
|
||||
@@ -0,0 +1,202 @@
|
||||
---
|
||||
name: View Components
|
||||
description: Core container components for layout and structure
|
||||
---
|
||||
|
||||
# View Components
|
||||
|
||||
## view
|
||||
|
||||
Basic container component, similar to HTML `<div>`.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="flex-row">
|
||||
<view class="item">A</view>
|
||||
<view class="item">B</view>
|
||||
</view>
|
||||
<view class="flex-column">
|
||||
<view class="item">C</view>
|
||||
<view class="item">D</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| hover-class | String | none | CSS class when pressed |
|
||||
| hover-stop-propagation | Boolean | false | Stop propagation to ancestor nodes |
|
||||
| hover-start-time | Number | 50 | Delay before hover state (ms) |
|
||||
| hover-stay-time | Number | 400 | Duration to keep hover state (ms) |
|
||||
|
||||
**Tips:**
|
||||
- `<div>` is auto-converted to `<view>` in mini-programs
|
||||
- Use `<text>` to wrap text in nvue pages
|
||||
|
||||
## scroll-view
|
||||
|
||||
Scrollable container with enhanced scroll capabilities.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Vertical scroll -->
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="scroll-container"
|
||||
@scroll="onScroll"
|
||||
@scrolltolower="loadMore"
|
||||
:scroll-top="scrollTop"
|
||||
:scroll-into-view="targetId"
|
||||
>
|
||||
<view id="item1">Item 1</view>
|
||||
<view id="item2">Item 2</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- Horizontal scroll -->
|
||||
<scroll-view scroll-x class="horizontal-scroll">
|
||||
<view class="scroll-item">1</view>
|
||||
<view class="scroll-item">2</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| scroll-x | Boolean | Enable horizontal scroll |
|
||||
| scroll-y | Boolean | Enable vertical scroll |
|
||||
| upper-threshold | Number | Distance from top to trigger scrolltoupper (px) |
|
||||
| lower-threshold | Number | Distance from bottom to trigger scrolltolower (px) |
|
||||
| scroll-top | Number | Vertical scroll position |
|
||||
| scroll-left | Number | Horizontal scroll position |
|
||||
| scroll-into-view | String | Element ID to scroll into view |
|
||||
| scroll-with-animation | Boolean | Enable smooth scroll animation |
|
||||
| enable-back-to-top | Boolean | iOS: tap status bar to scroll top |
|
||||
|
||||
**Events:**
|
||||
- `@scroll` - Scroll event
|
||||
- `@scrolltoupper` - Reached top
|
||||
- `@scrolltolower` - Reached bottom
|
||||
|
||||
## swiper
|
||||
|
||||
Carousel/slider container for switching content.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<swiper
|
||||
:current="currentIndex"
|
||||
:autoplay="true"
|
||||
:interval="3000"
|
||||
:duration="500"
|
||||
:circular="true"
|
||||
:indicator-dots="true"
|
||||
@change="onSwiperChange"
|
||||
>
|
||||
<swiper-item>
|
||||
<view class="slide">Slide 1</view>
|
||||
</swiper-item>
|
||||
<swiper-item>
|
||||
<view class="slide">Slide 2</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSwiperChange(e) {
|
||||
this.currentIndex = e.detail.current
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**swiper Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| indicator-dots | Boolean | false | Show pagination dots |
|
||||
| indicator-color | Color | rgba(0,0,0,.3) | Inactive dot color |
|
||||
| indicator-active-color | Color | #000000 | Active dot color |
|
||||
| autoplay | Boolean | false | Auto-play slides |
|
||||
| current | Number | 0 | Current slide index |
|
||||
| interval | Number | 5000 | Auto-play interval (ms) |
|
||||
| duration | Number | 500 | Transition duration (ms) |
|
||||
| circular | Boolean | false | Circular sliding |
|
||||
| vertical | Boolean | false | Vertical sliding |
|
||||
| previous-margin | String | 0px | Previous slide margin |
|
||||
| next-margin | String | 0px | Next slide margin |
|
||||
|
||||
## movable-area / movable-view
|
||||
|
||||
Draggable and scalable container.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<movable-area class="move-area">
|
||||
<movable-view
|
||||
:x="x"
|
||||
:y="y"
|
||||
direction="all"
|
||||
:scale="true"
|
||||
:scale-min="0.5"
|
||||
:scale-max="4"
|
||||
@change="onChange"
|
||||
@scale="onScale"
|
||||
>
|
||||
Draggable content
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
</template>
|
||||
```
|
||||
|
||||
**movable-view Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| direction | String | none | Move direction: all/vertical/horizontal/none |
|
||||
| x | Number | | Initial X position |
|
||||
| y | Number | | Initial Y position |
|
||||
| scale | Boolean | false | Enable scaling |
|
||||
| scale-min | Number | 0.5 | Min scale |
|
||||
| scale-max | Number | 10 | Max scale |
|
||||
| scale-value | Number | 1 | Initial scale |
|
||||
|
||||
## cover-view / cover-image
|
||||
|
||||
Native overlay components that can cover native components (map, video, canvas).
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<map class="map">
|
||||
<cover-view class="overlay">Overlay text</cover-view>
|
||||
<cover-image class="marker" src="/static/marker.png" />
|
||||
</map>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Limitations:**
|
||||
- Only supported in WeChat MP, App, and H5
|
||||
- Limited styling capabilities
|
||||
- Cannot nest regular components inside
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/view.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/scroll-view.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/swiper.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/movable-area.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/cover-view.md
|
||||
-->
|
||||
@@ -0,0 +1,391 @@
|
||||
---
|
||||
name: File Operations
|
||||
description: File system operations, image/video selection, and file management
|
||||
---
|
||||
|
||||
# File Operations
|
||||
|
||||
## Image Selection
|
||||
|
||||
### uni.chooseImage
|
||||
|
||||
Select images from album or camera.
|
||||
|
||||
```javascript
|
||||
// Select from album
|
||||
uni.chooseImage({
|
||||
count: 9, // Max 9
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album'],
|
||||
success: (res) => {
|
||||
console.log('Selected:', res.tempFilePaths)
|
||||
// tempFilePaths: ['blob:xxx', 'blob:xxx']
|
||||
// tempFiles: [{ path, size }]
|
||||
}
|
||||
})
|
||||
|
||||
// Take photo
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sourceType: ['camera'],
|
||||
success: (res) => {
|
||||
const tempPath = res.tempFilePaths[0]
|
||||
this.uploadImage(tempPath)
|
||||
}
|
||||
})
|
||||
|
||||
// Both album and camera
|
||||
uni.chooseImage({
|
||||
count: 5,
|
||||
sizeType: ['compressed'], // Compressed only
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
res.tempFilePaths.forEach(path => {
|
||||
this.previewImage(path)
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| count | Number | 9 | Max number of images |
|
||||
| sizeType | Array | ['original', 'compressed'] | original/compressed |
|
||||
| sourceType | Array | ['album', 'camera'] | album/camera |
|
||||
|
||||
## Video Selection
|
||||
|
||||
### uni.chooseVideo
|
||||
|
||||
Select or record video.
|
||||
|
||||
```javascript
|
||||
uni.chooseVideo({
|
||||
sourceType: ['album', 'camera'],
|
||||
compressed: true,
|
||||
maxDuration: 60,
|
||||
camera: 'back', // front/back
|
||||
success: (res) => {
|
||||
console.log('Path:', res.tempFilePath)
|
||||
console.log('Duration:', res.duration) // seconds
|
||||
console.log('Size:', res.size) // bytes
|
||||
console.log('Height:', res.height)
|
||||
console.log('Width:', res.width)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.chooseMedia (WeChat/QQ)
|
||||
|
||||
Choose mixed media types.
|
||||
|
||||
```javascript
|
||||
uni.chooseMedia({
|
||||
count: 9,
|
||||
mediaType: ['image', 'video'],
|
||||
sourceType: ['album', 'camera'],
|
||||
maxDuration: 30,
|
||||
camera: 'back',
|
||||
success: (res) => {
|
||||
console.log(res.tempFiles)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## File Selection
|
||||
|
||||
### uni.chooseFile
|
||||
|
||||
Select any file type.
|
||||
|
||||
```javascript
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
type: 'all', // all/video/image/file
|
||||
extension: ['.pdf', '.doc', '.docx'], // Filter by extension
|
||||
success: (res) => {
|
||||
console.log(res.tempFilePaths)
|
||||
console.log(res.tempFiles)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## File System Operations (App)
|
||||
|
||||
### Get File System Manager
|
||||
|
||||
```javascript
|
||||
const fs = uni.getFileSystemManager()
|
||||
```
|
||||
|
||||
### Read File
|
||||
|
||||
```javascript
|
||||
// Read as text
|
||||
fs.readFile({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/data.txt`,
|
||||
encoding: 'utf8',
|
||||
success: (res) => {
|
||||
console.log(res.data)
|
||||
}
|
||||
})
|
||||
|
||||
// Read as binary
|
||||
fs.readFile({
|
||||
filePath: tempFilePath,
|
||||
encoding: 'binary',
|
||||
success: (res) => {
|
||||
console.log(res.data)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Write File
|
||||
|
||||
```javascript
|
||||
fs.writeFile({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/config.json`,
|
||||
data: JSON.stringify({ theme: 'dark' }),
|
||||
encoding: 'utf8',
|
||||
success: () => {
|
||||
console.log('File written')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Append to File
|
||||
|
||||
```javascript
|
||||
fs.appendFile({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/log.txt`,
|
||||
data: '\nNew log entry',
|
||||
encoding: 'utf8',
|
||||
success: () => {
|
||||
console.log('Appended')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Delete File
|
||||
|
||||
```javascript
|
||||
fs.unlink({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/temp.txt`,
|
||||
success: () => {
|
||||
console.log('File deleted')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Check File Exists
|
||||
|
||||
```javascript
|
||||
fs.access({
|
||||
path: `${uni.env.USER_DATA_PATH}/data.json`,
|
||||
success: () => {
|
||||
console.log('File exists')
|
||||
},
|
||||
fail: () => {
|
||||
console.log('File not found')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Create Directory
|
||||
|
||||
```javascript
|
||||
fs.mkdir({
|
||||
dirPath: `${uni.env.USER_DATA_PATH}/downloads`,
|
||||
recursive: true, // Create parent directories
|
||||
success: () => {
|
||||
console.log('Directory created')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Read Directory
|
||||
|
||||
```javascript
|
||||
fs.readdir({
|
||||
dirPath: `${uni.env.USER_DATA_PATH}/downloads`,
|
||||
success: (res) => {
|
||||
console.log('Files:', res.files)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Get File Info
|
||||
|
||||
```javascript
|
||||
fs.getFileInfo({
|
||||
filePath: tempFilePath,
|
||||
success: (res) => {
|
||||
console.log('Size:', res.size)
|
||||
console.log('Create time:', res.createTime)
|
||||
console.log('Last access:', res.lastAccessedTime)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Save and Open Files
|
||||
|
||||
### Save File
|
||||
|
||||
```javascript
|
||||
uni.saveFile({
|
||||
tempFilePath: res.tempFilePath,
|
||||
success: (res) => {
|
||||
const savedPath = res.savedFilePath
|
||||
console.log('Saved to:', savedPath)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Get Saved File List
|
||||
|
||||
```javascript
|
||||
uni.getSavedFileList({
|
||||
success: (res) => {
|
||||
console.log('Files:', res.fileList)
|
||||
// [{ filePath, createTime, size }, ...]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Get Saved File Info
|
||||
|
||||
```javascript
|
||||
uni.getSavedFileInfo({
|
||||
filePath: savedFilePath,
|
||||
success: (res) => {
|
||||
console.log('Size:', res.size)
|
||||
console.log('Create time:', res.createTime)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Remove Saved File
|
||||
|
||||
```javascript
|
||||
uni.removeSavedFile({
|
||||
filePath: savedFilePath,
|
||||
success: () => {
|
||||
console.log('File removed')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Open Document
|
||||
|
||||
```javascript
|
||||
uni.openDocument({
|
||||
filePath: filePath,
|
||||
fileType: 'pdf', // Optional hint
|
||||
showMenu: true, // Show share menu (WeChat)
|
||||
success: () => {
|
||||
console.log('Document opened')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Image Operations
|
||||
|
||||
### Preview Image
|
||||
|
||||
```javascript
|
||||
uni.previewImage({
|
||||
current: currentImage, // Current image URL
|
||||
urls: imageList, // All image URLs
|
||||
indicator: 'default',
|
||||
loop: false,
|
||||
longPressActions: {
|
||||
itemList: ['Save Image', 'Share'],
|
||||
success: (data) => {
|
||||
console.log('Selected:', data.tapIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Get Image Info
|
||||
|
||||
```javascript
|
||||
uni.getImageInfo({
|
||||
src: imagePath,
|
||||
success: (res) => {
|
||||
console.log('Width:', res.width)
|
||||
console.log('Height:', res.height)
|
||||
console.log('Path:', res.path)
|
||||
console.log('Orientation:', res.orientation)
|
||||
console.log('Type:', res.type)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Compress Image
|
||||
|
||||
```javascript
|
||||
uni.compressImage({
|
||||
src: originalPath,
|
||||
quality: 80, // 0-100
|
||||
success: (res) => {
|
||||
console.log('Compressed:', res.tempFilePath)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Save Image to Album
|
||||
|
||||
```javascript
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: tempFilePath,
|
||||
success: () => {
|
||||
uni.showToast({ title: 'Saved to album' })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Video Operations
|
||||
|
||||
### Save Video to Album
|
||||
|
||||
```javascript
|
||||
uni.saveVideoToPhotosAlbum({
|
||||
filePath: videoPath,
|
||||
success: () => {
|
||||
uni.showToast({ title: 'Video saved' })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Get Video Info
|
||||
|
||||
```javascript
|
||||
uni.getVideoInfo({
|
||||
src: videoPath,
|
||||
success: (res) => {
|
||||
console.log('Duration:', res.duration)
|
||||
console.log('Size:', res.size)
|
||||
console.log('Bitrate:', res.bitrate)
|
||||
console.log('FPS:', res.fps)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## File Paths Reference
|
||||
|
||||
| Path Type | Example | Description |
|
||||
|-----------|---------|-------------|
|
||||
| tempFilePath | `blob:xxx` or `_doc/uniapp_temp/xxx` | Temporary file |
|
||||
| savedFilePath | `_doc/uniapp_save/xxx` | Saved file |
|
||||
| USER_DATA_PATH | `_doc/` | App data directory |
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/media/image.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/media/file.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/file/file.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/file/getFileSystemManager.md
|
||||
-->
|
||||
@@ -0,0 +1,423 @@
|
||||
---
|
||||
name: Page Lifecycle
|
||||
description: Page and application lifecycle hooks
|
||||
---
|
||||
|
||||
# Page Lifecycle
|
||||
|
||||
## Application Lifecycle
|
||||
|
||||
In `App.vue`:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
globalData: {
|
||||
userInfo: null,
|
||||
theme: 'light'
|
||||
},
|
||||
|
||||
onLaunch(options) {
|
||||
// App launched (only once)
|
||||
console.log('App launched', options)
|
||||
this.checkUpdate()
|
||||
},
|
||||
|
||||
onShow(options) {
|
||||
// App shown/foreground
|
||||
console.log('App shown', options)
|
||||
},
|
||||
|
||||
onHide() {
|
||||
// App hidden/background
|
||||
console.log('App hidden')
|
||||
},
|
||||
|
||||
onError(msg) {
|
||||
// Global error handler
|
||||
console.error('App error:', msg)
|
||||
},
|
||||
|
||||
onUnhandledRejection(err) {
|
||||
// Unhandled promise rejection
|
||||
console.error('Unhandled rejection:', err)
|
||||
},
|
||||
|
||||
onPageNotFound(res) {
|
||||
// 404 page not found
|
||||
console.error('Page not found:', res.path)
|
||||
uni.redirectTo({
|
||||
url: '/pages/404/404'
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkUpdate() {
|
||||
// Check for app updates
|
||||
const updateManager = uni.getUpdateManager()
|
||||
updateManager.onCheckForUpdate((res) => {
|
||||
if (res.hasUpdate) {
|
||||
console.log('New version available')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Page Lifecycle
|
||||
|
||||
```vue
|
||||
<script>
|
||||
export default {
|
||||
// === Page Load ===
|
||||
onLoad(options) {
|
||||
// Page loaded with query parameters
|
||||
console.log('Page loaded', options)
|
||||
// options contains URL query params
|
||||
// e.g., /pages/detail?id=123 -> options = { id: '123' }
|
||||
this.id = options.id
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
// === Page Show ===
|
||||
onShow() {
|
||||
// Page shown (every time)
|
||||
console.log('Page shown')
|
||||
// Good for refreshing data when returning
|
||||
},
|
||||
|
||||
// === Page Ready ===
|
||||
onReady() {
|
||||
// Page ready, DOM rendered
|
||||
console.log('Page ready')
|
||||
// Safe to access DOM elements
|
||||
this.initChart()
|
||||
},
|
||||
|
||||
// === Page Hide ===
|
||||
onHide() {
|
||||
// Page hidden (navigated away)
|
||||
console.log('Page hidden')
|
||||
// Pause videos, timers, etc.
|
||||
},
|
||||
|
||||
// === Page Unload ===
|
||||
onUnload() {
|
||||
// Page destroyed
|
||||
console.log('Page unloaded')
|
||||
// Clean up resources, remove listeners
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
|
||||
// === Pull Down Refresh ===
|
||||
onPullDownRefresh() {
|
||||
// User pulled down
|
||||
console.log('Pull down refresh')
|
||||
this.refreshData().finally(() => {
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
},
|
||||
|
||||
// === Reach Bottom ===
|
||||
onReachBottom() {
|
||||
// Scrolled to bottom
|
||||
console.log('Reach bottom')
|
||||
this.loadMore()
|
||||
},
|
||||
|
||||
// === Page Scroll ===
|
||||
onPageScroll(e) {
|
||||
// Page scrolled
|
||||
// e.scrollTop: scroll position
|
||||
this.scrollTop = e.scrollTop
|
||||
},
|
||||
|
||||
// === Resize ===
|
||||
onResize(e) {
|
||||
// Page resized (e.g., rotation)
|
||||
console.log('Page resized', e.size)
|
||||
},
|
||||
|
||||
// === Share ===
|
||||
onShareAppMessage(res) {
|
||||
// Native share (MP)
|
||||
if (res.from === 'button') {
|
||||
// From share button
|
||||
console.log(res.target)
|
||||
}
|
||||
return {
|
||||
title: 'Share Title',
|
||||
path: '/pages/index/index',
|
||||
imageUrl: '/static/share.png'
|
||||
}
|
||||
},
|
||||
|
||||
// === Timeline Share ===
|
||||
onShareTimeline() {
|
||||
// Share to timeline (WeChat)
|
||||
return {
|
||||
title: 'Timeline Title',
|
||||
query: 'id=123',
|
||||
imageUrl: '/static/share.png'
|
||||
}
|
||||
},
|
||||
|
||||
// === Add to Favorites ===
|
||||
onAddToFavorites() {
|
||||
// Add to MP favorites
|
||||
return {
|
||||
title: 'Favorite Title',
|
||||
imageUrl: '/static/fav.png',
|
||||
query: 'id=123'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
id: null,
|
||||
scrollTop: 0,
|
||||
timer: null
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadData() {
|
||||
// Load page data
|
||||
},
|
||||
refreshData() {
|
||||
// Refresh data
|
||||
},
|
||||
loadMore() {
|
||||
// Load more data
|
||||
},
|
||||
initChart() {
|
||||
// Initialize chart after DOM ready
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Component Lifecycle (Vue 2)
|
||||
|
||||
```vue
|
||||
<script>
|
||||
export default {
|
||||
// === Creation ===
|
||||
beforeCreate() {
|
||||
// Instance initialized
|
||||
},
|
||||
|
||||
created() {
|
||||
// Instance created, data observed
|
||||
// Good for initial data loading
|
||||
},
|
||||
|
||||
// === Mounting ===
|
||||
beforeMount() {
|
||||
// Before DOM mount
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// DOM mounted
|
||||
// Good for DOM operations
|
||||
},
|
||||
|
||||
// === Updating ===
|
||||
beforeUpdate() {
|
||||
// Before data update
|
||||
},
|
||||
|
||||
updated() {
|
||||
// After data update
|
||||
},
|
||||
|
||||
// === Destruction ===
|
||||
beforeDestroy() {
|
||||
// Before instance destroyed
|
||||
// Clean up here
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
// Instance destroyed
|
||||
},
|
||||
|
||||
// === Keep-alive ===
|
||||
activated() {
|
||||
// Component activated (kept-alive)
|
||||
},
|
||||
|
||||
deactivated() {
|
||||
// Component deactivated (kept-alive)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Component Lifecycle (Vue 3)
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import {
|
||||
onBeforeMount,
|
||||
onMounted,
|
||||
onBeforeUpdate,
|
||||
onUpdated,
|
||||
onBeforeUnmount,
|
||||
onUnmounted,
|
||||
onActivated,
|
||||
onDeactivated
|
||||
} from 'vue'
|
||||
|
||||
// Setup runs before beforeCreate
|
||||
console.log('setup')
|
||||
|
||||
onBeforeMount(() => {
|
||||
console.log('onBeforeMount')
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
console.log('onMounted')
|
||||
})
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
console.log('onBeforeUpdate')
|
||||
})
|
||||
|
||||
onUpdated(() => {
|
||||
console.log('onUpdated')
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
console.log('onBeforeUnmount')
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
console.log('onUnmounted')
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
console.log('onActivated')
|
||||
})
|
||||
|
||||
onDeactivated(() => {
|
||||
console.log('onDeactivated')
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## Lifecycle Comparison
|
||||
|
||||
| Scenario | UniApp Page | Vue Component |
|
||||
|----------|-------------|---------------|
|
||||
| Initial load | onLoad | created |
|
||||
| DOM ready | onReady | mounted |
|
||||
| Page show | onShow | - |
|
||||
| Page hide | onHide | - |
|
||||
| Page destroy | onUnload | destroyed/unmounted |
|
||||
| Data refresh | onPullDownRefresh | - |
|
||||
| Infinite scroll | onReachBottom | - |
|
||||
| Scroll position | onPageScroll | - |
|
||||
|
||||
## App Update Manager
|
||||
|
||||
```javascript
|
||||
// In App.vue onLaunch
|
||||
onLaunch() {
|
||||
const updateManager = uni.getUpdateManager()
|
||||
|
||||
updateManager.onCheckForUpdate((res) => {
|
||||
console.log('Has update:', res.hasUpdate)
|
||||
})
|
||||
|
||||
updateManager.onUpdateReady(() => {
|
||||
uni.showModal({
|
||||
title: 'Update Ready',
|
||||
content: 'New version downloaded. Restart to apply?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
updateManager.applyUpdate()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
updateManager.onUpdateFailed(() => {
|
||||
console.error('Update failed')
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Data Loading Pattern
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
error: null,
|
||||
data: null
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.fetchData(options.id)
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.fetchData(this.id).finally(() => {
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchData(id) {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
try {
|
||||
this.data = await api.getDetail(id)
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scroll Performance
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollTop: 0,
|
||||
showBackTop: false
|
||||
}
|
||||
},
|
||||
|
||||
// Throttle scroll events
|
||||
onPageScroll: throttle(function(e) {
|
||||
this.scrollTop = e.scrollTop
|
||||
this.showBackTop = e.scrollTop > 500
|
||||
}, 200),
|
||||
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
uni.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/collocation/App.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/lifecycle.md
|
||||
-->
|
||||
@@ -0,0 +1,417 @@
|
||||
---
|
||||
name: Location Services
|
||||
description: Geolocation, map operations, and location-based services
|
||||
---
|
||||
|
||||
# Location Services
|
||||
|
||||
## Get Current Location
|
||||
|
||||
### uni.getLocation
|
||||
|
||||
Get current geographic location.
|
||||
|
||||
```javascript
|
||||
uni.getLocation({
|
||||
type: 'wgs84', // wgs84/gcj02 (gcj02 for map display)
|
||||
altitude: false, // Include altitude
|
||||
geocode: false, // Include address info (App)
|
||||
highAccuracyExpireTime: 3000, // High accuracy timeout
|
||||
success: (res) => {
|
||||
console.log('Latitude:', res.latitude)
|
||||
console.log('Longitude:', res.longitude)
|
||||
console.log('Speed:', res.speed)
|
||||
console.log('Accuracy:', res.accuracy)
|
||||
// App only:
|
||||
console.log('Altitude:', res.altitude)
|
||||
console.log('Address:', res.address)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('Location failed:', err)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Response Properties:**
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| latitude | Number | Latitude |
|
||||
| longitude | Number | Longitude |
|
||||
| speed | Number | Speed (m/s) |
|
||||
| accuracy | Number | Accuracy (meters) |
|
||||
| altitude | Number | Altitude (meters) |
|
||||
| verticalAccuracy | Number | Vertical accuracy |
|
||||
| horizontalAccuracy | Number | Horizontal accuracy |
|
||||
| address | Object | Address info (App) |
|
||||
|
||||
### uni.getFuzzyLocation (WeChat)
|
||||
|
||||
Get approximate location (better privacy, faster).
|
||||
|
||||
```javascript
|
||||
uni.getFuzzyLocation({
|
||||
type: 'wgs84',
|
||||
success: (res) => {
|
||||
console.log(res.latitude, res.longitude)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Choose Location
|
||||
|
||||
### uni.chooseLocation
|
||||
|
||||
Open map to select location.
|
||||
|
||||
```javascript
|
||||
uni.chooseLocation({
|
||||
latitude: 39.9,
|
||||
longitude: 116.4,
|
||||
keyword: 'restaurant',
|
||||
success: (res) => {
|
||||
console.log('Name:', res.name)
|
||||
console.log('Address:', res.address)
|
||||
console.log('Latitude:', res.latitude)
|
||||
console.log('Longitude:', res.longitude)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Open Location
|
||||
|
||||
### uni.openLocation
|
||||
|
||||
Open external map app.
|
||||
|
||||
```javascript
|
||||
uni.openLocation({
|
||||
latitude: 39.9,
|
||||
longitude: 116.4,
|
||||
name: 'Destination Name',
|
||||
address: 'Full address here',
|
||||
scale: 18
|
||||
})
|
||||
```
|
||||
|
||||
## Location Change Monitoring
|
||||
|
||||
### uni.startLocationUpdate
|
||||
|
||||
Start background location updates.
|
||||
|
||||
```javascript
|
||||
uni.startLocationUpdate({
|
||||
type: 'gcj02',
|
||||
success: () => {
|
||||
console.log('Location updates started')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.startLocationUpdateBackground
|
||||
|
||||
Start background location (requires permission).
|
||||
|
||||
```javascript
|
||||
uni.startLocationUpdateBackground({
|
||||
type: 'gcj02',
|
||||
success: () => {
|
||||
console.log('Background location started')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Listen for Location Changes
|
||||
|
||||
```javascript
|
||||
uni.onLocationChange((res) => {
|
||||
console.log('Location updated:', res.latitude, res.longitude)
|
||||
})
|
||||
|
||||
// Stop listening
|
||||
uni.offLocationChange(callback)
|
||||
```
|
||||
|
||||
### Stop Location Updates
|
||||
|
||||
```javascript
|
||||
uni.stopLocationUpdate({
|
||||
success: () => {
|
||||
console.log('Location updates stopped')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Map Component
|
||||
|
||||
### Basic Map
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<map
|
||||
id="myMap"
|
||||
style="width: 100%; height: 300px;"
|
||||
:latitude="latitude"
|
||||
:longitude="longitude"
|
||||
:scale="14"
|
||||
:markers="markers"
|
||||
:polyline="polyline"
|
||||
:circles="circles"
|
||||
:show-location="true"
|
||||
@markertap="onMarkerTap"
|
||||
@regionchange="onRegionChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
latitude: 39.909,
|
||||
longitude: 116.39742,
|
||||
markers: [{
|
||||
id: 1,
|
||||
latitude: 39.909,
|
||||
longitude: 116.39742,
|
||||
title: 'Marker 1',
|
||||
iconPath: '/static/marker.png',
|
||||
width: 30,
|
||||
height: 30,
|
||||
callout: {
|
||||
content: 'Hello',
|
||||
color: '#000',
|
||||
fontSize: 14,
|
||||
borderRadius: 5,
|
||||
padding: 10,
|
||||
display: 'BYCLICK'
|
||||
}
|
||||
}],
|
||||
polyline: [{
|
||||
points: [
|
||||
{ latitude: 39.909, longitude: 116.39742 },
|
||||
{ latitude: 39.91, longitude: 116.4 }
|
||||
],
|
||||
color: '#FF0000',
|
||||
width: 2,
|
||||
dottedLine: false
|
||||
}],
|
||||
circles: [{
|
||||
latitude: 39.909,
|
||||
longitude: 116.39742,
|
||||
radius: 100,
|
||||
strokeWidth: 2,
|
||||
fillColor: '#FF000020'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Map Context Operations
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
onReady() {
|
||||
this.mapContext = uni.createMapContext('myMap')
|
||||
},
|
||||
|
||||
methods: {
|
||||
// Get center location
|
||||
getCenter() {
|
||||
this.mapContext.getCenterLocation({
|
||||
success: (res) => {
|
||||
console.log('Center:', res.latitude, res.longitude)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// Move to location
|
||||
moveToLocation() {
|
||||
this.mapContext.moveToLocation({
|
||||
latitude: 39.9,
|
||||
longitude: 116.4
|
||||
})
|
||||
},
|
||||
|
||||
// Translate marker
|
||||
translateMarker() {
|
||||
this.mapContext.translateMarker({
|
||||
markerId: 1,
|
||||
destination: {
|
||||
latitude: 39.91,
|
||||
longitude: 116.41
|
||||
},
|
||||
autoRotate: true,
|
||||
rotate: 0,
|
||||
duration: 1000
|
||||
})
|
||||
},
|
||||
|
||||
// Include points in view
|
||||
includePoints() {
|
||||
this.mapContext.includePoints({
|
||||
points: [
|
||||
{ latitude: 39.9, longitude: 116.4 },
|
||||
{ latitude: 39.91, longitude: 116.41 }
|
||||
],
|
||||
padding: [10, 10, 10, 10]
|
||||
})
|
||||
},
|
||||
|
||||
// Get region
|
||||
getRegion() {
|
||||
this.mapContext.getRegion({
|
||||
success: (res) => {
|
||||
console.log('Southwest:', res.southwest)
|
||||
console.log('Northeast:', res.northeast)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// Add markers
|
||||
addMarkers() {
|
||||
this.mapContext.addMarkers({
|
||||
markers: [{
|
||||
id: 2,
|
||||
latitude: 39.91,
|
||||
longitude: 116.41,
|
||||
title: 'New Marker'
|
||||
}],
|
||||
clear: false // Don't clear existing
|
||||
})
|
||||
},
|
||||
|
||||
// Remove markers
|
||||
removeMarkers() {
|
||||
this.mapContext.removeMarkers({
|
||||
markerIds: [1, 2]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Coordinate Systems
|
||||
|
||||
| System | Description | Usage |
|
||||
|--------|-------------|-------|
|
||||
| WGS84 | GPS coordinates | International standard |
|
||||
| GCJ02 | Mars coordinates | China national standard |
|
||||
| BD09 | Baidu coordinates | Baidu Map only |
|
||||
|
||||
**Note:** For map display in China, use `gcj02`.
|
||||
|
||||
## Permission Configuration
|
||||
|
||||
### Mini-Program
|
||||
|
||||
Add to `manifest.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mp-weixin": {
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "Your location is needed to find nearby stores"
|
||||
}
|
||||
},
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation",
|
||||
"chooseLocation"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### App (Android)
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### App (iOS)
|
||||
|
||||
```json
|
||||
{
|
||||
"app-plus": {
|
||||
"distribute": {
|
||||
"ios": {
|
||||
"privacyDescription": {
|
||||
"NSLocationWhenInUseUsageDescription": "Location is needed to find nearby stores",
|
||||
"NSLocationAlwaysUsageDescription": "Background location is needed for navigation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Permission Handling
|
||||
|
||||
```javascript
|
||||
async function getLocationWithPermission() {
|
||||
try {
|
||||
// Check permission
|
||||
const setting = await uni.getSetting()
|
||||
if (!setting.authSetting['scope.userLocation']) {
|
||||
// Request permission
|
||||
await uni.authorize({ scope: 'scope.userLocation' })
|
||||
}
|
||||
|
||||
// Get location
|
||||
const res = await uni.getLocation({ type: 'gcj02' })
|
||||
return res
|
||||
} catch (err) {
|
||||
if (err.errMsg.includes('auth deny')) {
|
||||
uni.showModal({
|
||||
title: 'Permission Required',
|
||||
content: 'Please enable location permission in settings',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.openSetting()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Distance Calculation
|
||||
|
||||
```javascript
|
||||
function calculateDistance(lat1, lon1, lat2, lon2) {
|
||||
const R = 6371 // Earth's radius in km
|
||||
const dLat = (lat2 - lat1) * Math.PI / 180
|
||||
const dLon = (lon2 - lon1) * Math.PI / 180
|
||||
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
||||
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
||||
Math.sin(dLon/2) * Math.sin(dLon/2)
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
|
||||
return R * c // Distance in km
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/location/location.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/location/location-change.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/location/open-location.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/map.md
|
||||
-->
|
||||
@@ -0,0 +1,314 @@
|
||||
---
|
||||
name: Media Components
|
||||
description: Image, video, audio, and camera components
|
||||
---
|
||||
|
||||
# Media Components
|
||||
|
||||
## image
|
||||
|
||||
Display images with various mode options.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Basic usage -->
|
||||
<image src="/static/logo.png" mode="aspectFit" />
|
||||
|
||||
<!-- With event handling -->
|
||||
<image
|
||||
:src="imageUrl"
|
||||
mode="aspectFill"
|
||||
:lazy-load="true"
|
||||
:show-menu-by-longpress="true"
|
||||
@load="onImageLoad"
|
||||
@error="onImageError"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| src | String | | Image source URL |
|
||||
| mode | String | scaleToFill | Display mode (see below) |
|
||||
| lazy-load | Boolean | false | Lazy load image |
|
||||
| show-menu-by-longpress | Boolean | false | Show menu on long press |
|
||||
| webp | Boolean | false | Parse WebP format (Android) |
|
||||
|
||||
**Mode Values:**
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| scaleToFill | Fill container, may distort |
|
||||
| aspectFit | Contain within container |
|
||||
| aspectFill | Cover container, may clip |
|
||||
| widthFix | Width fixed, height auto |
|
||||
| heightFix | Height fixed, width auto |
|
||||
| top / bottom / center / left / right | Align to position |
|
||||
| top left / top right / bottom left / bottom right | Corner alignment |
|
||||
|
||||
**Events:**
|
||||
- `@load` - Image loaded successfully
|
||||
- `@error` - Image failed to load
|
||||
|
||||
## video
|
||||
|
||||
Video player component.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<video
|
||||
id="myVideo"
|
||||
src="https://example.com/video.mp4"
|
||||
:controls="true"
|
||||
:autoplay="false"
|
||||
:loop="false"
|
||||
:muted="false"
|
||||
initial-time="30"
|
||||
:duration="300"
|
||||
poster="/static/poster.jpg"
|
||||
object-fit="contain"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@ended="onEnded"
|
||||
@timeupdate="onTimeUpdate"
|
||||
@fullscreenchange="onFullscreenChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onReady() {
|
||||
this.videoContext = uni.createVideoContext('myVideo')
|
||||
},
|
||||
methods: {
|
||||
play() {
|
||||
this.videoContext.play()
|
||||
},
|
||||
pause() {
|
||||
this.videoContext.pause()
|
||||
},
|
||||
seek(time) {
|
||||
this.videoContext.seek(time)
|
||||
},
|
||||
sendDanmu(danmu) {
|
||||
this.videoContext.sendDanmu({
|
||||
text: danmu.text,
|
||||
color: danmu.color
|
||||
})
|
||||
},
|
||||
playbackRate(rate) {
|
||||
this.videoContext.playbackRate(rate)
|
||||
},
|
||||
onFullscreenChange(e) {
|
||||
console.log('Fullscreen:', e.detail.fullScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| src | String | | Video source URL |
|
||||
| controls | Boolean | true | Show controls |
|
||||
| autoplay | Boolean | false | Auto play |
|
||||
| loop | Boolean | false | Loop playback |
|
||||
| muted | Boolean | false | Muted |
|
||||
| initial-time | Number | 0 | Start time (s) |
|
||||
| duration | Number | | Total duration (s) |
|
||||
| poster | String | | Poster image URL |
|
||||
| object-fit | String | contain | contain/cover/fill |
|
||||
| danmu-list | Array | | Danmu list |
|
||||
| danmu-btn | Boolean | false | Show danmu button |
|
||||
| enable-danmu | Boolean | false | Enable danmu |
|
||||
| show-center-play-btn | Boolean | true | Show center play button |
|
||||
| show-play-btn | Boolean | true | Show play button |
|
||||
| show-fullscreen-btn | Boolean | true | Show fullscreen button |
|
||||
| page-gesture | Boolean | false | Enable page gesture |
|
||||
| enable-progress-gesture | Boolean | true | Enable progress gesture |
|
||||
|
||||
## audio
|
||||
|
||||
Audio player (deprecated, use `uni.getBackgroundAudioManager` instead).
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<audio
|
||||
:src="audioSrc"
|
||||
:poster="posterUrl"
|
||||
:name="audioName"
|
||||
:author="author"
|
||||
:controls="true"
|
||||
:loop="false"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@ended="onEnded"
|
||||
@timeupdate="onTimeUpdate"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
## camera
|
||||
|
||||
Camera component for capturing photos/videos.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<camera
|
||||
device-position="back"
|
||||
flash="auto"
|
||||
resolution="high"
|
||||
frame-size="large"
|
||||
@stop="onCameraStop"
|
||||
@error="onCameraError"
|
||||
@initdone="onCameraReady"
|
||||
/>
|
||||
<button @click="takePhoto">Take Photo</button>
|
||||
<button @click="startRecord">Start Record</button>
|
||||
<button @click="stopRecord">Stop Record</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onReady() {
|
||||
this.cameraContext = uni.createCameraContext()
|
||||
},
|
||||
methods: {
|
||||
takePhoto() {
|
||||
this.cameraContext.takePhoto({
|
||||
quality: 'high',
|
||||
success: (res) => {
|
||||
console.log(res.tempImagePath)
|
||||
}
|
||||
})
|
||||
},
|
||||
startRecord() {
|
||||
this.cameraContext.startRecord({
|
||||
success: () => console.log('Recording started')
|
||||
})
|
||||
},
|
||||
stopRecord() {
|
||||
this.cameraContext.stopRecord({
|
||||
success: (res) => {
|
||||
console.log(res.tempVideoPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| mode | String | normal | normal/scanCode |
|
||||
| resolution | String | medium | low/medium/high |
|
||||
| device-position | String | back | front/back |
|
||||
| flash | String | auto | auto/on/off |
|
||||
| frame-size | String | large | small/medium/large |
|
||||
|
||||
## live-player / live-pusher
|
||||
|
||||
Live streaming components (mini-program only).
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Live player -->
|
||||
<live-player
|
||||
src="rtmp://example.com/live/stream"
|
||||
mode="live"
|
||||
:autoplay="true"
|
||||
:muted="false"
|
||||
orientation="vertical"
|
||||
object-fit="contain"
|
||||
@statechange="onStateChange"
|
||||
@error="onError"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
## map
|
||||
|
||||
Map component for displaying maps and markers.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<map
|
||||
id="myMap"
|
||||
style="width: 100%; height: 300px;"
|
||||
:latitude="latitude"
|
||||
:longitude="longitude"
|
||||
:scale="14"
|
||||
:markers="markers"
|
||||
:polyline="polyline"
|
||||
:circles="circles"
|
||||
:controls="controls"
|
||||
:show-location="true"
|
||||
@markertap="onMarkerTap"
|
||||
@regionchange="onRegionChange"
|
||||
@tap="onMapTap"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
latitude: 39.909,
|
||||
longitude: 116.39742,
|
||||
markers: [{
|
||||
id: 1,
|
||||
latitude: 39.909,
|
||||
longitude: 116.39742,
|
||||
title: 'Marker 1',
|
||||
iconPath: '/static/marker.png',
|
||||
width: 30,
|
||||
height: 30
|
||||
}],
|
||||
polyline: [{
|
||||
points: [
|
||||
{ latitude: 39.909, longitude: 116.39742 },
|
||||
{ latitude: 39.91, longitude: 116.4 }
|
||||
],
|
||||
color: '#FF0000',
|
||||
width: 2
|
||||
}]
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.mapContext = uni.createMapContext('myMap')
|
||||
},
|
||||
methods: {
|
||||
moveToLocation() {
|
||||
this.mapContext.moveToLocation({
|
||||
latitude: 39.91,
|
||||
longitude: 116.4
|
||||
})
|
||||
},
|
||||
getCenterLocation() {
|
||||
this.mapContext.getCenterLocation({
|
||||
success: (res) => {
|
||||
console.log(res.latitude, res.longitude)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/image.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/video.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/audio.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/camera.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/live-player.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/map.md
|
||||
-->
|
||||
@@ -0,0 +1,257 @@
|
||||
---
|
||||
name: Navigation
|
||||
description: Navigation, routing, and page navigation components
|
||||
---
|
||||
|
||||
# Navigation
|
||||
|
||||
## navigator
|
||||
|
||||
Page navigation component.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Basic navigation -->
|
||||
<navigator url="/pages/detail/detail" hover-class="navigator-hover">
|
||||
Go to Detail
|
||||
</navigator>
|
||||
|
||||
<!-- Open in new page -->
|
||||
<navigator url="/pages/detail/detail" open-type="navigate">
|
||||
Navigate (default)
|
||||
</navigator>
|
||||
|
||||
<!-- Redirect (no back button) -->
|
||||
<navigator url="/pages/login/login" open-type="redirect">
|
||||
Login (redirect)
|
||||
</navigator>
|
||||
|
||||
<!-- Switch to tab page -->
|
||||
<navigator url="/pages/index/index" open-type="switchTab">
|
||||
Go to Home
|
||||
</navigator>
|
||||
|
||||
<!-- Re-launch app -->
|
||||
<navigator url="/pages/start/start" open-type="reLaunch">
|
||||
Restart
|
||||
</navigator>
|
||||
|
||||
<!-- Navigate back -->
|
||||
<navigator open-type="navigateBack" :delta="1">
|
||||
Go Back
|
||||
</navigator>
|
||||
|
||||
<!-- Exit app (mini-program) -->
|
||||
<navigator open-type="exit" target="miniProgram">
|
||||
Exit
|
||||
</navigator>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| url | String | | Target page path |
|
||||
| open-type | String | navigate | navigate/redirect/switchTab/reLaunch/navigateBack/exit |
|
||||
| delta | Number | 1 | Back level when open-type is navigateBack |
|
||||
| hover-class | String | navigator-hover | Hover state class |
|
||||
| hover-stop-propagation | Boolean | false | Stop hover propagation |
|
||||
| target | String | self | self/miniProgram (mini-program only) |
|
||||
|
||||
## Programmatic Navigation
|
||||
|
||||
### uni.navigateTo
|
||||
|
||||
Navigate to new page.
|
||||
|
||||
```javascript
|
||||
// Basic navigation
|
||||
uni.navigateTo({
|
||||
url: '/pages/detail/detail'
|
||||
})
|
||||
|
||||
// With query parameters
|
||||
uni.navigateTo({
|
||||
url: '/pages/detail/detail?id=123&name=test'
|
||||
})
|
||||
|
||||
// With events (Vue 2 only)
|
||||
uni.navigateTo({
|
||||
url: '/pages/detail/detail',
|
||||
events: {
|
||||
acceptDataFromOpenedPage(data) {
|
||||
console.log(data)
|
||||
}
|
||||
},
|
||||
success(res) {
|
||||
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.redirectTo
|
||||
|
||||
Redirect to new page (closes current page).
|
||||
|
||||
```javascript
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
```
|
||||
|
||||
### uni.reLaunch
|
||||
|
||||
Re-launch application to specified page.
|
||||
|
||||
```javascript
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
```
|
||||
|
||||
### uni.switchTab
|
||||
|
||||
Switch to tab bar page.
|
||||
|
||||
```javascript
|
||||
uni.switchTab({
|
||||
url: '/pages/home/home'
|
||||
})
|
||||
```
|
||||
|
||||
### uni.navigateBack
|
||||
|
||||
Navigate back to previous page.
|
||||
|
||||
```javascript
|
||||
// Go back one page
|
||||
uni.navigateBack()
|
||||
|
||||
// Go back multiple pages
|
||||
uni.navigateBack({
|
||||
delta: 2
|
||||
})
|
||||
|
||||
// With animation (App only)
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
animationType: 'pop-out',
|
||||
animationDuration: 300
|
||||
})
|
||||
```
|
||||
|
||||
### uni.preloadPage
|
||||
|
||||
Preload page for faster navigation (App only).
|
||||
|
||||
```javascript
|
||||
uni.preloadPage({
|
||||
url: '/pages/detail/detail'
|
||||
})
|
||||
```
|
||||
|
||||
## Getting Page Information
|
||||
|
||||
### getCurrentPages
|
||||
|
||||
Get current page stack.
|
||||
|
||||
```javascript
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
console.log(currentPage.route) // Current page path
|
||||
```
|
||||
|
||||
### getApp
|
||||
|
||||
Get app instance.
|
||||
|
||||
```javascript
|
||||
const app = getApp()
|
||||
console.log(app.globalData)
|
||||
```
|
||||
|
||||
## Page Event Channel (Vue 2)
|
||||
|
||||
Communicate between pages using event channel.
|
||||
|
||||
```javascript
|
||||
// Page A: Open page B
|
||||
uni.navigateTo({
|
||||
url: '/pages/pageB/pageB',
|
||||
success(res) {
|
||||
// Listen for events from page B
|
||||
res.eventChannel.on('acceptDataFromPageB', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
// Send data to page B
|
||||
res.eventChannel.emit('acceptDataFromPageA', { data: 'hello' })
|
||||
}
|
||||
})
|
||||
|
||||
// Page B: Receive and send data
|
||||
export default {
|
||||
onLoad() {
|
||||
const eventChannel = this.getOpenerEventChannel()
|
||||
// Listen for events from page A
|
||||
eventChannel.on('acceptDataFromPageA', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
// Send data back to page A
|
||||
eventChannel.emit('acceptDataFromPageB', { data: 'world' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation Bar
|
||||
|
||||
### Custom Navigation Bar
|
||||
|
||||
Configure in `pages.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### uni.setNavigationBarTitle
|
||||
|
||||
```javascript
|
||||
uni.setNavigationBarTitle({
|
||||
title: 'New Title'
|
||||
})
|
||||
```
|
||||
|
||||
### uni.setNavigationBarColor
|
||||
|
||||
```javascript
|
||||
uni.setNavigationBarColor({
|
||||
frontColor: '#ffffff',
|
||||
backgroundColor: '#000000',
|
||||
animation: {
|
||||
duration: 400,
|
||||
timingFunc: 'easeIn'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.showNavigationBarLoading
|
||||
|
||||
```javascript
|
||||
uni.showNavigationBarLoading()
|
||||
// ...loading operation
|
||||
uni.hideNavigationBarLoading()
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/component/navigator.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/router.md
|
||||
-->
|
||||
@@ -0,0 +1,345 @@
|
||||
---
|
||||
name: Network Requests
|
||||
description: HTTP requests, file upload/download, and WebSocket
|
||||
---
|
||||
|
||||
# Network Requests
|
||||
|
||||
## uni.request
|
||||
|
||||
Make HTTP requests to backend APIs.
|
||||
|
||||
```javascript
|
||||
// GET request
|
||||
uni.request({
|
||||
url: 'https://api.example.com/data',
|
||||
method: 'GET',
|
||||
data: { id: 123 },
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer token'
|
||||
},
|
||||
timeout: 30000,
|
||||
success: (res) => {
|
||||
console.log(res.data)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(err)
|
||||
},
|
||||
complete: () => {
|
||||
console.log('Request complete')
|
||||
}
|
||||
})
|
||||
|
||||
// POST request with JSON
|
||||
uni.request({
|
||||
url: 'https://api.example.com/submit',
|
||||
method: 'POST',
|
||||
data: {
|
||||
name: 'John',
|
||||
age: 30
|
||||
},
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
console.log('Success:', res.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Using Promise
|
||||
uni.request({
|
||||
url: 'https://api.example.com/data',
|
||||
method: 'GET'
|
||||
}).then(res => {
|
||||
console.log(res.data)
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
// Async/await
|
||||
async function fetchData() {
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: 'https://api.example.com/data'
|
||||
})
|
||||
return res.data
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| url | String | Yes | Request URL |
|
||||
| data | Object/String/Array/ArrayBuffer | No | Request data |
|
||||
| header | Object | No | Request headers |
|
||||
| method | String | No | HTTP method (default: GET) |
|
||||
| timeout | Number | No | Timeout in ms (default: 60000) |
|
||||
| dataType | String | No | Response data type (default: json) |
|
||||
| responseType | String | No | Response type (default: text) |
|
||||
| sslVerify | Boolean | No | Verify SSL certificate (default: true) |
|
||||
|
||||
**Response Object:**
|
||||
|
||||
```javascript
|
||||
{
|
||||
data: Object | String | ArrayBuffer, // Response data
|
||||
statusCode: Number, // HTTP status code
|
||||
header: Object, // Response headers
|
||||
cookies: Array // Response cookies
|
||||
}
|
||||
```
|
||||
|
||||
## uni.uploadFile
|
||||
|
||||
Upload files to server.
|
||||
|
||||
```javascript
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (chooseRes) => {
|
||||
const tempFilePath = chooseRes.tempFilePaths[0]
|
||||
|
||||
const uploadTask = uni.uploadFile({
|
||||
url: 'https://api.example.com/upload',
|
||||
filePath: tempFilePath,
|
||||
name: 'file',
|
||||
formData: {
|
||||
user: 'test',
|
||||
description: 'Image upload'
|
||||
},
|
||||
header: {
|
||||
'Authorization': 'Bearer token'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('Upload success:', JSON.parse(res.data))
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('Upload failed:', err)
|
||||
}
|
||||
})
|
||||
|
||||
// Track upload progress
|
||||
uploadTask.onProgressUpdate((res) => {
|
||||
console.log('Progress:', res.progress)
|
||||
console.log('Uploaded bytes:', res.totalBytesSent)
|
||||
console.log('Total bytes:', res.totalBytesExpectedToSend)
|
||||
})
|
||||
|
||||
// Abort upload if needed
|
||||
// uploadTask.abort()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Upload Task Methods:**
|
||||
- `onProgressUpdate(callback)` - Listen for progress updates
|
||||
- `abort()` - Cancel the upload
|
||||
- `offProgressUpdate(callback)` - Remove progress listener
|
||||
|
||||
## uni.downloadFile
|
||||
|
||||
Download files from server.
|
||||
|
||||
```javascript
|
||||
const downloadTask = uni.downloadFile({
|
||||
url: 'https://example.com/file.pdf',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
console.log('Downloaded to:', res.tempFilePath)
|
||||
|
||||
// Save to local (App only)
|
||||
uni.saveFile({
|
||||
tempFilePath: res.tempFilePath,
|
||||
success: (saveRes) => {
|
||||
console.log('Saved to:', saveRes.savedFilePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Track download progress
|
||||
downloadTask.onProgressUpdate((res) => {
|
||||
console.log('Progress:', res.progress)
|
||||
})
|
||||
```
|
||||
|
||||
## WebSocket
|
||||
|
||||
Real-time bidirectional communication.
|
||||
|
||||
```javascript
|
||||
// Connect to WebSocket
|
||||
const socketTask = uni.connectSocket({
|
||||
url: 'wss://api.example.com/ws',
|
||||
protocols: ['protocol1'],
|
||||
header: {
|
||||
'Authorization': 'Bearer token'
|
||||
},
|
||||
success: () => {
|
||||
console.log('WebSocket connecting...')
|
||||
}
|
||||
})
|
||||
|
||||
// Listen for connection open
|
||||
uni.onSocketOpen((res) => {
|
||||
console.log('WebSocket connected')
|
||||
|
||||
// Send message
|
||||
uni.sendSocketMessage({
|
||||
data: JSON.stringify({
|
||||
type: 'message',
|
||||
content: 'Hello server'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Listen for messages
|
||||
uni.onSocketMessage((res) => {
|
||||
console.log('Received:', res.data)
|
||||
const data = JSON.parse(res.data)
|
||||
// Handle message...
|
||||
})
|
||||
|
||||
// Listen for errors
|
||||
uni.onSocketError((err) => {
|
||||
console.error('WebSocket error:', err)
|
||||
})
|
||||
|
||||
// Listen for close
|
||||
uni.onSocketClose((res) => {
|
||||
console.log('WebSocket closed:', res)
|
||||
})
|
||||
|
||||
// Close connection
|
||||
function closeSocket() {
|
||||
uni.closeSocket({
|
||||
code: 1000,
|
||||
reason: 'User logout',
|
||||
success: () => {
|
||||
console.log('Socket closed successfully')
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Socket Task Methods:**
|
||||
- `close(options)` - Close connection
|
||||
- `send(options)` - Send message
|
||||
- `onOpen(callback)` - Connection opened
|
||||
- `onMessage(callback)` - Message received
|
||||
- `onClose(callback)` - Connection closed
|
||||
- `onError(callback)` - Error occurred
|
||||
|
||||
## Request Interceptors
|
||||
|
||||
Use `uni.addInterceptor` to intercept requests.
|
||||
|
||||
```javascript
|
||||
// Add request interceptor
|
||||
uni.addInterceptor('request', {
|
||||
invoke(args) {
|
||||
// Before request
|
||||
console.log('Request:', args)
|
||||
|
||||
// Add auth token
|
||||
args.header = args.header || {}
|
||||
args.header.Authorization = `Bearer ${getToken()}`
|
||||
|
||||
return args
|
||||
},
|
||||
success(res) {
|
||||
// After success
|
||||
console.log('Response:', res)
|
||||
return res
|
||||
},
|
||||
fail(err) {
|
||||
// After failure
|
||||
console.error('Request failed:', err)
|
||||
return err
|
||||
},
|
||||
complete(res) {
|
||||
// Always executed
|
||||
console.log('Request complete')
|
||||
}
|
||||
})
|
||||
|
||||
// Remove interceptor
|
||||
uni.removeInterceptor('request')
|
||||
```
|
||||
|
||||
## Domain Configuration
|
||||
|
||||
### Mini-Program
|
||||
|
||||
Configure request domains in mini-program developer console:
|
||||
- `request` domain: For `uni.request`
|
||||
- `uploadFile` domain: For `uni.uploadFile`
|
||||
- `downloadFile` domain: For `uni.downloadFile`
|
||||
- `websocket` domain: For `uni.connectSocket`
|
||||
|
||||
### H5
|
||||
|
||||
H5 uses browser's same-origin policy. Configure CORS on server or use proxy in development.
|
||||
|
||||
```javascript
|
||||
// vite.config.js proxy configuration
|
||||
export default {
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'https://api.example.com',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
```javascript
|
||||
// Create a request wrapper
|
||||
const request = (options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
...options,
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data)
|
||||
} else if (res.statusCode === 401) {
|
||||
// Handle unauthorized
|
||||
uni.redirectTo({ url: '/pages/login/login' })
|
||||
reject(new Error('Unauthorized'))
|
||||
} else {
|
||||
reject(new Error(res.data.message || 'Request failed'))
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Usage
|
||||
const api = {
|
||||
getUser: () => request({ url: '/user' }),
|
||||
updateUser: (data) => request({ url: '/user', method: 'PUT', data })
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/request/request.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/request/network-file.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/request/websocket.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/interceptor.md
|
||||
-->
|
||||
@@ -0,0 +1,279 @@
|
||||
---
|
||||
name: Storage
|
||||
description: Local data storage and caching APIs
|
||||
---
|
||||
|
||||
# Storage
|
||||
|
||||
## Synchronous Storage (Recommended for small data)
|
||||
|
||||
### uni.setStorageSync
|
||||
|
||||
Store data synchronously.
|
||||
|
||||
```javascript
|
||||
// Store simple value
|
||||
uni.setStorageSync('username', 'John')
|
||||
|
||||
// Store object
|
||||
uni.setStorageSync('userInfo', {
|
||||
name: 'John',
|
||||
age: 30,
|
||||
email: 'john@example.com'
|
||||
})
|
||||
|
||||
// Store array
|
||||
uni.setStorageSync('tags', ['vue', 'uniapp', 'javascript'])
|
||||
```
|
||||
|
||||
### uni.getStorageSync
|
||||
|
||||
Retrieve data synchronously.
|
||||
|
||||
```javascript
|
||||
// Get simple value
|
||||
const username = uni.getStorageSync('username')
|
||||
console.log(username) // 'John'
|
||||
|
||||
// Get object
|
||||
const userInfo = uni.getStorageSync('userInfo')
|
||||
console.log(userInfo.name) // 'John'
|
||||
|
||||
// Check if exists
|
||||
const value = uni.getStorageSync('nonexistent')
|
||||
console.log(value) // '' (empty string if not found)
|
||||
```
|
||||
|
||||
### uni.removeStorageSync
|
||||
|
||||
Remove specific key.
|
||||
|
||||
```javascript
|
||||
uni.removeStorageSync('username')
|
||||
```
|
||||
|
||||
### uni.clearStorageSync
|
||||
|
||||
Clear all storage.
|
||||
|
||||
```javascript
|
||||
uni.clearStorageSync()
|
||||
```
|
||||
|
||||
## Asynchronous Storage (Recommended for large data)
|
||||
|
||||
### uni.setStorage
|
||||
|
||||
```javascript
|
||||
uni.setStorage({
|
||||
key: 'userData',
|
||||
data: {
|
||||
id: 123,
|
||||
preferences: { theme: 'dark', language: 'zh' }
|
||||
},
|
||||
success: () => {
|
||||
console.log('Storage saved')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('Save failed:', err)
|
||||
}
|
||||
})
|
||||
|
||||
// Promise style
|
||||
uni.setStorage({
|
||||
key: 'config',
|
||||
data: { debug: true }
|
||||
}).then(() => {
|
||||
console.log('Config saved')
|
||||
})
|
||||
```
|
||||
|
||||
### uni.getStorage
|
||||
|
||||
```javascript
|
||||
uni.getStorage({
|
||||
key: 'userData',
|
||||
success: (res) => {
|
||||
console.log('Data:', res.data)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('Key not found')
|
||||
}
|
||||
})
|
||||
|
||||
// Promise style
|
||||
uni.getStorage({ key: 'userData' })
|
||||
.then(res => console.log(res.data))
|
||||
.catch(() => console.log('Not found'))
|
||||
```
|
||||
|
||||
### uni.removeStorage
|
||||
|
||||
```javascript
|
||||
uni.removeStorage({
|
||||
key: 'tempData',
|
||||
success: () => {
|
||||
console.log('Removed successfully')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.getStorageInfo
|
||||
|
||||
Get storage information.
|
||||
|
||||
```javascript
|
||||
uni.getStorageInfo({
|
||||
success: (res) => {
|
||||
console.log('Keys:', res.keys)
|
||||
console.log('Current size:', res.currentSize, 'KB')
|
||||
console.log('Limit size:', res.limitSize, 'KB')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Storage Limits
|
||||
|
||||
| Platform | Limit |
|
||||
|----------|-------|
|
||||
| Mini Program | 10 MB (single) / 200+ MB total |
|
||||
| App | No hard limit (device dependent) |
|
||||
| H5 | ~5-10 MB (browser dependent) |
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Data Persistence Helper
|
||||
|
||||
```javascript
|
||||
const storage = {
|
||||
// Set with expiration (days)
|
||||
setWithExpiry(key, value, days) {
|
||||
const item = {
|
||||
value,
|
||||
expiry: Date.now() + days * 24 * 60 * 60 * 1000
|
||||
}
|
||||
uni.setStorageSync(key, item)
|
||||
},
|
||||
|
||||
// Get with expiration check
|
||||
getWithExpiry(key) {
|
||||
const item = uni.getStorageSync(key)
|
||||
if (!item) return null
|
||||
|
||||
if (Date.now() > item.expiry) {
|
||||
uni.removeStorageSync(key)
|
||||
return null
|
||||
}
|
||||
return item.value
|
||||
},
|
||||
|
||||
// Safe get with default
|
||||
get(key, defaultValue = null) {
|
||||
try {
|
||||
const value = uni.getStorageSync(key)
|
||||
return value !== '' ? value : defaultValue
|
||||
} catch (e) {
|
||||
return defaultValue
|
||||
}
|
||||
},
|
||||
|
||||
// Batch operations
|
||||
setBatch(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
uni.setStorageSync(key, value)
|
||||
})
|
||||
},
|
||||
|
||||
clear() {
|
||||
uni.clearStorageSync()
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
storage.setWithExpiry('token', 'abc123', 7) // Expires in 7 days
|
||||
const token = storage.getWithExpiry('token')
|
||||
```
|
||||
|
||||
### User Session Management
|
||||
|
||||
```javascript
|
||||
const session = {
|
||||
setToken(token) {
|
||||
uni.setStorageSync('access_token', token)
|
||||
},
|
||||
|
||||
getToken() {
|
||||
return uni.getStorageSync('access_token')
|
||||
},
|
||||
|
||||
clearToken() {
|
||||
uni.removeStorageSync('access_token')
|
||||
},
|
||||
|
||||
setUserInfo(info) {
|
||||
uni.setStorageSync('user_info', info)
|
||||
},
|
||||
|
||||
getUserInfo() {
|
||||
return uni.getStorageSync('user_info')
|
||||
},
|
||||
|
||||
isLoggedIn() {
|
||||
return !!this.getToken()
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.clearToken()
|
||||
uni.removeStorageSync('user_info')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## File Storage (App only)
|
||||
|
||||
### Local File System
|
||||
|
||||
```javascript
|
||||
// Get file system manager
|
||||
const fs = uni.getFileSystemManager()
|
||||
|
||||
// Write file
|
||||
fs.writeFile({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/data.json`,
|
||||
data: JSON.stringify({ name: 'test' }),
|
||||
encoding: 'utf8',
|
||||
success: () => console.log('File written')
|
||||
})
|
||||
|
||||
// Read file
|
||||
fs.readFile({
|
||||
filePath: `${uni.env.USER_DATA_PATH}/data.json`,
|
||||
encoding: 'utf8',
|
||||
success: (res) => {
|
||||
const data = JSON.parse(res.data)
|
||||
console.log(data)
|
||||
}
|
||||
})
|
||||
|
||||
// Check if file exists
|
||||
fs.access({
|
||||
path: `${uni.env.USER_DATA_PATH}/data.json`,
|
||||
success: () => console.log('File exists'),
|
||||
fail: () => console.log('File not found')
|
||||
})
|
||||
```
|
||||
|
||||
## Storage Comparison
|
||||
|
||||
| Method | Data Type | Size Limit | Async | Use Case |
|
||||
|--------|-----------|------------|-------|----------|
|
||||
| StorageSync | Any | ~10MB | No | Small config data |
|
||||
| Storage | Any | ~10MB | Yes | Large data objects |
|
||||
| File System | Binary/Text | Large | Yes | Files, images |
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/storage/storage.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/file/file.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/file/getFileSystemManager.md
|
||||
-->
|
||||
@@ -0,0 +1,300 @@
|
||||
---
|
||||
name: System Information
|
||||
description: Device info, system info, and environment detection APIs
|
||||
---
|
||||
|
||||
# System Information
|
||||
|
||||
## uni.getSystemInfo / getSystemInfoSync
|
||||
|
||||
Get device and system information.
|
||||
|
||||
```javascript
|
||||
// Synchronous (faster, recommended)
|
||||
const info = uni.getSystemInfoSync()
|
||||
console.log(info)
|
||||
|
||||
// Asynchronous
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
console.log(res)
|
||||
}
|
||||
})
|
||||
|
||||
// Promise
|
||||
uni.getSystemInfo().then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
```
|
||||
|
||||
### System Info Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| brand | String | Device brand |
|
||||
| model | String | Device model |
|
||||
| pixelRatio | Number | Device pixel ratio |
|
||||
| screenWidth | Number | Screen width (px) |
|
||||
| screenHeight | Number | Screen height (px) |
|
||||
| windowWidth | Number | Window width (px) |
|
||||
| windowHeight | Number | Window height (px) |
|
||||
| statusBarHeight | Number | Status bar height (px) |
|
||||
| language | String | Language |
|
||||
| system | String | OS version |
|
||||
| version | String | WeChat/Runtime version |
|
||||
| platform | String | Platform: ios/android/windows/mac/devtools |
|
||||
| SDKVersion | String | Client base library version |
|
||||
| appId | String | App ID (DCloud) |
|
||||
| appName | String | App name |
|
||||
| appVersion | String | App version |
|
||||
| appCodeName | String | App code name |
|
||||
| uniPlatform | String | uni-app platform |
|
||||
| uniCompileVersion | String | Compilation version |
|
||||
| uniRuntimeVersion | String | Runtime version |
|
||||
| deviceId | String | Device ID |
|
||||
| deviceBrand | String | Device brand |
|
||||
| deviceModel | String | Device model |
|
||||
| deviceType | String | Device type: phone/pad |
|
||||
| osName | String | OS name |
|
||||
| osVersion | String | OS version |
|
||||
| osLanguage | String | OS language |
|
||||
| osTheme | String | OS theme: light/dark |
|
||||
| batteryLevel | Number | Battery level (0-100) |
|
||||
|
||||
## uni.getAppBaseInfo
|
||||
|
||||
Get app base information.
|
||||
|
||||
```javascript
|
||||
const info = uni.getAppBaseInfo()
|
||||
// Returns: appId, appName, appVersion, appVersionCode, etc.
|
||||
```
|
||||
|
||||
## uni.getDeviceInfo
|
||||
|
||||
Get device hardware information.
|
||||
|
||||
```javascript
|
||||
const info = uni.getDeviceInfo()
|
||||
// Returns: brand, model, deviceId, deviceBrand, deviceModel, deviceType
|
||||
```
|
||||
|
||||
## uni.getWindowInfo
|
||||
|
||||
Get window information.
|
||||
|
||||
```javascript
|
||||
const info = uni.getWindowInfo()
|
||||
// Returns: pixelRatio, screenWidth, screenHeight, windowWidth, windowHeight,
|
||||
// statusBarHeight, safeArea, screenTop
|
||||
```
|
||||
|
||||
## Safe Area
|
||||
|
||||
Handle notched devices and safe areas.
|
||||
|
||||
```javascript
|
||||
const info = uni.getSystemInfoSync()
|
||||
|
||||
// Safe area info
|
||||
const safeArea = info.safeArea
|
||||
console.log(safeArea) // { top, left, right, bottom, width, height }
|
||||
|
||||
// Check if device has notch (unsafe area at top)
|
||||
const hasNotch = info.safeAreaInsets && info.safeAreaInsets.top > 0
|
||||
```
|
||||
|
||||
### Safe Area CSS Variables (App/H5)
|
||||
|
||||
```css
|
||||
.safe-area-bottom {
|
||||
padding-bottom: constant(safe-area-inset-bottom); /* iOS 11.0 */
|
||||
padding-bottom: env(safe-area-inset-bottom); /* iOS 11.2+ */
|
||||
}
|
||||
```
|
||||
|
||||
## Network Status
|
||||
|
||||
### uni.getNetworkType
|
||||
|
||||
```javascript
|
||||
uni.getNetworkType({
|
||||
success: (res) => {
|
||||
// res.networkType: wifi/2g/3g/4g/5g/unknown/none
|
||||
console.log('Network:', res.networkType)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### uni.onNetworkStatusChange
|
||||
|
||||
```javascript
|
||||
// Listen for network changes
|
||||
uni.onNetworkStatusChange((res) => {
|
||||
console.log('Network type:', res.networkType)
|
||||
console.log('Is connected:', res.isConnected)
|
||||
})
|
||||
|
||||
// Remove listener
|
||||
uni.offNetworkStatusChange(callback)
|
||||
```
|
||||
|
||||
## Battery Info
|
||||
|
||||
### uni.getBatteryInfo
|
||||
|
||||
```javascript
|
||||
uni.getBatteryInfo({
|
||||
success: (res) => {
|
||||
console.log('Level:', res.level) // 0-100
|
||||
console.log('Is charging:', res.isCharging)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Device Orientation
|
||||
|
||||
### uni.onDeviceMotionChange
|
||||
|
||||
```javascript
|
||||
uni.startDeviceMotionListening({
|
||||
interval: 'normal', // game/ui/normal
|
||||
success: () => {
|
||||
uni.onDeviceMotionChange((res) => {
|
||||
console.log('Alpha:', res.alpha) // 0-360
|
||||
console.log('Beta:', res.beta) // -180 to 180
|
||||
console.log('Gamma:', res.gamma) // -90 to 90
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Stop listening
|
||||
uni.stopDeviceMotionListening()
|
||||
```
|
||||
|
||||
### Screen Orientation
|
||||
|
||||
```javascript
|
||||
// Get current orientation
|
||||
const info = uni.getSystemInfoSync()
|
||||
const isLandscape = info.screenWidth > info.screenHeight
|
||||
|
||||
// Lock orientation (App only)
|
||||
plus.screen.lockOrientation('portrait-primary')
|
||||
// Options: portrait-primary/portrait-secondary/landscape-primary/landscape-secondary
|
||||
```
|
||||
|
||||
## Screen Brightness
|
||||
|
||||
```javascript
|
||||
// Set brightness (0-1)
|
||||
uni.setScreenBrightness({
|
||||
value: 0.8
|
||||
})
|
||||
|
||||
// Get brightness
|
||||
uni.getScreenBrightness({
|
||||
success: (res) => {
|
||||
console.log('Brightness:', res.value)
|
||||
}
|
||||
})
|
||||
|
||||
// Keep screen on
|
||||
uni.setKeepScreenOn({
|
||||
keepScreenOn: true
|
||||
})
|
||||
```
|
||||
|
||||
## Vibration
|
||||
|
||||
```javascript
|
||||
// Short vibration (15ms)
|
||||
uni.vibrateShort()
|
||||
|
||||
// Long vibration (400ms)
|
||||
uni.vibrateLong()
|
||||
|
||||
// Pattern vibration (App only)
|
||||
uni.vibrateLong() // or custom pattern
|
||||
```
|
||||
|
||||
## Clipboard
|
||||
|
||||
```javascript
|
||||
// Set clipboard
|
||||
uni.setClipboardData({
|
||||
data: 'Text to copy',
|
||||
success: () => {
|
||||
uni.showToast({ title: 'Copied' })
|
||||
}
|
||||
})
|
||||
|
||||
// Get clipboard
|
||||
uni.getClipboardData({
|
||||
success: (res) => {
|
||||
console.log('Clipboard:', res.data)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Phone Call
|
||||
|
||||
```javascript
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: '13800138000'
|
||||
})
|
||||
```
|
||||
|
||||
## Scan Code
|
||||
|
||||
```javascript
|
||||
uni.scanCode({
|
||||
onlyFromCamera: false, // Allow from album
|
||||
scanType: ['qrCode', 'barCode'], // Types to scan
|
||||
success: (res) => {
|
||||
console.log('Result:', res.result)
|
||||
console.log('Type:', res.scanType)
|
||||
console.log('CharSet:', res.charSet)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Platform Detection
|
||||
|
||||
```javascript
|
||||
const info = uni.getSystemInfoSync()
|
||||
|
||||
// Platform checks
|
||||
const isIOS = info.platform === 'ios'
|
||||
const isAndroid = info.platform === 'android'
|
||||
const isWindows = info.platform === 'windows'
|
||||
const isMac = info.platform === 'mac'
|
||||
const isDevtools = info.platform === 'devtools'
|
||||
|
||||
// App platform checks
|
||||
const isApp = info.uniPlatform === 'app'
|
||||
const isH5 = info.uniPlatform === 'web'
|
||||
const isWeixinMP = info.uniPlatform === 'mp-weixin'
|
||||
|
||||
// Safe area calculation
|
||||
const safeAreaTop = info.statusBarHeight + (isApp ? 44 : 0) // 44px for nav bar
|
||||
```
|
||||
|
||||
## Storage Info
|
||||
|
||||
```javascript
|
||||
uni.getStorageInfo({
|
||||
success: (res) => {
|
||||
console.log('Keys:', res.keys)
|
||||
console.log('Current size:', res.currentSize)
|
||||
console.log('Limit size:', res.limitSize)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/system/info.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/system/network.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/system/phone.md
|
||||
-->
|
||||
@@ -0,0 +1,382 @@
|
||||
---
|
||||
name: UI Feedback
|
||||
description: Toast, modal, loading, and action sheet APIs
|
||||
---
|
||||
|
||||
# UI Feedback
|
||||
|
||||
## Toast Messages
|
||||
|
||||
### uni.showToast
|
||||
|
||||
Display success/error messages.
|
||||
|
||||
```javascript
|
||||
// Success toast
|
||||
uni.showToast({
|
||||
title: 'Success!',
|
||||
icon: 'success',
|
||||
duration: 2000,
|
||||
mask: false
|
||||
})
|
||||
|
||||
// Loading toast
|
||||
uni.showToast({
|
||||
title: 'Loading...',
|
||||
icon: 'loading',
|
||||
duration: 10000
|
||||
})
|
||||
|
||||
// Text only (no icon)
|
||||
uni.showToast({
|
||||
title: 'Please wait',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// Error toast
|
||||
uni.showToast({
|
||||
title: 'Failed!',
|
||||
icon: 'error'
|
||||
})
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| title | String | Required | Message text |
|
||||
| icon | String | success | success/loading/none/error |
|
||||
| duration | Number | 1500 | Duration in ms |
|
||||
| mask | Boolean | false | Prevent touch during display |
|
||||
| position | String | | top/center/bottom (App) |
|
||||
|
||||
### uni.hideToast
|
||||
|
||||
```javascript
|
||||
uni.hideToast()
|
||||
```
|
||||
|
||||
## Loading
|
||||
|
||||
### uni.showLoading
|
||||
|
||||
```javascript
|
||||
uni.showLoading({
|
||||
title: 'Loading...',
|
||||
mask: true // Prevent interaction
|
||||
})
|
||||
|
||||
// Hide after operation
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
}, 2000)
|
||||
```
|
||||
|
||||
### uni.hideLoading
|
||||
|
||||
```javascript
|
||||
uni.hideLoading()
|
||||
```
|
||||
|
||||
## Modal Dialogs
|
||||
|
||||
### uni.showModal
|
||||
|
||||
Alert and confirm dialogs.
|
||||
|
||||
```javascript
|
||||
// Alert (single button)
|
||||
uni.showModal({
|
||||
title: 'Notice',
|
||||
content: 'Operation completed',
|
||||
showCancel: false
|
||||
})
|
||||
|
||||
// Confirm (two buttons)
|
||||
uni.showModal({
|
||||
title: 'Confirm',
|
||||
content: 'Are you sure?',
|
||||
cancelText: 'Cancel',
|
||||
cancelColor: '#999',
|
||||
confirmText: 'Confirm',
|
||||
confirmColor: '#007AFF',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
console.log('User confirmed')
|
||||
} else if (res.cancel) {
|
||||
console.log('User cancelled')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Editable modal
|
||||
uni.showModal({
|
||||
title: 'Input',
|
||||
content: 'Enter your name',
|
||||
editable: true,
|
||||
placeholderText: 'Name',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
console.log('Input:', res.content)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Action Sheet
|
||||
|
||||
### uni.showActionSheet
|
||||
|
||||
Bottom action menu.
|
||||
|
||||
```javascript
|
||||
uni.showActionSheet({
|
||||
itemList: ['Take Photo', 'Choose from Album', 'Cancel'],
|
||||
itemColor: '#000000',
|
||||
success: (res) => {
|
||||
// res.tapIndex: 0, 1, 2...
|
||||
console.log('Selected:', res.tapIndex)
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
this.takePhoto()
|
||||
break
|
||||
case 1:
|
||||
this.chooseFromAlbum()
|
||||
break
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('Cancelled')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Pull to Refresh
|
||||
|
||||
### Enable in pages.json
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundTextStyle": "dark"
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Handle in Page
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
onPullDownRefresh() {
|
||||
console.log('Pull down triggered')
|
||||
this.refreshData().finally(() => {
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Programmatic Control
|
||||
|
||||
```javascript
|
||||
// Start pull refresh
|
||||
uni.startPullDownRefresh()
|
||||
|
||||
// Stop pull refresh
|
||||
uni.stopPullDownRefresh()
|
||||
```
|
||||
|
||||
## Navigation Bar Loading
|
||||
|
||||
```javascript
|
||||
// Show loading in nav bar
|
||||
uni.showNavigationBarLoading()
|
||||
|
||||
// Hide loading
|
||||
uni.hideNavigationBarLoading()
|
||||
```
|
||||
|
||||
## Tab Bar Operations
|
||||
|
||||
### Show/Hide Tab Bar
|
||||
|
||||
```javascript
|
||||
// Hide tab bar
|
||||
uni.hideTabBar({
|
||||
animation: true
|
||||
})
|
||||
|
||||
// Show tab bar
|
||||
uni.showTabBar({
|
||||
animation: true
|
||||
})
|
||||
```
|
||||
|
||||
### Set Tab Bar Style
|
||||
|
||||
```javascript
|
||||
uni.setTabBarStyle({
|
||||
color: '#999',
|
||||
selectedColor: '#007AFF',
|
||||
backgroundColor: '#fff',
|
||||
borderStyle: 'black'
|
||||
})
|
||||
```
|
||||
|
||||
### Set Tab Bar Item
|
||||
|
||||
```javascript
|
||||
uni.setTabBarItem({
|
||||
index: 0,
|
||||
text: 'Home',
|
||||
iconPath: '/static/home.png',
|
||||
selectedIconPath: '/static/home-active.png'
|
||||
})
|
||||
```
|
||||
|
||||
### Add/Remove Tab Bar Badge
|
||||
|
||||
```javascript
|
||||
// Show badge
|
||||
uni.showTabBarRedDot({
|
||||
index: 2 // Tab index
|
||||
})
|
||||
|
||||
// Hide badge
|
||||
uni.hideTabBarRedDot({
|
||||
index: 2
|
||||
})
|
||||
|
||||
// Set badge text
|
||||
uni.setTabBarBadge({
|
||||
index: 2,
|
||||
text: '5'
|
||||
})
|
||||
|
||||
// Remove badge text
|
||||
uni.removeTabBarBadge({
|
||||
index: 2
|
||||
})
|
||||
```
|
||||
|
||||
## Preview Image
|
||||
|
||||
```javascript
|
||||
uni.previewImage({
|
||||
current: 'https://example.com/1.jpg', // Current image
|
||||
urls: [
|
||||
'https://example.com/1.jpg',
|
||||
'https://example.com/2.jpg',
|
||||
'https://example.com/3.jpg'
|
||||
],
|
||||
indicator: 'default', // default/number/none
|
||||
loop: false,
|
||||
longPressActions: {
|
||||
itemList: ['Save Image', 'Share'],
|
||||
success: (data) => {
|
||||
console.log('Long press:', data.tapIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Save Image to Photos
|
||||
|
||||
```javascript
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: 'temp://path/to/image.jpg',
|
||||
success: () => {
|
||||
uni.showToast({ title: 'Saved' })
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Toast Helper
|
||||
|
||||
```javascript
|
||||
const toast = {
|
||||
success(message, duration = 2000) {
|
||||
uni.showToast({ title: message, icon: 'success', duration })
|
||||
},
|
||||
error(message, duration = 2000) {
|
||||
uni.showToast({ title: message, icon: 'error', duration })
|
||||
},
|
||||
loading(message = 'Loading...') {
|
||||
uni.showLoading({ title: message, mask: true })
|
||||
},
|
||||
hide() {
|
||||
uni.hideLoading()
|
||||
uni.hideToast()
|
||||
},
|
||||
text(message, duration = 2000) {
|
||||
uni.showToast({ title: message, icon: 'none', duration })
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
toast.loading()
|
||||
fetchData()
|
||||
.then(() => toast.success('Loaded'))
|
||||
.catch(() => toast.error('Failed'))
|
||||
.finally(() => toast.hide())
|
||||
```
|
||||
|
||||
### Modal Helper
|
||||
|
||||
```javascript
|
||||
const modal = {
|
||||
confirm(title, content) {
|
||||
return new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title,
|
||||
content,
|
||||
success: (res) => resolve(res.confirm)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
alert(title, content) {
|
||||
return new Promise((resolve) => {
|
||||
uni.showModal({
|
||||
title,
|
||||
content,
|
||||
showCancel: false,
|
||||
success: () => resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
action(items) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.showActionSheet({
|
||||
itemList: items,
|
||||
success: (res) => resolve(res.tapIndex),
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
async function deleteItem(id) {
|
||||
const confirmed = await modal.confirm('Delete', 'Are you sure?')
|
||||
if (confirmed) {
|
||||
await api.delete(id)
|
||||
toast.success('Deleted')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/ui/prompt.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/ui/navigationbar.md
|
||||
- https://gitcode.com/dcloud/unidocs-zh/blob/main/docs/api/ui/tabbar.md
|
||||
-->
|
||||
Reference in New Issue
Block a user