API调用详解 - 网络请求、本地存储、设备信息
🔌 API是应用的生命线,今天我们来学习如何调用各种API让应用更强大
1. 网络请求
基础请求
javascript
// GET请求
async function getData() {
try {
const res = await uni.request({
url: 'https://api.example.com/users',
method: 'GET',
header: {
'Content-Type': 'application/json'
}
})
console.log('请求成功:', res.data)
return res.data
} catch (error) {
console.error('请求失败:', error)
uni.showToast({
title: '网络请求失败',
icon: 'error'
})
}
}
// POST请求
async function postData(userData) {
try {
const res = await uni.request({
url: 'https://api.example.com/users',
method: 'POST',
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getToken()
},
data: userData
})
return res.data
} catch (error) {
console.error('提交失败:', error)
throw error
}
}
封装请求工具
javascript
// utils/request.js
class Request {
constructor() {
this.baseURL = 'https://api.example.com'
this.timeout = 10000
this.header = {
'Content-Type': 'application/json'
}
}
// 请求拦截器
interceptRequest(config) {
// 添加token
const token = uni.getStorageSync('token')
if (token) {
config.header.Authorization = 'Bearer ' + token
}
// 显示加载提示
uni.showLoading({
title: '加载中...'
})
return config
}
// 响应拦截器
interceptResponse(response) {
// 隐藏加载提示
uni.hideLoading()
// 统一错误处理
if (response.statusCode !== 200) {
uni.showToast({
title: '请求失败',
icon: 'error'
})
throw new Error(`HTTP \${response.statusCode}`)
}
// 业务错误处理
if (response.data.code !== 0) {
uni.showToast({
title: response.data.message || '操作失败',
icon: 'error'
})
throw new Error(response.data.message)
}
return response.data
}
// 通用请求方法
async request(options) {
const config = {
url: this.baseURL + options.url,
method: options.method || 'GET',
header: { ...this.header, ...options.header },
data: options.data,
timeout: this.timeout
}
try {
const interceptedConfig = this.interceptRequest(config)
const response = await uni.request(interceptedConfig)
return this.interceptResponse(response)
} catch (error) {
uni.hideLoading()
throw error
}
}
// 便捷方法
get(url, params) {
return this.request({
url: params ? `\${url}?\${this.buildQuery(params)}` : url,
method: 'GET'
})
}
post(url, data) {
return this.request({
url,
method: 'POST',
data
})
}
put(url, data) {
return this.request({
url,
method: 'PUT',
data
})
}
delete(url) {
return this.request({
url,
method: 'DELETE'
})
}
// 构建查询字符串
buildQuery(params) {
return Object.keys(params)
.map(key => `\${encodeURIComponent(key)}=\${encodeURIComponent(params[key])}`)
.join('&')
}
}
// 创建实例
const request = new Request()
export default request
使用封装的请求
vue
<template>
<view class="api-demo">
<button @click="loadUsers">获取用户列表</button>
<button @click="createUser">创建用户</button>
<view v-for="user in users" :key="user.id" class="user-item">
<text>\{\{ user.name \}\} - \{\{ user.email \}\}</text>
</view>
</view>
</template>
<script>
import request from '@/utils/request.js'
export default {
data() {
return {
users: []
}
},
methods: {
async loadUsers() {
try {
const result = await request.get('/users', {
page: 1,
limit: 10
})
this.users = result.data
} catch (error) {
console.error('加载用户失败:', error)
}
},
async createUser() {
try {
const newUser = {
name: '新用户',
email: 'new@example.com'
}
const result = await request.post('/users', newUser)
this.users.push(result.data)
uni.showToast({
title: '创建成功',
icon: 'success'
})
} catch (error) {
console.error('创建用户失败:', error)
}
}
}
}
</script>
2. 本地存储
同步存储
javascript
// 存储数据
uni.setStorageSync('userInfo', {
id: 1,
name: '张三',
avatar: '/static/avatar.jpg'
})
// 读取数据
const userInfo = uni.getStorageSync('userInfo')
console.log('用户信息:', userInfo)
// 删除数据
uni.removeStorageSync('userInfo')
// 清空所有数据
uni.clearStorageSync()
// 获取存储信息
const storageInfo = uni.getStorageInfoSync()
console.log('存储信息:', storageInfo)
异步存储
javascript
// 异步存储
async function saveUserData(userData) {
try {
await uni.setStorage({
key: 'userData',
data: userData
})
console.log('保存成功')
} catch (error) {
console.error('保存失败:', error)
}
}
// 异步读取
async function getUserData() {
try {
const res = await uni.getStorage({
key: 'userData'
})
return res.data
} catch (error) {
console.error('读取失败:', error)
return null
}
}
存储管理工具
javascript
// utils/storage.js
class Storage {
// 设置过期时间的存储
setWithExpiry(key, value, expiryMinutes = 60) {
const now = new Date()
const item = {
value: value,
expiry: now.getTime() + (expiryMinutes * 60 * 1000)
}
uni.setStorageSync(key, item)
}
// 获取带过期时间的存储
getWithExpiry(key) {
const itemStr = uni.getStorageSync(key)
if (!itemStr) {
return null
}
const item = itemStr
const now = new Date()
if (now.getTime() > item.expiry) {
uni.removeStorageSync(key)
return null
}
return item.value
}
// 存储用户信息
setUserInfo(userInfo) {
uni.setStorageSync('userInfo', userInfo)
}
// 获取用户信息
getUserInfo() {
return uni.getStorageSync('userInfo') || {}
}
// 清除用户信息
clearUserInfo() {
uni.removeStorageSync('userInfo')
uni.removeStorageSync('token')
}
// 存储token
setToken(token) {
uni.setStorageSync('token', token)
}
// 获取token
getToken() {
return uni.getStorageSync('token')
}
// 检查是否登录
isLoggedIn() {
return !!this.getToken()
}
}
const storage = new Storage()
export default storage
3. 设备信息
获取系统信息
javascript
// 获取系统信息
function getSystemInfo() {
const systemInfo = uni.getSystemInfoSync()
console.log('设备信息:', {
brand: systemInfo.brand, // 设备品牌
model: systemInfo.model, // 设备型号
system: systemInfo.system, // 操作系统
platform: systemInfo.platform, // 客户端平台
version: systemInfo.version, // 微信版本号
SDKVersion: systemInfo.SDKVersion, // 基础库版本
screenWidth: systemInfo.screenWidth, // 屏幕宽度
screenHeight: systemInfo.screenHeight, // 屏幕高度
windowWidth: systemInfo.windowWidth, // 可使用窗口宽度
windowHeight: systemInfo.windowHeight, // 可使用窗口高度
statusBarHeight: systemInfo.statusBarHeight, // 状态栏高度
safeArea: systemInfo.safeArea // 安全区域
})
return systemInfo
}
// 异步获取
async function getSystemInfoAsync() {
try {
const systemInfo = await uni.getSystemInfo()
return systemInfo
} catch (error) {
console.error('获取系统信息失败:', error)
}
}
网络状态
javascript
// 获取网络类型
function getNetworkType() {
uni.getNetworkType({
success: (res) => {
console.log('网络类型:', res.networkType)
// wifi, 2g, 3g, 4g, 5g, unknown, none
if (res.networkType === 'none') {
uni.showToast({
title: '网络连接失败',
icon: 'error'
})
}
}
})
}
// 监听网络状态变化
function watchNetworkStatus() {
uni.onNetworkStatusChange((res) => {
console.log('网络状态变化:', res)
if (!res.isConnected) {
uni.showToast({
title: '网络已断开',
icon: 'error'
})
} else {
uni.showToast({
title: '网络已连接',
icon: 'success'
})
}
})
}
位置信息
javascript
// 获取当前位置
async function getCurrentLocation() {
try {
const res = await uni.getLocation({
type: 'gcj02', // 坐标系类型
altitude: true // 传入 true 会返回高度信息
})
console.log('位置信息:', {
latitude: res.latitude, // 纬度
longitude: res.longitude, // 经度
speed: res.speed, // 速度
accuracy: res.accuracy, // 位置精度
altitude: res.altitude, // 高度
verticalAccuracy: res.verticalAccuracy, // 垂直精度
horizontalAccuracy: res.horizontalAccuracy // 水平精度
})
return res
} catch (error) {
console.error('获取位置失败:', error)
if (error.errMsg.includes('auth deny')) {
uni.showModal({
title: '提示',
content: '需要获取您的地理位置,请确认授权',
success: (res) => {
if (res.confirm) {
uni.openSetting()
}
}
})
}
}
}
// 选择位置
function chooseLocation() {
uni.chooseLocation({
success: (res) => {
console.log('选择的位置:', {
name: res.name,
address: res.address,
latitude: res.latitude,
longitude: res.longitude
})
},
fail: (error) => {
console.error('选择位置失败:', error)
}
})
}
4. 实战案例:用户管理页面
vue
<template>
<view class="user-manager">
<!-- 系统信息 -->
<view class="info-section">
<text class="section-title">设备信息</text>
<view class="info-item">
<text>设备型号:\{\{ deviceInfo.model \}\}</text>
</view>
<view class="info-item">
<text>系统版本:\{\{ deviceInfo.system \}\}</text>
</view>
<view class="info-item">
<text>网络状态:\{\{ networkStatus \}\}</text>
</view>
</view>
<!-- 用户信息 -->
<view class="info-section">
<text class="section-title">用户信息</text>
<view v-if="userInfo.id" class="user-card">
<image :src="userInfo.avatar" class="avatar" />
<view class="user-details">
<text class="username">\{\{ userInfo.name \}\}</text>
<text class="user-email">\{\{ userInfo.email \}\}</text>
</view>
<button @click="logout" size="mini">退出登录</button>
</view>
<view v-else class="login-prompt">
<text>未登录</text>
<button @click="login" type="primary" size="mini">立即登录</button>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-section">
<button @click="refreshData">刷新数据</button>
<button @click="clearCache">清除缓存</button>
<button @click="getLocation">获取位置</button>
</view>
<!-- 位置信息 -->
<view v-if="locationInfo" class="info-section">
<text class="section-title">位置信息</text>
<view class="info-item">
<text>纬度:\{\{ locationInfo.latitude \}\}</text>
</view>
<view class="info-item">
<text>经度:\{\{ locationInfo.longitude \}\}</text>
</view>
<view class="info-item">
<text>精度:\{\{ locationInfo.accuracy \}\}米</text>
</view>
</view>
</view>
</template>
<script>
import request from '@/utils/request.js'
import storage from '@/utils/storage.js'
export default {
data() {
return {
deviceInfo: {},
networkStatus: '未知',
userInfo: {},
locationInfo: null
}
},
onLoad() {
this.initData()
},
methods: {
async initData() {
// 获取设备信息
this.deviceInfo = uni.getSystemInfoSync()
// 获取网络状态
this.getNetworkStatus()
// 获取用户信息
this.userInfo = storage.getUserInfo()
// 监听网络状态变化
this.watchNetwork()
},
getNetworkStatus() {
uni.getNetworkType({
success: (res) => {
this.networkStatus = res.networkType
}
})
},
watchNetwork() {
uni.onNetworkStatusChange((res) => {
this.networkStatus = res.networkType
if (!res.isConnected) {
uni.showToast({
title: '网络已断开',
icon: 'error'
})
}
})
},
async login() {
try {
// 模拟登录
const loginData = {
username: 'demo',
password: '123456'
}
const result = await request.post('/auth/login', loginData)
// 保存用户信息和token
storage.setUserInfo(result.user)
storage.setToken(result.token)
this.userInfo = result.user
uni.showToast({
title: '登录成功',
icon: 'success'
})
} catch (error) {
console.error('登录失败:', error)
}
},
logout() {
uni.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
storage.clearUserInfo()
this.userInfo = {}
uni.showToast({
title: '已退出登录',
icon: 'success'
})
}
}
})
},
async refreshData() {
try {
if (!storage.isLoggedIn()) {
uni.showToast({
title: '请先登录',
icon: 'error'
})
return
}
const userInfo = await request.get('/user/profile')
storage.setUserInfo(userInfo)
this.userInfo = userInfo
uni.showToast({
title: '刷新成功',
icon: 'success'
})
} catch (error) {
console.error('刷新失败:', error)
}
},
clearCache() {
uni.showModal({
title: '清除缓存',
content: '确定要清除所有缓存数据吗?',
success: (res) => {
if (res.confirm) {
uni.clearStorageSync()
this.userInfo = {}
uni.showToast({
title: '缓存已清除',
icon: 'success'
})
}
}
})
},
async getLocation() {
try {
const location = await uni.getLocation({
type: 'gcj02'
})
this.locationInfo = location
uni.showToast({
title: '位置获取成功',
icon: 'success'
})
} catch (error) {
console.error('获取位置失败:', error)
if (error.errMsg.includes('auth deny')) {
uni.showModal({
title: '权限申请',
content: '需要获取您的位置信息,请在设置中开启位置权限',
success: (res) => {
if (res.confirm) {
uni.openSetting()
}
}
})
}
}
}
}
}
</script>
<style>
.user-manager {
padding: 20px;
}
.info-section {
margin-bottom: 30px;
background: white;
border-radius: 8px;
padding: 15px;
}
.section-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
display: block;
}
.info-item {
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
}
.user-card {
display: flex;
align-items: center;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 25px;
margin-right: 15px;
}
.user-details {
flex: 1;
}
.username {
font-size: 16px;
font-weight: bold;
display: block;
margin-bottom: 5px;
}
.user-email {
color: #666;
font-size: 14px;
}
.login-prompt {
display: flex;
justify-content: space-between;
align-items: center;
}
.action-section button {
margin-bottom: 10px;
width: 100%;
}
</style>
小结
今天我们学习了:
- ✅ 网络请求的基础用法和封装
- ✅ 本地存储的同步和异步操作
- ✅ 设备信息和网络状态获取
- ✅ 位置信息的获取和处理
- ✅ 实战案例:用户管理页面
API使用要点:
- 合理封装请求工具提高开发效率
- 注意错误处理和用户体验
- 谨慎使用设备权限,做好权限申请
- 本地存储要考虑数据安全和过期
下一篇预告
下一篇我们将学习《自定义组件开发 - 封装你自己的组件》,学习如何创建可复用的组件。
API是连接应用与外界的桥梁,掌握了API的使用,你的应用就能拥有无限可能!