乐趣区

小程序云开发攻略解决最棘手的问题

背景

最近小程序非常的火, 应公司业务发展要求, 开发维护了几款小程序, 公司开发的小程序都是由后端提供的接口, 开发繁琐而复杂, 直到小程序出现了云开发, 仔细研读了文档之后, 欣喜不已, 于是我着手开发了本人的第一款小程序

  • 小程序云开发教程地址 点我查看 >>

分析

云开发为开发者提供完整的原生云端支持和微信服务支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开发,即可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。

优势

  • 无需自建服务器, 数据库, 无需自建存储和 CDN
  • 数据库模型很简单, 就是一个 json 形式的对象格式
  • 调用服务端云函数自动获取 openid, 再也没有繁琐的授权登陆流程了, 只要进入小程序就是登陆状态, 体验真的好
  • 开发迅速, 只需要前端就能搞定所有开发工作

需要解决的问题

数据库切换问题

使用过云开发的人都发现云开发切换数据库环境是最头疼的, 如果手动去切换容易搞错, 不小心在当前环境修改了线上数据库数据

直到官方出了这个函数问题也就迎刃而解

cloud.updateConfig({env: ENV === 'local' ? 'dev-aqijb' : ENV});

我使用的是服务端云开发功能, 为什么要这样判断, 因为在开发工具中 ENV = ‘local’, 所以这么判断一下, 保证开发工具中使用的是测试环境数据库

使用 taro 多端开发框架, 借助于 webpack, 还可以通过 process.env.NODE_ENV 值区分当前代码开发环境

await Taro.cloud.init({env: `${process.env.NODE_ENV === 'development' ? 'dev-aqijb' : 'pro-hljv7'}`
        /* env: 'pro-hljv7' */
      });

这样可以保证开发环境和线上环境可以使用对应环境的数据库

数据库字段定义问题

因为 JS 是弱类型语言, 不能像 typescript 那样静态定义变量类型, 这样添加到数据库的字段数量和字段类型都无法控制

我不想用 typescript, 能不能实现这样的功能呢, 可以用 superstruct 库来实现这个功能

  • superstruct git 地址 点我查看 >>

详细使用案例见下方代码

函数文件太多的问题

官方和他人教程的例子都是一个文件对应一个云函数, 通过开发体验我发现这样做并不好, 当项目有多个表的时候, 找个函数文件真的太难了
我们可以将一个表的增删改查函数全部写入一个文件中

教程: 首先每个云函数文件中 package.json 引入 superstruct

{
  "dependencies": {
    "wx-server-sdk": "latest",
    "superstruct": "latest"
  }
}

以下代码是一个完整的云函数例子

const cloud = require('wx-server-sdk');
const {struct, superstruct} = require('superstruct');
cloud.init();
// 小区信息
const Model = () => {const db = cloud.database();
  const _ = db.command;
  const collection = db.collection('address');
  return {async add(data) {
      try {
        data = struct({
          name: 'string', // 名字
          phone: 'string',
          unit: 'number', // 楼单元号
          doorNumber: 'string', // 门号
          communityId: 'string', // 小区 id
          _openid: 'string' // 用户的 id
          //isDefault: 'boolean' // 是否默认地址
        })(data);
      } catch (e) {const { path, value, type} = e;
        const key = path[0];

        if (value === undefined) {const error = new Error(`${key}_required`);
          error.attribute = key;
          throw error;
        }

        if (type === undefined) {const error = new Error(`attribute_${key}_unknown`);
          error.attribute = key;
          throw error;
        }
        const error = new Error(`${key}_invalid`);
        error.attribute = key;
        error.value = value;
        throw error;
      }
      let res = await this.getList({_openid: data._openid});
      if (res.data.length >= 1) {return { msg: '当前只支持保存一个地址'};
      }
      res = await collection.add({
        data,
        createTime: db.serverDate(),
        updateTime: db.serverDate()});
      return res;
    },
    async getAdressById({_openid, _id}) {
      const user = await collection
        .where({
          _openid,
          _id: _.eq(_id)
        })
        .get();
      return user;
    },
    // 更新指定的 id 先判断手机号修改没, 没修改直接就改数据, 修改过判断一下库中有没有这条数据
    async update(data) {// 更新表的操作},
    // 删除指定 id 的 shop
    async remove({_id, _openid}) {// 删除表的操作},
    /**
     * 获取商列表
     * @param {*} option {category 类别, pagenum 页码}
     */
    async getList({_openid}) {
      const shopList = await collection
        .where({_openid})
        .get();

      return shopList;
    }
  };
};

exports.main = async (event, context) => {const { func, data} = event;
  const {ENV, OPENID} = cloud.getWXContext();
  // 更新默认配置,将默认访问环境设为当前云函数所在环境
  console.log('ENV', ENV);
  cloud.updateConfig({env: ENV === 'local' ? 'dev-aqijb' : ENV});
  let res = await Model()[func]({...data, _openid: OPENID});
  return {
    ENV,
    data: res
  };
};

函数使用方式

wx.cloud.callFunction({
      'address', // 云函数文件名
      data: {
        func: 'add', // 云函数中定义的方法
        data: {} // 需要上传的数据}
    });

图片 视频等文件

直接打开云开发控制台选择存储直接上传文件, 复制 url 地址就可以放到代码中使用了

扫码体验我的小程序:

退出移动版