uni-app 微信云开发小程序

x33g5p2x  于2021-08-23 转载在 uni-app  
字(7.0k)|赞(0)|评价(0)|浏览(614)

前言

微信云开发是微信小程序推出来挺久的功能了,最近看了下云开发文档,准备动手写个小程序练练手。

前端模块使用以前写过的一个用uni-app搭建的一个项目,云开发模块就是重新搭建。

1、创建微信小程序

首先在微信开发工具创建小程序,填入你的appid,后端服务选择小程序云开发。

创建完毕,目录结构如下:

cloudfunctions 是云函数目录,miniprogram是小程序前端模块。

因为前端模块我要使用uni-app,所以得进行改造。
miniprogram目录删除,把 vue-cli 创建 uni-app 项目代码复制进来,不懂怎么创建uni-app项目的点这里

安装依赖npm i,运行npm run dev:mp-weixin,最终目录如下:

2、重新指定小程序前端模块目录

修改uni-app的打包输出路径:
dev 模式编译出的各平台代码存放于根目录下的 /dist/dev/目录下,
build 模式编译出的各平台代码存放于根目录下的 /dist/build/ 目录下,
对于要固定的小程序目录很不友好,我们得固定输出目录。

修改package.jsonscriptsdev:mp-weixinbuild:mp-weixin命令:

"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin UNI_OUTPUT_DIR=dist/build/mp-weixin vue-cli-service uni-build",
     
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin UNI_OUTPUT_DIR=dist/build/mp-weixin vue-cli-service uni-build --watch",
    

添加UNI_OUTPUT_DIR=dist/build/mp-weixin,指定输出目录为dist/build/mp-weixin

再修改project.config.json文件,把前端模块指定到dist/build/mp-weixin

 "miniprogramRoot": "dist/build/mp-weixin/",

修改完成,打开微信开发工具,小程序就可以运行了。

3、云开发

初始化

在云开发设置面板,新建个环境,后面的env取环境ID

小程序端

在src/main.js 添加初始化方法

wx.cloud.init({
  env: '5175aa',  //环境
  traceUser: true, //是否在将用户访问记录到用户管理中,在控制台中可见
})

云函数端

// 初始化 cloud
cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  // env: cloud.DYNAMIC_CURRENT_ENV
  env: '5175aa'
})

4、编写第一个云函数

云函数

我们把cloudfunctions文件夹下的文件都删除,新建个main云函数:

config.json
{
  "permissions": {
    "openapi": []
  }
}


package.json
{
  "name": "echo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "wx-server-sdk": "~2.4.0"
  }
}


index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  // env: cloud.DYNAMIC_CURRENT_ENV
  env: '5175aa'
})

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()

  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }
}

一个云函数就完成了,我们现在可以进行本地调试,或者上传到云端部署。

本地调试步骤

需要进入cloudfunctions/main目录下,安装依赖 npm i 再右键选择开启云函数本地调试

上传到云端部署

小程序端调用

wx.cloud.callFunction({
  // 云函数名称
  name: 'mian',
  // 传给云函数的参数
  data: {
    a: 1,
    b: 2,
  },
  success: function(res) {
    console.log(res.result.sum) // 3
  },
  fail: console.error
})

当然,Promise 风格的调用也是支持的:

wx.cloud.callFunction({
  // 云函数名称
  name: 'main',
  // 传给云函数的参数
  data: {
    a: 1,
    b: 2,
  },
})
.then(res => {
  console.log(res.result) // 3
})
.catch(console.error)

请求成功。

5、云函数路由优化tcb-router

云函数也有不少缺点:

  • 一个微信小程序只能创建50个云函数,不能满足复杂业务需求。
  • 每个云函数都都需要维护一份package.json

所以我们需要用tcb-router进行优化,tcb-router是一个koa风格的云函数路由库。

安装tcb-router

cloudfunctions/main目录下

npm i tcb-router -S

cloudfunctions/main/index.js修改成:

const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router')
cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  // env: cloud.DYNAMIC_CURRENT_ENV
  env: '5175aa'
})

// 云函数入口函数
exports.main = async(event, context) => {
  const app = new TcbRouter({
    event
  })
 //全局中间件
  app.use(async(ctx, next) => {
    console.log('进入全局中间件')
    await next()
    console.log('退出全局中间件')
  })
  app.router('add', async(ctx, next) => {
    ctx.body = {
      data: '新增成功'
    }
  })	
  app.router('movie', async(ctx, next) => {
    ctx.body = {
      data: '输出'
    }
  })
  return app.serve()
}

小程序端调用

   wx.cloud.callFunction({
      name: 'main',
      data: {
        $url: 'add'
      },
    }).then((res) => {
      console.log(res)
    })
    
    wx.cloud.callFunction({
      name: 'main',
      data: {
        $url: 'movie'
      },
    }).then((res) => {
      console.log(res)
    })

云函数模块化

我们可以把路由的实现抽离成一个个js文件:

cloudfunctions/main下新建common/index.js

exports.login = async (ctx, next) => {
  console.log(ctx.cloud)
  console.log(ctx.db)
  ctx.body = {
     data: '输出'
  }
}

cloudfunctions/main/index.js中,用require导入,并且可以把clouddb对象挂载到ctx对象下,在实现模块就可以使用ctx.cloudctx.db调用对象

// 云函数模板
// 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署”

const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router');

// 公共模块
const common = require('./common/index')

// 初始化 cloud
cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  // env: cloud.DYNAMIC_CURRENT_ENV
  env: '5175aa'
})
const db = cloud.database()

exports.main = async (event, context) => {
  const app = new TcbRouter({event});
  // app.use 表示该中间件会适用于所有的路由
  app.use(async (ctx, next) => {
    ctx.db = db;
    ctx.cloud = cloud;
    console.log('进入全局中间件')
    await next()
    console.log('退出全局中间件')
  });

  //授权登录
  app.router('/login', common.login)


  return app.serve();
}

6、全局异常捕捉中间件

到现在为止,可以进行应用开发了,但使用过koa的人都知道,我们还差个全局异常捕捉中间件,来统一处理服务器报错问题。

新建个工具类utils/index.js

module.exports = {
  // 手动报错
  throwError(code = 400, msg = '服务器错误') {
    const err = new Error(msg);
    err.code = code;
    err.msg = msg;
    throw err;
  },
};

cloudfunctions/main/index.js

const utils = require('./utils/index')

// app.use 表示该中间件会适用于所有的路由
  app.use(async (ctx, next) => {
    ctx.db = db;
    ctx.cloud = cloud;
    ctx.utils=utils  //挂载工具类
    try {
      await next();  //在下个环节报错就抛出错误
    } catch (err) {
      // 手动抛出异常 throwError函数触发
      if (err.msg) {
        ctx.body = {
          code: err.code,
          data: '',
          msg: err.msg,
        };
      } else {
      //自动报错
        ctx.body = {
          code: 500,
          data: '',
          msg: '服务器内部错误:' + err,
        };
      }

    }
  });

测试

手动抛出异常

exports.login = async (ctx, next) => {

  ctx.uilts.throwError('500','手动抛出异常')
  
  ctx.body = {
     data: '输出'
  }
}

返回成功

内部错误异常

exports.login = async (ctx, next) => {

  console.log(a);  //错误  不存在a变量
  
  ctx.body = {
     data: '输出'
  }
}

返回成功

7、数据库的增、删、查、改

云开发的数据库,前端和云函数都可以进行操作,但在前端进行数据库操作有比较大的缺点:

  • 请求列表数据,直接操作数据库每次只能返回20条,云函数的话可以返回100条;
  • 还有就是直接调用数据库,所有的增删改查运算操作都是在手机本地运行的,数据量大的话,会耗用用户流量,而云函数则是在微信服务器上运算的。
  • 安全问题,可能会被恶意攻击

所以还是推荐在云函数进行数据库操作。

初始化

在云开发面板,新建个集合user(表)

在云函数初始化

const db = cloud.database()

插入数据

db.collection('user').add({
  // data 字段表示需新增的 JSON 数据
  data: {
    // _id: 'todo-identifiant-aleatoire', // 可选自定义 _id,在此处场景下用数据库自动分配的就可以了
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    // 为待办事项添加一个地理位置(113°E,23°N)
    location: new db.Geo.Point(113, 23),
    done: false
  },
  success: function(res) {
    // res 是一个对象,其中有 _id 字段标记刚创建的记录的 id
    console.log(res)
  }
})

获取一个记录的数据

db.collection('user').doc('todo-identifiant-aleatoire').get().then(res => {
  // res.data 包含该记录的数据
  console.log(res.data)
})

获取多个记录的数据

我们也可以一次性获取多条记录。通过调用集合上的 where 方法可以指定查询条件,再调用 get 方法即可只返回满足指定查询条件的记录,比如获取用户的所有未完成的待办事项:

db.collection('user').where({
  _openid: 'user-open-id',
  done: false
})
.get({
  success: function(res) {
    // res.data 是包含以上定义的两条记录的数组
    console.log(res.data)
  }
})

更新数据

db.collection('user').doc('todo-identifiant-aleatoire').update({
  // data 传入需要局部更新的数据
  data: {
    // 表示将 done 字段置为 true
    done: true
  },
  success: function(res) {
    console.log(res.data)
  }
})

删除一条记录

db.collection('user').doc('todo-identifiant-aleatoire').remove({
  success: function(res) {
    console.log(res.data)
  }
})

更多用法可以去查看微信官方文档

8、小程序端请求云函数的封装

为了统一管理和方便调用,我们可以封装下小程序端请求云函数的方法

新建文件 scr/config/http.js

const http = function (param) {
  const isHideToast = param.isHideToast || false;  //是否隐藏错误提示
  return new Promise((resolve, reject) => {
    wx.cloud.callFunction({
      // 要调用的云函数名称
      name: param.moduleName || "main",
      // 传递给云函数的参数
      data: {
        $url:param.url,
        ...param.data
      }
    }).then(res => {
      if (res.result) {
        if (res.result.code === 200) {
          resolve(res.result.data);
        } else {
          if (isHideToast) {
            uni.showToast({
              title: res.result.data.msg || '返回失败',
              duration: 1500,
              icon:'none'
            });
          }
          reject(res.result.data);
        }
      } else {
        uni.showToast({
          title: 'url不存在',
          duration: 1500,
          icon:'none'
        });
      }

    })
  })
}

export default http

再把http对象挂载到vue

src/main.js下,添加

import http from './api/http'
Vue.prototype.$http = http

在小程序端调用:

this.$http({
    url: "/login",  
    data: {}
}).then(res => {
    console.log(res)
})

原文地址:https://juejin.cn/post/6936855461895340068

相关文章