第18集:uni-app 云开发

章节概览

在本章节中,我们将学习 uni-app 的云开发能力,这是 uni-app 提供的一项强大功能,允许开发者直接在前端代码中调用后端服务,无需搭建和维护传统的后端服务器。通过本章节的学习,您将掌握云函数、云数据库和云存储的使用方法,并能够实现完整的后端服务。

核心知识点

1. 云开发概述

uni-app 云开发是基于腾讯云开发(Tencent CloudBase)提供的 BaaS(Backend as a Service)服务,为开发者提供了以下核心能力:

  • 云函数:在云端运行的 JavaScript 代码,无需管理服务器
  • 云数据库:一个文档型数据库,支持丰富的查询能力
  • 云存储:用于存储文件,支持图片、视频等各种类型的文件

2. 云函数

云函数是在云端运行的 JavaScript 代码,具有以下特点:

  • 无需管理服务器,按需执行
  • 支持 Node.js 运行环境
  • 可以调用腾讯云的各种服务
  • 与前端代码无缝集成

3. 云数据库

云数据库是一个文档型数据库,具有以下特点:

  • 支持 JSON 格式存储数据
  • 提供丰富的查询能力
  • 支持事务操作
  • 与云函数无缝集成

4. 云存储

云存储用于存储文件,具有以下特点:

  • 支持各种类型的文件存储
  • 提供文件上传和下载功能
  • 支持文件访问权限控制
  • 与云函数和云数据库无缝集成

实用案例

实现用户注册和登录功能

我们将使用云开发能力实现一个完整的用户注册和登录功能,包括:

  1. 创建云函数处理用户注册和登录请求
  2. 使用云数据库存储用户信息
  3. 实现前端调用云函数的逻辑

代码示例

1. 初始化云开发环境

首先,我们需要在 uni-app 项目中初始化云开发环境:

// main.js
import Vue from 'vue'
import App from './App.vue'

// 初始化云开发
uniCloud.init({
  provider: 'tencent',
  spaceId: 'your-space-id',
  clientSecret: 'your-client-secret',
  env: 'your-env-id'
})

Vue.config.productionTip = false

App.mpType = 'app'

const app = new Vue({
  ...App
})
app.$mount()

2. 创建云函数

创建用户注册云函数

// cloudfunctions/register/index.js
'use strict';

exports.main = async (event, context) => {
  const { username, password, email } = event;
  
  // 获取数据库引用
  const db = uniCloud.database();
  const usersCollection = db.collection('users');
  
  // 检查用户是否已存在
  const existingUser = await usersCollection.where({ username }).get();
  if (existingUser.data.length > 0) {
    return {
      code: 400,
      message: '用户名已存在'
    };
  }
  
  // 创建新用户
  const result = await usersCollection.add({
    username,
    password: md5(password), // 实际应用中应该使用更安全的加密方式
    email,
    createTime: new Date()
  });
  
  return {
    code: 200,
    message: '注册成功',
    data: {
      userId: result.id
    }
  };
};

// 简单的 md5 加密函数(实际应用中应该使用更安全的加密方式)
function md5(str) {
  const crypto = require('crypto');
  return crypto.createHash('md5').update(str).digest('hex');
}

创建用户登录云函数

// cloudfunctions/login/index.js
'use strict';

exports.main = async (event, context) => {
  const { username, password } = event;
  
  // 获取数据库引用
  const db = uniCloud.database();
  const usersCollection = db.collection('users');
  
  // 查找用户
  const user = await usersCollection.where({ 
    username, 
    password: md5(password) 
  }).get();
  
  if (user.data.length === 0) {
    return {
      code: 401,
      message: '用户名或密码错误'
    };
  }
  
  // 生成 token(实际应用中应该使用更安全的 token 生成方式)
  const token = generateToken(user.data[0]._id);
  
  return {
    code: 200,
    message: '登录成功',
    data: {
      user: {
        id: user.data[0]._id,
        username: user.data[0].username,
        email: user.data[0].email
      },
      token
    }
  };
};

// 简单的 md5 加密函数
function md5(str) {
  const crypto = require('crypto');
  return crypto.createHash('md5').update(str).digest('hex');
}

// 简单的 token 生成函数
function generateToken(userId) {
  const crypto = require('crypto');
  return crypto.createHash('sha256').update(userId + Date.now()).digest('hex');
}

3. 前端调用云函数

<template>
  <view class="container">
    <view class="form">
      <view class="form-item">
        <text>用户名:</text>
        <input v-model="username" placeholder="请输入用户名" />
      </view>
      <view class="form-item">
        <text>密码:</text>
        <input v-model="password" type="password" placeholder="请输入密码" />
      </view>
      <view class="form-item" v-if="isRegister">
        <text>邮箱:</text>
        <input v-model="email" placeholder="请输入邮箱" />
      </view>
      <button @click="handleSubmit" :loading="loading">{{ isRegister ? '注册' : '登录' }}</button>
      <text @click="toggleMode" class="toggle-mode">{{ isRegister ? '已有账号?去登录' : '没有账号?去注册' }}</text>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      isRegister: true,
      username: '',
      password: '',
      email: '',
      loading: false
    };
  },
  methods: {
    toggleMode() {
      this.isRegister = !this.isRegister;
    },
    async handleSubmit() {
      if (!this.username || !this.password) {
        uni.showToast({ title: '请填写用户名和密码', icon: 'none' });
        return;
      }
      
      if (this.isRegister && !this.email) {
        uni.showToast({ title: '请填写邮箱', icon: 'none' });
        return;
      }
      
      this.loading = true;
      
      try {
        const result = await uniCloud.callFunction({
          name: this.isRegister ? 'register' : 'login',
          data: {
            username: this.username,
            password: this.password,
            email: this.email
          }
        });
        
        if (result.result.code === 200) {
          uni.showToast({ title: result.result.message, icon: 'success' });
          
          // 存储用户信息
          if (!this.isRegister) {
            uni.setStorageSync('userInfo', result.result.data.user);
            uni.setStorageSync('token', result.result.data.token);
            // 跳转到首页
            uni.switchTab({ url: '/pages/index/index' });
          } else {
            // 注册成功后自动切换到登录
            this.isRegister = false;
          }
        } else {
          uni.showToast({ title: result.result.message, icon: 'none' });
        }
      } catch (error) {
        console.error('调用云函数失败:', error);
        uni.showToast({ title: '网络错误,请稍后重试', icon: 'none' });
      } finally {
        this.loading = false;
      }
    }
  }
};
</script>

<style scoped>
.container {
  padding: 20rpx;
}

.form {
  background-color: #fff;
  border-radius: 10rpx;
  padding: 30rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}

.form-item {
  display: flex;
  align-items: center;
  margin-bottom: 30rpx;
}

.form-item text {
  width: 150rpx;
  font-size: 30rpx;
}

.form-item input {
  flex: 1;
  height: 70rpx;
  border: 1rpx solid #e5e5e5;
  border-radius: 5rpx;
  padding: 0 20rpx;
  font-size: 30rpx;
}

button {
  width: 100%;
  height: 80rpx;
  background-color: #007aff;
  color: #fff;
  font-size: 32rpx;
  border-radius: 5rpx;
  margin-bottom: 20rpx;
}

.toggle-mode {
  display: block;
  text-align: center;
  color: #007aff;
  font-size: 28rpx;
}
</style>

4. 使用云数据库

// 获取数据库引用
const db = uniCloud.database();

// 查询数据
export async function getUsers() {
  const result = await db.collection('users').get();
  return result.data;
}

// 添加数据
export async function addUser(userInfo) {
  const result = await db.collection('users').add(userInfo);
  return result;
}

// 更新数据
export async function updateUser(userId, userInfo) {
  const result = await db.collection('users').doc(userId).update(userInfo);
  return result;
}

// 删除数据
export async function deleteUser(userId) {
  const result = await db.collection('users').doc(userId).remove();
  return result;
}

// 条件查询
export async function getUsersByCondition(condition) {
  const result = await db.collection('users').where(condition).get();
  return result.data;
}

5. 使用云存储

// 上传文件
export async function uploadFile(filePath, cloudPath) {
  const result = await uniCloud.uploadFile({
    filePath: filePath,
    cloudPath: cloudPath
  });
  return result;
}

// 下载文件
export async function downloadFile(fileID) {
  const result = await uniCloud.downloadFile({
    fileID: fileID
  });
  return result;
}

// 删除文件
export async function deleteFile(fileList) {
  const result = await uniCloud.deleteFile({
    fileList: fileList
  });
  return result;
}

// 获取文件信息
export async function getFileInfo(fileList) {
  const result = await uniCloud.getFileInfo({
    fileList: fileList
  });
  return result;
}

常见问题与解决方案

1. 云函数调用失败

问题:调用云函数时返回错误

解决方案

  • 检查云函数是否已部署
  • 检查云函数代码是否有语法错误
  • 检查云函数的入参是否正确
  • 检查云开发环境配置是否正确

2. 云数据库操作失败

问题:云数据库操作返回错误

解决方案

  • 检查数据库权限配置
  • 检查数据格式是否正确
  • 检查查询条件是否合法
  • 检查集合是否存在

3. 云存储上传失败

问题:文件上传到云存储失败

解决方案

  • 检查文件大小是否超过限制
  • 检查文件格式是否支持
  • 检查云存储权限配置
  • 检查网络连接是否正常

学习总结

通过本章节的学习,您已经掌握了以下内容:

  1. 云开发概述:了解了 uni-app 云开发的基本概念和核心能力
  2. 云函数:学会了如何创建和调用云函数,实现后端业务逻辑
  3. 云数据库:掌握了云数据库的基本操作,包括增删改查
  4. 云存储:学会了如何使用云存储上传、下载和管理文件
  5. 实战应用:实现了完整的用户注册和登录功能

云开发为 uni-app 开发者提供了一种简单、高效的后端服务实现方式,无需搭建和维护传统的后端服务器,大大降低了开发成本和技术门槛。通过云开发,您可以将更多精力放在前端业务逻辑和用户体验上,快速构建完整的应用。

在实际项目中,您可以根据具体需求,灵活使用云开发的各项能力,实现各种复杂的后端服务。同时,您也可以结合传统的后端服务,构建更加灵活和强大的应用架构。

« 上一篇 uni-app 插件开发 下一篇 » uni-app 大型应用架构