2020-04-08 | miniApp | UNLOCK

小程序云开发 —— taro

小程序模版

区别于普通的小程序:

  • 目录结构 官网模版
  • 使用微信开发者工具调试项目,请将项目 整个文件夹 作为运行目录。
  • project.config.jsonminiprogramRoot 的启动目录设置为 client/dist/
  • cloudfunctionRoot 设置目录为 cloud/functions/
  • 入口文件src/app.jsx 添加
   componentDidMount() {
       wx.cloud.init({
         env: "环境ID"
       });
   }

数据库

云开发提供了一个 JSON 数据库,一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。

建立数据库步骤:

  • 小程序内点击云开发 - 数据库
  • 新建一个集合(表)
  • 对应集合中添加需要的字段,JSON 格式。
  • 索引字段默认为 _id, 使用系统自动生成的 id

云函数的开发和调试

  1. 建立好云函数文件夹后,打开开发者开发工具,右键云函数文件夹,新建 Node.js 云函数。会自动生成一个文件夹,并且同时部署到远程

image

文件结构如下

├── sum                         云函数名
│   ├── config.json             配置文件
│   ├── package.json            依赖包
│   ├── index.js                云函数主体

  1. 修改新建的云函数

    一开始发现怎么改 index.js 都不起作用,原来是修改后远程的云函数并未自动更新,解决方案:

  • 修改后直接上传和部署:每次修改都得重新部署,麻烦
  • 云函数本地调试 官网文档

image

本地调试云函数首先得安装依赖 npm i,同时监听文件的更改,部署到云端不上传 node_modules

云函数的注意事项和总结

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command

exports.main = async (event, context) => {
  try {
    return await db
      .collection('todos')
      .where({
        _id: _.in(event.ids),
      })
      .remove()
  } catch (e) {
    console.error(e)
  }
}
  • 异步问题:可以使用 generator 语法
  • 批量处理多条数据可以使用 where 语句,搭配 command 中的方法
  • node_modules: 本地调试和部署到云端,前者需要,后者不需要
  • 调用云函数: wx.cloud.callFunction ,要根据返回的 result 数据判断是是否执行成功,云函数执行失败,返回的数据可能不包含 result 字段或者为 null

具体实例

获取 oppenid 和 unionid

  • 云函数
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }
}

获取用户信息

  • 云函数
const cloud = require('wx-server-sdk')
cloud.init({})

exports.main = async (event, context) => {
  const res = await cloud.getOpenData({
    list: [event.cloudID], // CloudID 字符串列表
  })
  return res.list
}
  • 小程序端
<button
  type="primary"
  openType="getUserInfo"
  onGetUserInfo="{this.getUserInfo}"
  className="marginTop"
>
  获取微信信息
</button>
getUserInfo = function (e) {
  wx.cloud.callFunction({
    name: 'getUserInfo',
    data: {
      cloudID: e.detail.cloudID,
    },
    success: (res) => {
      console.log(res)
    },
  })
}

  • 云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async (event, context) => {
  const {
    description = '',
    done = '',
    date = new Date(),
    tags = [],
    title = '',
  } = event
  try {
    // todos 数据库中的表名
    const res = await db.collection('todos').add({
      // data 字段表示需新增的 JSON 数据
      data: {
        description,
        done,
        date,
        tags,
        title,
      },
    })
    return res
  } catch (e) {
    console.error(e)
  }
}
  • 小程序
wx.cloud
  .callFunction({
    name: 'addTodo',
    data: {
      description,
      done,
      date,
      tags,
      title,
    },
  })
  .then((res) => {
    if (res && res.result && res.result._id) {
      console.log('success')
    } else {
      console.log('添加失败')
    }
  })

  • 云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
  try {
    // where 删除所有符合条件的id
    return await db
      .collection('todos')
      .where({
        _id: _.in(event.ids),
      })
      .remove()
  } catch (e) {
    console.error(e)
  }
}
  • 小程序端调用
wx.cloud
  .callFunction({
    name: 'delTodo',
    data: { ids: this.state.checkedList },
  })
  .then((res) => {
    if (res && res.result && res.result.stats && res.result.stats.removed > 0) {
      console.log('delete success')
    }
  })

  • 云函数
// 云函数入口函数
exports.main = async (event, context) => {
  try {
    const {
      description = '',
      done = '',
      date = new Date(),
      tags = [],
      title = '',
      id = '',
    } = event
    // 根据 id 去修改数据
    const res = await db.collection('todos').doc(id).update({
      data: {
        description,
        done,
        date,
        tags,
        title,
      },
    })
    return res
  } catch (error) {
    console.log(error)
  }
}
  • 小程序端
    类似于增,需要多传一个参数 id

  • 云函数
    云函数每次限制查出 100 条数据,要查出所有的数据,需要循环的去查
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const MAX_LIMIT = 100
exports.main = async (event, context) => {
  const _id = event.id
  if (_id) {
    // 单条查询
    const res = await db
      .collection('todos')
      .where({
        _id,
      })
      .get()
    return res
  } else {
    // 先取出集合记录总数
    const countResult = await db.collection('todos').count()
    const total = countResult.total
    // 计算需分几次取
    const batchTimes = Math.ceil(total / 100)
    // 承载所有读操作的 promise 的数组
    const tasks = []
    for (let i = 0; i < batchTimes; i++) {
      const promise = db
        .collection('todos')
        .skip(i * MAX_LIMIT)
        .limit(MAX_LIMIT)
        .get()
      tasks.push(promise)
    }
    // 等待所有
    return (await Promise.all(tasks)).reduce((acc, cur) => ({
      data: acc.data.concat(cur.data),
      errMsg: acc.errMsg,
    }))
  }
}

上传文件 - 图片

  • 云函数
const cloud = require('wx-server-sdk')
const fs = require('fs')
cloud.init()
exports.main = async (event, context) => {
  const fileStream = fs.createReadStream(event.filePath)
  return await cloud.uploadFile({
    cloudPath: event.cloudPath,
    fileContent: fileStream,
  })
}
  • 小程序端
wx.chooseImage({
  count: 2,
  sizeType: ['original', 'compressed'],
  sourceType: ['album', 'camera'],
  success: function (res) {
    const filePath = res.tempFilePaths[0]
    // 上传图片
    var timestamp = Date.parse(new Date())
    // test_img/ 文件夹路径
    const cloudPath = 'test_img/' + timestamp + filePath.match(/\.[^.]+?$/)[0]
    wx.cloud.uploadFile({
      cloudPath,
      filePath,
      success: (data) => {
        console.log(data)
      },
      fail: () => {
        console.log('faile')
      },
      complete: () => {
        console.log('complete')
      },
    })
  },
  fail: (e) => {
    console.error(e)
  },
})