目录
[1.uniapp 如何实现表单验证?](#1.uniapp 如何实现表单验证?)
[3.小程序的自定义 tabBar](#3.小程序的自定义 tabBar)
[配置 manifest.json 文件](#配置 manifest.json 文件)
[创建自定义 tabBar 组件](#创建自定义 tabBar 组件)
[实现 tabBar 逻辑](#实现 tabBar 逻辑)
[4.uniapp 状态管理 方法](#4.uniapp 状态管理 方法)
[Vuex 状态管理](#Vuex 状态管理)
[Pinia 替代方案](#Pinia 替代方案)
[Vuex 推荐场景](#Vuex 推荐场景)
[使用uni.share API](#使用uni.share API)
[7.UniApp使用 WebSocket](#7.UniApp使用 WebSocket)
[WebSocket 基础配置](#WebSocket 基础配置)
[监听 WebSocket 事件](#监听 WebSocket 事件)
[关闭 WebSocket 连接](#关闭 WebSocket 连接)
[8.UniApp 如何支持 PWA](#8.UniApp 如何支持 PWA)
[配置 manifest.json](#配置 manifest.json)
[生成 Service Worker](#生成 Service Worker)
[9.UniApp 中如何处理用户授权](#9.UniApp 中如何处理用户授权)
[10. UniApp 的插件机制,如何集成一个地图插件](#10. UniApp 的插件机制,如何集成一个地图插件)
[UniApp 插件机制概述](#UniApp 插件机制概述)
1.uniapp 如何实现表单验证?
内置组件
uniapp的<form>
组件和<input>
组件支持基础的表单验证。可以设置required
属性进行非空验证,或通过type
属性限制输入类型(如email
、number
)。
html
<form @submit="handleSubmit">
<input v-model="formData.username" required placeholder="请输入用户名" />
<input v-model="formData.password" type="password" required placeholder="请输入密码" />
<button form-type="submit">提交</button>
</form>
自定义函数
通过JavaScript编写验证逻辑,在提交表单时触发验证函数。例如验证手机号格式:
第三方验证库
async-validator
可以简化复杂验证规则的实现
javascript
import Schema from 'async-validator';
const rules = {
username: { type: 'string', required: true, message: '用户名不能为空' },
email: { type: 'email', message: '邮箱格式不正确' }
};
const validator = new Schema(rules);
methods: {
validateForm() {
validator.validate(this.formData, (errors) => {
if (errors) {
uni.showToast({ title: errors[0].message, icon: 'none' });
} else {
// 提交表单
}
});
}
}
实时表单验证
通过监听输入变化实现实时验证,提升用户体验
html
<input v-model="formData.email" @input="validateEmail" placeholder="邮箱" />
javascript
methods: {
validateEmail() {
const reg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!reg.test(this.formData.email)) {
this.errorMsg = '邮箱格式不正确';
} else {
this.errorMsg = '';
}
}
}
结合UI组件库
使用uView
或uni-ui
等组件库提供的表单验证功能,可以快速实现带错误提示的验证。以uView
为例:
html
<u-form :model="formData" :rules="rules" ref="uForm">
<u-form-item label="用户名" prop="username">
<u-input v-model="formData.username" />
</u-form-item>
</u-form>
javascript
data() {
return {
rules: {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }]
}
};
},
methods: {
submit() {
this.$refs.uForm.validate(valid => {
if (valid) {
// 验证通过
}
});
}
}
后端验证的必要性
前端验证无法替代后端验证。在提交数据到服务器后,必须进行后端验证以确保数据安全性。前端验证仅用于提升用户体验和减少无效请求。
2.不同平台的导航栏差异
导航栏基础配置
在
pages.json
中配置全局导航栏样式,通过globalStyle
统一基础属性,例如背景色、文字颜色。针对特定页面,在style
节点中覆盖全局配置。
javascript
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "默认标题",
"navigationBarBackgroundColor": "#FFFFFF"
},
"pages": [{
"path": "page/index",
"style": {
"navigationBarTitleText": "自定义标题"
}
}]
条件编译
在
pages.json
或组件中,通过#ifdef
和#endif
区分不同平台代码块。
javascript
"style": {
"navigationBarTitleText": "通用标题",
"#ifdef H5": {
"navigationStyle": "custom" // H5隐藏默认导航栏
},
"#ifdef APP-PLUS": {
"titleNView": { // APP专用配置
"buttons": [{
"text": "按钮",
"fontSize": "16px"
}]
}
}
}
JS控制导航栏
通过
uni.setNavigationBarTitle
或uni.setNavigationBarColor
动态修改导航栏属性。注意:部分API在小程序不兼容
javascript
// 修改标题
uni.setNavigationBarTitle({
title: '新标题'
});
// 修改背景色(仅支持HEX)
uni.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#FF0000'
});
复杂导航栏处理
在
titleNView
配置复杂导航栏,支持按钮、搜索框等组件。需在pages.json
中声明:
javascript
"titleNView": {
"searchInput": {
"align": "center",
"backgroundColor": "#F5F5F5",
"borderRadius": "4px"
},
"buttons": [{
"text": "\ue534",
"fontSrc": "/static/iconfont.ttf",
"fontSize": "22px"
}]
}
微信小程序胶囊按钮适配
通过
uni.getMenuButtonBoundingClientRect()
获取胶囊按钮位置信息,动态计算偏移量
javascript
const menuInfo = uni.getMenuButtonBoundingClientRect();
console.log(menuInfo.width, menuInfo.top);
// 示例:自定义导航栏高度计算
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
const navHeight = menuInfo.top + menuInfo.height + 8;
自定义导航栏组件
创建跨平台导航栏组件,通过
slot
接收内容,内部处理平台差异:
javascript
<template>
<view class="custom-nav">
<!-- 安卓/iOS返回按钮 -->
<view v-if="showBack" @click="handleBack">
<text class="icon-back"></text>
</view>
<slot></slot>
</view>
</template>
<script>
export default {
computed: {
showBack() {
return uni.getSystemInfoSync().platform !== 'h5';
}
},
methods: {
handleBack() {
uni.navigateBack();
}
}
}
</script>
状态栏高度适配
使用
uni.getSystemInfoSync()
获取状态栏高度,确保内容不被遮挡:
javascript
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight || 0;
const navBarHeight = systemInfo.platform === 'android' ? 48 : 44;
const totalHeight = statusBarHeight + navBarHeight;
注意事项
- 微信小程序自定义导航栏需在
pages.json
设置"navigationStyle": "custom"
- APP端动态修改导航栏按钮需使用
uni.setNavigationBarButton
- H5端隐藏导航栏可能影响浏览器原生返回功能
- 颜色值需使用6位HEX格式(如
#RRGGBB
),不支持缩写或RGB
3.小程序的自定义 tabBar
配置 manifest.json 文件
在项目的 manifest.json
文件中,明确声明需要使用自定义 tabBar。找到对应的小程序配置项(如微信小程序),添加以下配置:
javascript
"mp-weixin": {
"tabBar": {
"custom": true
}
}
创建自定义 tabBar 组件
在项目根目录下创建 custom-tab-bar
文件夹,内部结构需符合小程序规范。通常包含以下文件:
index.vue
(或index
目录下的组件文件)- 相关样式和逻辑文件
实现 tabBar 逻辑
在 custom-tab-bar/index.vue
中,通过 Vue 语法实现交互逻辑。例如:
javascript
<template>
<div class="custom-tab-bar">
<div v-for="(item, index) in list" :key="index" @click="switchTab(index)">
{{ item.text }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ text: "首页", pagePath: "/pages/index/index" },
{ text: "分类", pagePath: "/pages/category/index" }
]
};
},
methods: {
switchTab(index) {
uni.switchTab({ url: this.list[index].pagePath });
}
}
};
</script>
同步页面路径与选中状态
在 pages.json
中配置原生 tabBar 的路径(仅作参考,实际渲染由自定义组件控制):
javascript
"tabBar": {
"list": [
{ "pagePath": "pages/index/index" },
{ "pagePath": "pages/category/index" }
]
}
处理页面生命周期
在页面 onShow
生命周期中更新 tabBar 选中状态:
javascript
onShow() {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 0 }); // 根据实际索引调整
}
}
4.uniapp 状态管理 方法
全局变量
在 App.vue
中定义全局变量,通过 getApp().globalData
访问。适合简单数据共享,但不支持响应式更新。
javascript
// App.vue
export default {
globalData: { count: 0 }
}
// 页面中使用
const app = getApp()
console.log(app.globalData.count)
Vuex 状态管理
Vuex 是 Vue 生态的集中式状态管理工具,适合复杂应用。UniApp 支持 Vuex,需在项目根目录创建 store
文件夹并配置。
javascript
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: { count: 0 },
mutations: { increment(state) { state.count++ } }
})
javascript
// 页面中使用
import { mapState, mapMutations } from 'vuex'
export default {
computed: { ...mapState(['count']) },
methods: { ...mapMutations(['increment']) }
}
Pinia 替代方案
Pinia 是 Vuex 的轻量级替代,支持 Composition API,TypeScript 友好。UniApp 可通过插件引入。
javascript
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: { increment() { this.count++ } }
})
javascript
// 页面中使用
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
return { counter }
}
}
本地存储与持久化
结合 uni.setStorageSync
实现状态持久化,适合需长期保存的数据。
javascript
// 存储状态
uni.setStorageSync('userToken', 'abc123')
// 读取状态
const token = uni.getStorageSync('userToken')
Vuex 推荐场景
- 推荐使用:跨多个页面共享复杂状态,需严格的同步更新机制。
- 不推荐场景:简单应用或仅需父子组件通信时,优先使用 Props/Emit 或全局变量。
Vuex 会增加项目复杂度,建议根据实际需求评估。对于小型项目,Pinia 或全局变量可能更高效。
5.跨平台分享功能
UniApp提供了统一的API,支持微信、QQ、微博等主流社交平台的分享功能。
使用uni.share
API
UniApp内置的uni.share
API可以轻松实现多平台分享。该API支持微信、QQ、新浪微博等平台。
javascript
uni.share({
provider: "weixin", // 分享服务提供商,可选值:weixin、qq、sinaweibo等
scene: "WXSceneSession", // 分享到聊天界面(WXSceneSession)或朋友圈(WXSceneTimeline)
type: 0, // 分享类型,0为图文,1为纯文字,2为图片,5为小程序
title: "分享标题",
summary: "分享内容摘要",
href: "https://example.com", // 分享链接
imageUrl: "https://example.com/image.png", // 分享图片
success: function(res) {
console.log("分享成功");
},
fail: function(err) {
console.log("分享失败", err);
}
});
平台差异处理
不同平台对分享的支持程度不同,需根据平台特性调整参数。例如,微信支持分享到朋友圈和聊天界面,而QQ仅支持分享到聊天界面。
javascript
// 判断平台并设置不同参数
let provider = "";
let scene = "";
// #ifdef MP-WEIXIN
provider = "weixin";
scene = "WXSceneSession"; // 或 WXSceneTimeline
// #endif
// #ifdef MP-QQ
provider = "qq";
// #endif
uni.share({
provider: provider,
scene: scene,
// 其他参数
});
自定义分享按钮
某些平台(如微信小程序)要求分享必须通过按钮触发,不能直接调用API。需要在页面中添加<button>
组件并设置open-type="share"
。
html
<button open-type="share" type="warn">点击分享</button>
在页面的onShareAppMessage
生命周期中定义分享内容:
javascript
onShareAppMessage() {
return {
title: "自定义分享标题",
path: "/pages/index/index",
imageUrl: "/static/logo.png"
};
}
分享到更多平台
如果需要分享到更多平台(如微博、支付宝等),可以通过条件编译或第三方插件扩展功能。
javascript
// #ifdef APP-PLUS
// 使用原生扩展或第三方SDK
const share = uni.requireNativePlugin("ShareModule");
share.shareToWeibo({
text: "分享到微博",
image: "/static/logo.png"
});
// #endif
注意事项
- 分享功能在某些平台(如微信)需要配置合法域名。
- 部分平台要求应用审核通过后才能使用分享功能。
- 图片链接需为HTTPS协议,且某些平台对图片大小有限制。
6.小程序图片上传
uni.chooseImage选择图片
调用uni.chooseImage
接口选择本地图片,支持多选和压缩。
javascript
uni.chooseImage({
count: 3, // 最多选择3张
sizeType: ['compressed'], // 压缩图
success: (res) => {
const tempFilePaths = res.tempFilePaths // 临时文件路径数组
}
})
上传图片到服务器
获取临时路径后,通过uni.uploadFile
上传。需注意小程序端需配置合法域名:
javascript
uni.uploadFile({
url: 'https://example.com/upload',
filePath: tempFilePaths[0],
name: 'file',
formData: { user: 'test' },
success: (uploadRes) => {
console.log(uploadRes.data);
}
})
多图上传处理
递归上传方法 采用递归方式依次上传多张图片,确保顺序执行:
javascript
function uploadFiles(files, index = 0) {
if (index >= files.length) return
uni.uploadFile({
url: 'https://example.com/upload',
filePath: files[index],
success: () => {
uploadFiles(files, index + 1)
}
})
}
图片压缩与预览
使用条件编译处理平台差异 通过#ifdef
区分平台,H5端可用canvas压缩:
javascript
// #ifdef H5
compressImage(path) {
// H5端压缩逻辑
}
// #endif
预览大图接口 调用uni.previewImage
实现预览功能:
javascript
uni.previewImage({
current: 0, // 当前显示索引
urls: imageList // 图片URL数组
})
注意事项
域名白名单配置 小程序需在后台配置request
和uploadFile
的合法域名,开发阶段可勾选不校验域名。
临时路径有效期 小程序端获取的临时路径仅在本次启动有效,不可直接存储。需上传成功后保存服务器返回的永久URL。
类型限制示例 通过extension
参数限制文件类型:
javascript
uni.chooseImage({
extension: ['jpg', 'png'] // 只允许选择jpg/png
})
7.UniApp使用 WebSocket
WebSocket 基础配置
在 UniApp 中使用 WebSocket 需要通过 uni.connectSocket
方法建立连接。
javascript
const socketTask = uni.connectSocket({
url: 'wss://your-websocket-server.com',
success: () => {
console.log('WebSocket 连接成功');
},
fail: (err) => {
console.error('WebSocket 连接失败', err);
}
});
监听 WebSocket 事件
WebSocket 支持多个事件监听,包括连接打开、接收消息、错误和关闭事件。通过 uni.onSocketOpen
、uni.onSocketMessage
等方法实现:
javascript
uni.onSocketOpen((res) => {
console.log('WebSocket 连接已打开');
});
uni.onSocketMessage((res) => {
console.log('收到服务器内容:', res.data);
});
uni.onSocketError((err) => {
console.error('WebSocket 错误:', err);
});
uni.onSocketClose((res) => {
console.log('WebSocket 连接已关闭');
});
发送消息
通过 uni.sendSocketMessage
方法向服务器发送消息:
javascript
uni.sendSocketMessage({
data: JSON.stringify({ message: 'Hello WebSocket' }),
success: () => {
console.log('消息发送成功');
},
fail: (err) => {
console.error('消息发送失败', err);
}
});
关闭 WebSocket 连接
通过 uni.closeSocket
方法主动关闭连接:
javascript
uni.closeSocket({
success: () => {
console.log('WebSocket 连接已关闭');
}
});
断线重连机制
为实现稳定性,可以加入断线重连的逻辑。以下是一个简单的实现:
javascript
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
function connectWebSocket() {
const socketTask = uni.connectSocket({
url: 'wss://your-websocket-server.com',
success: () => {
reconnectAttempts = 0;
},
fail: () => {
if (reconnectAttempts < maxReconnectAttempts) {
setTimeout(connectWebSocket, 3000);
reconnectAttempts++;
}
}
});
}
uni.onSocketClose(() => {
if (reconnectAttempts < maxReconnectAttempts) {
setTimeout(connectWebSocket, 3000);
reconnectAttempts++;
}
});
注意事项
- 协议支持 :确保服务器支持 WebSocket 协议(
ws://
或wss://
)。 - 多平台兼容性:部分小程序平台对 WebSocket 的实现可能有差异,需测试目标平台。
- 心跳机制:长时间连接建议加入心跳包防止超时断开。
- 全局管理:建议将 WebSocket 逻辑封装为单独模块以便复用。
示例
javascript
class WebSocketManager {
constructor(url) {
this.url = url;
this.socketTask = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
}
connect() {
this.socketTask = uni.connectSocket({
url: this.url,
success: () => {
this.reconnectAttempts = 0;
},
fail: () => this.handleReconnect()
});
this.setupEventListeners();
}
setupEventListeners() {
uni.onSocketOpen(() => {
console.log('WebSocket connected');
});
uni.onSocketMessage((res) => {
console.log('Received:', res.data);
});
uni.onSocketClose(() => {
this.handleReconnect();
});
}
handleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
setTimeout(() => this.connect(), 3000);
this.reconnectAttempts++;
}
}
send(data) {
uni.sendSocketMessage({
data: JSON.stringify(data)
});
}
close() {
uni.closeSocket();
}
}
// 使用示例
const ws = new WebSocketManager('wss://your-websocket-server.com');
ws.connect();
8.UniApp 如何支持 PWA
UniApp 通过特定的配置和插件可以将应用打包为 PWA(Progressive Web App),
配置 manifest.json
在项目根目录创建 manifest.json
文件,内容参考以下示例:
javascript
{
"name": "My PWA App",
"short_name": "PWA App",
"start_url": ".",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4DBA87",
"icons": [
{
"src": "static/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "static/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
修改项目配置
在 manifest.json
同目录下创建 vue.config.js
,配置 PWA 插件:
javascript
module.exports = {
pwa: {
name: 'My PWA App',
themeColor: '#4DBA87',
msTileColor: '#000000',
appleMobileWebAppCapable: 'yes',
appleMobileWebAppStatusBarStyle: 'black',
manifestPath: 'manifest.json',
workboxPluginMode: 'GenerateSW',
workboxOptions: {
skipWaiting: true,
clientsClaim: true
}
}
}
生成 Service Worker
UniApp 使用 Workbox 生成 Service Worker。确保项目中已安装 workbox-webpack-plugin
:
bash
npm install workbox-webpack-plugin --save-dev
构建项目
运行以下命令生成 PWA 所需的文件:
bash
npm run build
构建完成后,dist
目录会包含 sw.js
和 manifest.json
等 PWA 必需文件。
部署注意事项
- 必须通过 HTTPS 协议访问 PWA 应用。
- 确保服务器正确配置
Content-Type
为application/json
处理manifest.json
。 - 测试 PWA 功能可使用 Chrome 的 Lighthouse 工具。
9.UniApp 中如何处理用户授权
检查权限状态
在 UniApp 中,可以使用 uni.getSetting
检查用户是否已授权某项权限。该方法返回用户的授权状态,可通过 authSetting
对象判断具体权限是否开启。
javascript
uni.getSetting({
success(res) {
const hasLocationPermission = res.authSetting['scope.userLocation']
if (hasLocationPermission) {
console.log('用户已授权位置权限')
} else {
console.log('用户未授权位置权限')
}
}
})
请求权限
如果用户未授权,通过 uni.authorize
发起权限请求。需在 manifest.json
中声明所需权限(如 "requiredPrivateInfos": ["getLocation"]
)。
javascript
uni.authorize({
scope: 'scope.userLocation',
success() {
console.log('授权成功')
},
fail() {
console.log('授权失败')
}
})
处理拒绝授权后的引导
用户可能首次拒绝授权,需通过 uni.openSetting
引导用户手动开启权限
javascript
uni.showModal({
title: '提示',
content: '需要位置权限才能继续使用,是否去设置开启?',
success(res) {
if (res.confirm) {
uni.openSetting({
success(res) {
console.log('用户已跳转至设置页')
}
})
}
}
})
获取用户位置
授权成功后,调用 uni.getLocation
获取具体位置信息。需注意高精度模式(isHighAccuracy
)可能增加耗电量。
javascript
uni.getLocation({
type: 'wgs84',
success(res) {
console.log('经度:', res.longitude, '纬度:', res.latitude)
},
fail(err) {
console.error('获取位置失败:', err)
}
})
兼容多端差异
不同平台(微信小程序、H5、App)的权限机制可能不同:
- 微信小程序 :需通过
button
组件的open-type="openSetting"
触发跳转设置页。 - H5 :依赖浏览器 API(如
navigator.geolocation
),需处理 HTTPS 环境限制。 - App :需在原生配置文件中声明权限(如 Android 的
AndroidManifest.xml
)。
注意事项
- 频繁调用授权弹窗可能被平台限制,建议合理设计触发逻辑。
- 部分平台(如 iOS)要求提供权限使用目的描述,需在配置文件中补充隐私说明。
- 用户拒绝后,部分平台(如微信小程序)需等待 24 小时才能再次触发授权弹窗。
10. UniApp 的插件机制,如何集成一个地图插件
UniApp 插件机制概述
UniApp 的插件机制允许开发者扩展原生功能,通过集成原生插件实现跨平台能力(如调用设备硬件、地图、支付等)。插件分为两种类型:
- 原生插件:基于 Android/iOS 原生代码开发,需通过 UniApp 的插件市场或手动集成。
- JS 插件:纯前端实现,基于 JavaScript 的通用功能扩展。
插件通过 uni.requireNativePlugin
或直接引入 JS 模块的方式调用。
集成地图插件的步骤
选择地图插件
UniApp 官方推荐的高德地图或腾讯地图插件,可通过插件市场搜索并下载。以高德地图为例:
配置插件
-
引入插件包
下载插件后,将插件包(如
amap-uni-plugin
)放入项目根目录的nativeplugins
文件夹。 -
配置 manifest.json
在
manifest.json
的App原生插件配置
中添加插件:javascript"app-plus": { "plugins": { "amap": { "version": "x.x.x", // 插件版本 "provider": "dcloud.amap" } } }
-
配置平台密钥
在高德开放平台申请 AppKey,并填入
manifest.json
:javascript"app-plus": { "distribute": { "android": { "amap": { "appkey": "你的高德Android Key" } }, "ios": { "amap": { "appkey": "你的高德iOS Key" } } } }
调用插件功能
在页面中通过原生插件 API 调用地图功能:
javascript
const amap = uni.requireNativePlugin('amap');
amap.init(() => {
console.log('地图初始化成功');
});
// 打开地图页面
amap.openMap({
latitude: 39.90469,
longitude: 116.40717,
name: '北京市'
});
注意事项
- 平台差异:Android 和 iOS 需分别配置密钥和权限。
- 调试:真机调试时需确保原生插件已正确打包到安装包中。
- 更新插件:插件版本需与 UniApp SDK 兼容,定期检查更新。