【云+社区年度征文】小程序·云开发综合提升篇

代码地址 : https://gitee.com/mtcarpenter/wechat-cloud.git

1 聊下云开发

1.1 从企业的角度

什么是小程序云开发,从前端解决后端的活。18 年以为很多大公司减员,小公司关闭,到底是互联网的寒冬时期,还是互联网换新时期,我认为是后者。小程序开发周期一般都相对比比较短,如果一个企业还是一个团队去开发一个博客、资讯、新闻这类的产品,支出的成本是还是相对大比较大的。其中可能大部分时间我们都用在联调这个事上了,代码的测试,数据校验,很大时间浪费在前后端相互对接等待等。像小程序这种无服务在以后会越来越多,只管写接口、写逻辑就好。总得来说,虽然你管的东西越来越少,但开发效率却越来越高,开发出来的轻应用、小程序却是具备高性能、高可用、高扩展的特性, 开发人员的较少必定资金和人力的需求可谓大大节省。

1.2 从开发者的角度

小程序云开发无疑是让前端开发者从前端开发到全栈开发,大前端目前是行业一个非常流行的趋势,这几年全栈的火爆主要有业务场景相对比较多,像之前那样前端只写静态页面,数据和模板都是通过后端来渲染,无法满足业务了,所以都出现前后端开始分离,前后两端是通过 API 的请求和返回去做一个数据交互,前端工程师比较贴近客户,所以他更能够去理解到一些业务逻辑,无论是业务的前台或是后台,交给前端工程师来做是更好的,所以现在很多公司选择使用 node.js ,做中台服务。企业的需要前端干的事越多,我们学习的东西就越多,掌握的技能就越多,如果在开发小程序的前端人员,在日常的闲暇时间了解下云开发,也是对自己后期做 node.js 做一个小小的铺垫,云开发无需自己在对环境的搭建,也能让我们不再额外购买服务器就能开发自己一个线上的作品。

1.3 什么是小程序云开发?

云开发是微信团队和腾讯云团队共同研发的一套小程序基础能力,简言之就是:云能力将会成为小程序的基础能力。

小程序云开发目前提供三大基础能力支持:

  • 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码
  • 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 数据库
  • 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理

小程序操作数据库可以在小程序端和服务端操作数据库,小程序本来相对于小,如果我们代码全部放在小程序端来操作,会占用不少的内存,另一方面就是直接在页面操作数据库安全性也无法得到保障,因此我们在对数据的操作就需要通过服务端操作,目前服务端要操作小程序我们就得通过云函数,云函数作为服务层对数据交互,在一定的层面保证了数据的安全性。

1.4 云开发项目搭建

1.4.1 准备工作

已经申请小程序,获取小程序 AppID 在小程序管理后台中, 设置的开发设置 下可以获取微信小程序 AppID 。

1.4.2 新建项目

进入云开发控制面板入口

  • 运营分析:资源使用是日常对云开发资源的使用的统计、用户访问是用户在小程序授权用户信息、监控图标是三大基础能力的请求统计。
  • 右上角设置:小程序云开发支持两个环境,在设置可以切换环境,数据库、存储、云函数根据环境显示当前的资源信息。

将所有没有带云开发标识的文件夹创建并部署,带有云开发标识的才能调用服务器。

如果你之前没有玩过云开发,在这里上传云函数之后,就可以试着跟着官方的 demo 操作下,官方的数据库跟我们的 mongodb 数据库类似,把 demo 提供的功能练习下:

官方文档: https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html

如果想要项目重命名,文件夹和 project.config.json 对应即可,如果无法直接修改就需要关闭项目修改了在打开项目。

这里我们已经不需要官方的模板,将其官方给的图片和模板删除。

2 灵活的自定义组件(插槽,behaviors,授权,自定义组件样式)

2.1 插槽(slot)

  • 使用场景
    小程序中多处使用同一个自定义组件,组件中部分样式灵活显示、隐藏。
  • 使用方法
    slot 标签定义在小程序自定义组件中,根据外部传入标签控制,动态的设置自定义组件的样式,在实际开发中提高了组件的复用性。
  • 示例代码如下:

(1)封装组件,components/title-bar

<!-- 自定义组件,添加插槽,插槽的name一定要设置,使用时name要相同-->
<!-- components/title-bar/index.wxml -->
<view class='container'>
  <view class="left-container">
    <view class='line'></view>
    <text class='text'>{{title}}</text>
  </view>
  <view class="right-container">
    <!-- slot 插槽 -->
    <slot name="more"></slot>
  </view>
</view>

(2)引入组件

{
  "usingComponents": {
    "title-comp": "/components/title-bar/index"
  }
}

(3)使用组件

  <!-- 卡槽 -->
  <title-comp title="没有插槽"></title-comp>
  <title-comp title="使用插槽">
    <!--里面的<text>标签就是传递给插槽的 text 中 slot 的值需跟组件的 name 保持一致-->
    <text class="more" slot="more">更多</text>
  </title-comp>

(4)运行效果

2.2 behaviors

  • 使用场景
    behaviors 是用于组件间代码共享的特性,例如商品基本信息在多处展示,布局不同,且有属性、数据、生命周期函数和方法。
  • 使用方法

新建 behavior.js(名字可自定义) 文件中有共享的 properties ,data ,methods 等。在组件中引入并继承即可。

示例代码如下:

(1)新建 behavior.js 文件中有共享的 properties ,data,methods 等

module.exports = Behavior({
    <!--共享属性-->
    properties: {
      product: { // 属性名
        type: Object,
        // value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个
        observer: function (newValue, oldValue,path) {
          console.log(newValue)
          console.log(oldValue)
          console.log(path)
        }
      }
    },
    //共享数据
    data:{

    },
   // 共享方法
    methods: {
      // 商品详情
      productDetails: function () {
        //  triggerEvent  组件间通信与事件 
        this.triggerEvent("productDetails", {
          id: this.data.product.id
        }, {})
      }
      
    }
  })

组件间通信与事件:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html

(2)封装组件,components/product-column

<!-- components/product-column/index.wxml -->
<view class='container'>
    <view class="left-container">
        <view class='line'></view>
        <text class='text' bind:tap="productDetails">{{product.name}}</text>
    </view>
    <view class="right-container">
        <text class="text">价格:¥{{product.price}}</text>
    </view>
</view>
// components/product-column/index.js
<!--引入behavior.js-->
let productBev = require("../behaviors/product.js")
Component({
 <!--继承 behavior.js里面的 properties,data,methods-->
  behaviors: [productBev],
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

(3)封装组件,components/product-row

<!-- components/product-row/index.wxml -->
<view class='container'>
    <view class="left-container">
        <view class='line'></view>
        <text class='text' bind:tap="productDetails">{{product.name}}</text>
    </view>
    <view class="right-container">
        <text class="text">数量:{{product.num}}</text>
    </view>
</view>
// components/product-row/index.js
<!--引入behavior.js-->
let productBev = require("../behaviors/product.js")
Component({
 <!--继承 behavior.js里面的 properties,data,methods-->
  behaviors: [productBev],
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

(4)使用组件

{
  "usingComponents": {
    "product-column-comp": "/components/product-column/index",
    "product-row-comp": "/components/product-row/index",
  }
}
<!-- behaviors -->
<product-column-comp product="{{product}}"></product-column-comp>
<product-row-comp product="{{product}}" bind:productDetails="productDetails"></product-row-comp>

(4)运行效果

2.3 自定义授权组件

  • 使用场景
    解决微信开放能力 button 的复用性。
  • 使用方法
    通过动态的传递 open-type 在组件中实现授权。
  • 示例代码如下:
    (1)封装组件,components/authorize-button
<!--components/authorize-button/index.wxml-->
<button bind:getuserinfo="onGetUserInfo" bind:tap="address" open-type="{{openType}}"  plain="{{true}}" class="container" lang="zh_CN">
  <slot name="share"></slot>
  <slot name="address"></slot>
  <slot name="info"></slot>
</button>
// components/authorize-button/index.js
Component({
  /**
   * 组件的属性列表
   */
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: {
    // 授权开放能力 通过传递实现
    openType: {
      type: String
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
   
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 用户信息获取方法
    onGetUserInfo(event) {   
      if (this.data.openType == "getUserInfo"){   
        console.log("-----------用户信息获取-----------")          
        console.log(event.detail)
      }           
    }, 
    // 地址信息的获取
    address(event){    
      if (this.data.openType == "primary") {
        console.log("-----------地址信息获取-----------")          
        this._addressInfo(event) 
      }      
    },
    _addressInfo(event){      
      wx.chooseAddress({
        success: (res) => { },
        fail:(err) =>{}, 
        complete:(e)=> {        
           console.log(e) // 用户授权和未授权都会执行 
        }
      })
    }
  }
})

(2)使用组件

{
  "usingComponents": {
    "authorize-comp": "/components/authorize-button/index"
  }
}
<!-- 授权 -->
  <view class="authorize-item">
    <authorize-comp class="authorize" open-type="getUserInfo">
      <text slot="info">用户信息</text>
    </authorize-comp>
    <authorize-comp class="authorize" open-type="primary">
      <text slot="address">获取地址</text>
    </authorize-comp>
    <authorize-comp class="authorize" open-type="share">
      <text slot="share">分享</text>
    </authorize-comp>
  </view>

(3)运行效果

2.4 自定义组件样式

  • 使用场景
    在复用组件的时候,且样式想要不同。
  • 使用方法
    使用外部样式类可以让组件使用指定的组件外样式类,如果希望组件外样式类能够完全影响组件内部,可以将组件构造器中的 options.addGlobalClass 字段置为 true 。
  • 示例代码如下:
    (1)封装组件,components/authorize-button
// components/class/index.js
Component({
  // 定义外部样式类
  externalClasses: ['box'],
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})
<!--components/class/index.wxml-->
<!--box 样式通过外部传递-->
<view class="container box"></view>

(2)使用组件

{
  "usingComponents": {
    "class-comp": "/components/class/index"
  }
}
<!-- 自定义组件样式  -->
<view class="class-item">
    <class-comp box="box1"></class-comp>
    <class-comp box="box2"></class-comp>
    <class-comp box="box3"></class-comp>
    <class-comp box="box4"></class-comp>
</view>
.box1 {
  background-color: #ff3f34;
}

.box2 {
  background-color: #fbbf00;
}

.box3 {
  background-color: #44ac45;
}

.box4 {
  background-color: #2f84d5;
}

(3)运行效果

3 wxs 的使用

WXS(WeiXin Script)是小程序的一套脚本语言,实现 wxml 数据的过滤。在使用的过程中需要需要结合官方文档,wxs 目前只是拥有部分 JavaScript 功能。官方给出的注意如下:

  • WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
  • WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
  • WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript
  • 文件中定义的函数,也不能调用小程序提供的API。
  • WXS 函数不能作为组件的事件回调。
  • 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。

常用的使用情况有两种引入后缀 wxs 和 直接在 wxml 文件中使用。

示例代码如下:

(1)新建 wxs 文件,common/wxs/filter.wxs

var filters = {
    // 定义方法
    toFix: function (value) {
        // 防止 wxs 渲染数据没有定义 
        if (value == 0 || !value) {
            return 0
        }
        // toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。
        return parseFloat(value).toFixed(2)
    }
     // 多个方法使用逗号分隔
    ,
    substr: function (value, length) {
        if (!value) {
            return ''
        }
        // 对数据进行长度限制
        return value.substring(0, length) + "..."
    }


}
// 导出方法
module.exports = {
    toFix: filters.toFix,
    substr: filters.substr
}

(2)引入使用 wxs

<!--引入 wxs 并指定标签的模块名-->
<wxs module="util" src="../../common/wxs/filter.wxs"></wxs>
    <view class="wxs-container">
    <view class="wxs-item">数字截取前:{{8.02231}}</view>
    <view class="wxs-item">数字截取后:{{util.toFix(8.02231)}}</view>
    <view class="wxs-item">订单状态页面直接引用:{{wUtil.orderStatus(1)}}</view>
</view>

module 属性
module 属性是当前 <wxs> 标签的模块名。在单个 wxml 文件内,建议其值唯一。有重复模块名则按照先后顺序覆盖(后者覆盖前者)。不同文件之间的 wxs 模块名不会相互覆盖。

module 属性值的命名必须符合下面两个规则:

首字符必须是:字母(a-zA-Z),下划线(_)

剩余字符可以是:字母(a-zA-Z),下划线(_), 数字(0-9)

(3)页面直接使用 wxs

<view class="wxs-item">文字截取后:{{util.substr("这是一段超级长的文字需要截取",6)}}</view>
<view class="wxs-item">订单状态页面直接引用:{{wUtil.orderStatus(1)}}</view>
<!--当前页面直接使用 wxs, 通过 wxs 标签指定模块名-->
<wxs module="wUtil">
  var orderStatus = function(num) {
    var value = ""
    switch (num) {
      case 0:
        value = "未支付"
        break
      case 1:
        value = "已支付"
        break
      case 2:
        value = "已发货"
        break
      case 3:
        value = "已支付,但库存不足"
        break
      default:
        value = "未知状态"
    }
    return value
  }
 <!--导出模块-->
  module.exports = {
    orderStatus: orderStatus
  }
</wxs>

(4)运行效果

4 云上 tcb-router(koa 风格)

但是无数个得云函数,我们管理又有问题了,如果想要一个函数处理多个任务 ,目前解决这一问题就是 tcb-router 。

tcb-router 小程序云函数高级玩法,在掘金开发者大会上,提到得一种云函数的用法,我们可以将相同的一些操作,比如用户管理、支付逻辑,按照业务的相似性,归类到一个云函数里,这样比较方便管理、排查问题以及逻辑的共享。甚至如果你的小程序的后台逻辑不复杂,请求量不是特别大,完全可以在云函数里面做一个单一的微服务,根据路由来处理任务。

下面三幅图可以看出:

比如这里就是传统的云函数用法,一个云函数处理一个任务,高度解耦。

第二幅架构图就是尝试将请求归类,一个云函数处理某一类的请求,比如有专门负责处理用户的,或者专门处理支付的云函数。

最后一幅图显示这里只有一个云函数,云函数里有一个分派任务的路由管理,将不同的任务分配给不同的本地函数处理。

想实现成最后一幅图,我们的使用咱们腾讯云 Tencent Cloud Base 团队开发了 tcb-router,云函数路由管理库。大家点击 tcb-router 进去看看,如果之前做过 node + koa 的同学应该很熟悉,后面我们也会有一个小得案例进一步讲解,官方例子如下:

// 云函数的 index.js
const TcbRouter = require('./router');

exports.main = (event, context) => {
    const app = new TcbRouter({ event });
  
    // app.use 表示该中间件会适用于所有的路由
    app.use(async (ctx, next) => {
        ctx.data = {};
        await next(); // 执行下一中间件
    });

    // 路由为数组表示,该中间件适用于 user 和 timer 两个路由
    app.router(['user', 'timer'], async (ctx, next) => {
        ctx.data.company = 'Tencent';
        await next(); // 执行下一中间件
    });

    // 路由为字符串,该中间件只适用于 user 路由
    app.router('user', async (ctx, next) => {
        ctx.data.name = 'heyli';
        await next(); // 执行下一中间件
    }, async (ctx, next) => {
        ctx.data.sex = 'male';
        await next(); // 执行下一中间件
    }, async (ctx) => {
        ctx.data.city = 'Foshan';
        // ctx.body 返回数据到小程序端
        ctx.body = { code: 0, data: ctx.data};
    });

    // 路由为字符串,该中间件只适用于 timer 路由
    app.router('timer', async (ctx, next) => {
        ctx.data.name = 'flytam';
        await next(); // 执行下一中间件
    }, async (ctx, next) => {
        ctx.data.sex = await new Promise(resolve => {
        // 等待500ms,再执行下一中间件
        setTimeout(() => {
            resolve('male');
        }, 500);
        });
        await next(); // 执行下一中间件
    }, async (ctx)=>  {
        ctx.data.city = 'Taishan';

        // ctx.body 返回数据到小程序端
        ctx.body = { code: 0, data: ctx.data };
    });

    return app.serve();

}

tips: 小程序云函数的 node 环境默认支持 async/await 语法

小程序端

// 调用名为 router 的云函数,路由名为 user
wx.cloud.callFunction({
    // 要调用的云函数名称
    name: "router",
    // 传递给云函数的参数
    data: {
        $url: "user", // 要调用的路由的路径,传入准确路径或者通配符*
        other: "xxx"
    }
});

5 简单实现云开发服务端

(1)新建云函数 rubbish

(2)新建集合 rubbish

添加数据

{"_id":"19b1e8b9-2662-471e-9a2d-dfda08b8b50d","goodsType":"湿垃圾","goodsName":"猕猴桃"}
{"_id":"72eb8a02-53a6-450a-9588-37a4408a3ff3","goodsType":"湿垃圾","goodsName":"苹果"}

(3)新建文件 utils/rubbish/ReturnUtil.js 用于对返回结果的处理

/**
 * 成功调用
 * @param {*} ctx
 * @retuen 
 */
const success = ctx => {
  return {
    code: 0,
    message: 'success',
    data: ctx.data
  }
}

/**
 * 调用失败 
 * @param {*} ctx
 * @param {*} msg
 * @retuen 
 */
const error = (ctx, msg) => {
  return {
    code: 400,
    message: msg,
    data: ctx.data
  }
}

module.exports = {
  success,
  error
}

(4)加入 tcb-router 依赖

npm install --save tcb-router

(5)rubbish/index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')
// 引入 tcb-router
const TcbRouter = require('tcb-router')
const returnUtil = require('utils/ReturnUtil.js')
// 初始化
cloud.init({
  env: 'test-123'
})
// 获取数据库
const db = cloud.database();
// 操作 rubbish 集合公共部分
const rubbish_db = db.collection('rubbish');
// 云函数入口函数
exports.main = async (event, context) => {
  const app = new TcbRouter({ event });
  // app.use 表示该中间件会适用于所有的路由
  app.use(async (ctx, next) => {
    ctx.data = {};
    await next(); // 执行下一中间件
  });

  /***************************    垃圾分类   *****************************************/
  // 获取单个垃圾分类信息
  app.router('getRubbish', async (ctx, next) => {
    console.log(event)
    let data = JSON.parse(event.data)
    ctx.data = await rubbish_db.where({ goodsName:data.name }).get();
    ctx.body = await returnUtil.success(ctx)
    await next();
  })

  return app.serve();
}

6 本地和服务器测试

6.1服务器测试

(1)打开云开发控制台 -> 云函数 ,点击 上面新建的 rubbish 的云端测试

(2)测试云函数

{
  // 路由  
  "$url": "getRubbish",
   // 传递参数
  "data":"{\\"name\\":\\"苹果\\"}"
}

6.2 本地调试

(1)打开本地调式

(2)点击 rubbish ,勾上开启本地调式 查看依赖是否安装

(3)安装依赖

如有依赖没有安装,在(1)步的界面中,点击在终端中打开 执行 npm install

(4)编写请求参数

{
  // 路由  
  "$url": "getRubbish",
   // 传递参数
  "data":"{\\"name\\":\\"苹果\\"}"
}

(5)调用云函数

7 Http 请求封装

网络请求的封装在小程中也能让代码更好修改,配置,维护。这里将进行网络请求和云开发请求的封装。

(1)新建 config.js

// 配置请求公用参数
const config = {
  // 网络请求
  api_http_url: 'https://www.mxnzp.com/api',
  // 云开发云函数
  api_cloud_route:"rubbish"
}
// 导出配置文件
export { config }

(2)封装网络请求 utils/http-request.js

import { config } from "../config.js"

class HTTP {

  constructor() {
    // 通过构造方法 实现 url 的赋值
    this.api_http_url = config.api_http_url
  }

  //http请求
  request(params) {
    
    wx.request({
      url: this.api_http_url + params.url, // 接口地址拼装
      method: params.method,              // 接口类型 get/post/put/delete
      data: params.data,    // 传递给后台的参数
      header: {
        // 设置请求类型  
        'content-type': 'application/x-www-form-urlencoded'
      },
      success: (res) => {
        let code = res.data.code.toString()
        if (code.startsWith('1')) {
         // 将请求的参数回调给上层
          params.success(res)
        }

      },
      fail: (error) => {
        console.log(error)
      },
      complete: (res) => {
        
      }

    })

  }

}

export {
  HTTP
}

(3)封装云开发请求 utils/cloud-request.js

// 导入配置文件
import { config } from "../config.js"
class CloudRequest{

  constructor(){
    this.api_cloud_route = config.api_cloud_route
  }

  request(params){
    
    wx.cloud.callFunction({
      // 要调用的云函数名称
      name: this.api_cloud_route,
      // 传递给云函数的参数
      data: {
        // 要调用的路由的路径,传入准确路径或者通配符*
        $url: params.url, 
        // 请求参数
        data: JSON.stringify(params.data)
      },
      success: res => {
        // 结果回调  
        params.success(res)
      },
      fail: err => {
        console.log(err)
      }
    })
  }


}
export { CloudRequest }

下面我们将通过案例来分别使用我们的封装的请求。

8 客户端、服务端通信

8.1 网络请求

(1)自定义 model 层,models/IndexModel.js 类

// 导入封装的 http 请求
import { HTTP } from '../utils/http-request.js'
// 继承 HTTP 直接调用其方法
class IndexModel extends HTTP {
  
  /**
   * 查询垃圾分类信息
   * @param {*} callBack
   */
  getRubbish(name,callback){
    // http 请求
    this.request({
      url: "/rubbish/type", // 接口地址
      data: {
        name: name // 传递参数
      },
      // 接收  params.success(res) 回调参数
      success: res => {
        // 将数据再次回调
        callback(res) 
      }
    })
  }

}

export { IndexModel }

在这里可能比较难得就是回调,回调。通过类进行请求的封装,在很大的使得代码更加简洁。model 层作为一个中间层来使用,无论是代码的复用和维护程度好了很多。

(2)实现 model 类

// 第一步:导入
import { IndexModel } from '../../models/indexModel.js'
// 第二步:实例化
let indexModel = new IndexModel()
/ 第三步:调用方法,参数和方法中一一对应 res 接收callback回调参数
indexModel.getRubbish("苹果",res=>{
	console.log(res)
	this.setData({
        httpItem:res.data.data.aim
     })
})
 <group-comp title="网络请求"></group-comp>
  <view class="http-container ">
    <view class="http-item">{{httpItem.goodsName}} : {{httpItem.goodsType}}</view>
  </view>

(3)运行效果

8.2 云开发请求

(1)自定义 model 层,models/IndexCloudModel.js 类,其方法类似于 http

// 导入封装的 http 请求
import { CloudRequest } from '../utils/cloud-request.js'
// 继承 CloudRequest 直接调用其方法
class IndexCloudModel extends CloudRequest {

  /**
   * 查询垃圾分类信息
   * @param {*} callBack 
   */
  getRubbish(name,callBack) {
    this.request({
      url: "getRubbish",
      data:{name:name},
      success: res => {
        callBack(res)
      }
    })
  }

  
}

export { IndexCloudModel }

(2)实现 model 类

// 第一步:导入
import { IndexCloudModel } from '../../models/indexCloudModel.js'
// 第二步:实例化
let indexCloudModel = new IndexCloudModel()
/ 第三步:调用方法,参数和方法中一一对应 res 接收callback回调参数
indexCloudModel.getRubbish("猕猴桃",res=>{
    console.log(res)
    this.setData({
        cloudItem: res.result.data.data[0]
    })
})	
<group-comp title="云函数请求" ></group-comp>
  <view class="http-container ">
    <view class="http-item">{{cloudItem.goodsName}} : {{cloudItem.goodsType}}</view>
  </view>

(3)运行效果

在这里就封装了两种请求,这里封装的代码在多人开发和后期维护节省了不少时间,大家日常在开发也可以直接使用。

9 函数实现定时器

如果云函数需要定时 / 定期执行,也就是定时触发,我们可以使用云函数定时触发器。配置了定时触发器的云函数,会在相应时间点被自动触发,函数的返回结果不会返回给调用方,详情进入官方网址,比如:两小时后取消订单、定点定时推送商品信息等。

右击 cloud 选择 新建 Node.js 云函数 命名为 triggers

云函数创建触发器,必须建一个 config.json 文件,因为只有 config.json 才会有上传触发器选项。

  • 一般 json 文件

  • config.json

config.json 相比一般的 json 多出上传触发器和删除触发器 触发器也只有通过这样上传和删除后台才会执行。

config.json 解读

{
  // triggers 字段是触发器数组,目前仅支持一个触发器,即数组只能填写一个,不可添加多个
  "triggers": [
    {
      // name: 触发器的名字,可以随意更改,规则见给出的官方链接
      "name": "myTrigger",
      // type: 触发器类型,目前仅支持 timer (即 定时触发器)
      "type": "timer",
      // config: 触发器配置,在定时触发器下,config 格式为 cron 表达式,规则见官方链接
      "config": "0 0 2 1 * * *"
    }
  ]
}

示例

下面展示了一些 Cron 表达式和相关含义的示例:

  • */5 * * * * * * 表示每5秒触发一次
  • 0 0 2 1 * * * 表示在每月的1日的凌晨2点触发
  • 0 15 10 * * MON-FRI * 表示在周一到周五每天上午10:15触发
  • 0 0 10,14,16 * * * * 表示在每天上午10点,下午2点,4点触发
  • 0 */30 9-17 * * * * 表示在每天上午9点到下午5点内每半小时触发
  • 0 0 12 * * WED * 表示在每个星期三中午12点触发

接下来我们编写每十秒的触发器,进入 config.json

{
  "triggers": [
    {
      "name": "trigger",
      "type": "timer",
      "config": "*/10 * * * * * *"
    }
  ]
}

注意:在创建触发器去掉触发器的注释 有注释上传在解析 json 会报错

编写 index.json

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

cloud.init()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  console.log("每十秒触发器执行一次测试。。。")
  
}

目前作为测试所以我们输出一句话测试下是否成功 因为云函数不会返回 所以 return 没有必要返回数据 。

编写云函数 triggers 下的 index.json 和 config.json ,点击 triggers 上传并部署:云端安装依赖,上传成功后,代有击 config.json 上传触发器,成功后我就在云开发后台去看下,选择云函数函数名为 triggers 我们在日志控制面看可以看出输出时间是不是我们的触发时间,云函数的输出内容,如下图:

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
【云+社区年度征文】小程序·云开发综合提升篇
什么是小程序云开发,从前端解决后端的活。18 年以为很多大公司减员,小公司关闭,到底是互联网的寒冬时期,还是互联网换新时期,我认为是后者。小程序开发周期一般都相...
<<上一篇
下一篇>>