小程序云开发初探

1,830 阅读8分钟

前言

从小程序刚开始的时候就接触了小程序,到现在也在公司开发过几个小程序项目,但是因为公司的项目都有专门的后台人员,所以在云开发上线以来一直就没有尝试过。

so,那么是到了玩一玩这个的时候了。

本文基于微信调试基础库 2.7.4,要实现一个很简单的功能,一个活动页,一个点击获取用户信息,然后一个分享,微信小程序这三个功能貌似99%的公司都会做!

文档

开发小程序只需要一个文档就可以了微信官方文档

前置知识

  • 需要掌握HTML,CSS,JavaScript知识
  • 需要了解一些Node知识
  • 有一定的小程序开发经验

起步

通过微信开发者工具创建云开发小程序后,点击左上角云开发按钮,然后再点击开通,初步创建就完成了,目录结构如下:

// cloudfunctions 云函数文件夹,miniprogram小程序文件夹
|-cloudfunctions | 未指定环境
    └──login
    └──openapi
|-miniprogram
|-project.config.json
|-README.md

如果一直显示 未指定环境,需要 右键->更多设置 然后就会变成你创建的环境,比如说这样:

|-cloudfunctions | test

一般来说最少创建两个环境,一个测试环境,一个线上环境!
一般你初次点击云开发的时候就会让你创建一个环境,如果想要再加一个,点击 云开发->右上角三角箭头->创建新环境
云开发暂时不支持修改环境名称,创建环境的时候要慎重

但是,这个时候如果点击模拟器上面的点击获取 openid会报错,报错如下:

Error: errCode: -404011 cloud function execution error | errMsg: cloud.callFunction:fail cloud function service error code -504002, error message Function not found: [login]; at cloud.callFunction api

原因是,你还没有把云代码部署到云服务器上去,右键点击cloudfunctions下的login文件夹,选择创建并部署,云端安装依赖,等到弹出上传成功的提示后,然后再点击点击获取 openid你就可以看到报错信息没有了,并且在模拟器会返回你的openid。

tips:如果你在微信公众平台设置了基础库最低版本设置,然而你的微信开发者工具的调试基础库不大于或等于你设置的最低版本,会报错,报错信息如下:

Error:connect ETIMEDOUT 192.30.253.113:443

如果你想要删除某个云函数,直接点击 云开发->云函数->删除 即可

组件

微信小程序提供了自定义组件功能,这个功能非常棒,是我们以后开发绝对必须熟悉的一种技能,写一个小例子掌握这个:

参考weui自定义一个button组件,练习怎么自定义组件,不建议实际开发这样封装button

// 进入
cd miniprogram

// 创建components文件夹
mkdir components

// 创建button文件夹,在这个里面自定义button组件
cd components
mkdir button

button.wxml

<button class="mui-btn" type="{{ type }}" plain="{{ pian }}" disabled="{{ disabled }}">
    {{ text }}
</button>

button.wxss

.mui-btn {
  margin-top: 30rpx;
}
.mui-btn:first-child {
  margin-top: 0;
}
.mui-btn-area {
  margin: 1.17647059em 30rpx 0.3em;
}

button.js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 按钮上显示的文字
    text: {
      type: String,
      value: '按钮'
    },

    // 按钮的样式属性,primary,default,warn
    type: {
      type: String,
      value: 'primary'
    },

    // 是否显示边框
    pian: {
      type: Boolean,
      value: false
    },

    // 是否禁用
    disabled: {
      type: Boolean,
      value: false
    }
  }
})

button.json

{
  "component": true,
  "usingComponents": {}
}

自定义button组件使用,在pages文件夹下新建login文件夹

login.json

{
  "usingComponents": {
    "m-button": "../../components/button/button"
  }
}

login.wxml

<m-button text="授权" pian="{{ true }}"></m-button>

tips:这个例子写的button组件一点也不实用,只是简单介绍以下自定义组件怎么写,实际上开发使用微信自己原生的button组件更好

登录页UI

虽然微信自带了一个登录的示范,但是那个不是我想要的,所以需要自定义一个

上面已经创建了login文件夹,使用这个开发登录页

首先,我们来完善下登录页的UI,在style文件夹下新建一个public.wxss文件,常用的公共的css都放在这里面,比如:

public.wxss

/*这个实际上根据项目自定义,但是也可以抽取一些公共的css,所有项目都会用到的,比如说一些布局之类的,方便以后复用*/
.mui-center-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

.mui-center-grid {
  justify-self: center;
  align-self: center;
}

.mui-center-margin {
  margin: 0 auto;
}

···

login.wxss中引入使用

login.wxss

@import '../../style/public.wxss';

然后,就可以在login.wxss写样式了

样式如下,请原谅我这垃圾的UI:

封装公共js

// 进入
cd miniprogram

// 创建utils文件夹
mkdir utils

// 进入
cd utils

// 创建js
vim WeChatPublic.js

一些公共的方法,放到utils文件夹下, WeChatPublic.js 放一些封装的微信api

WeChatPublic.js

export default class {
  constructor() {}
  // 获取用户信息
  static onGetSetting(pageUrl, loginUrl) {
    wx.getSetting({
      success: res => {
        // 已经授权,跳转页面
        if (res.authSetting['scope.userInfo'] && pageUrl) {
          wx.redirectTo({
            url: pageUrl
          })
        }
        // 没有授权,跳转登录页
        if (!res.authSetting['scope.userInfo'] && loginUrl) {
          wx.redirectTo({
            url: loginUrl
          })
        }
      }
    })
  }
  ...
}

tips:
1、这里要说明的是,微信小程序里,跳转不能设置为空字符串,设置为空字符串会报错!所以,要在外面加一层判断,如果是不是空字符串才执行跳转
2、小程序不支持绝对路径,都要使用相对路径,使用相对路径就有层级问题,有层级问题,所以上面的跳转登录页不能写死

官方已有计划支持绝对路径或者是别名需求:引用文件支持绝对路径,但是不知道啥时候能上线

使用:

app.js

import WeChatPublic from './utils/WeChatPublic'

App({
  // 监听全局加载,两个globalData放那个里面都行
  onLaunch() {
    if (!wx.cloud) {
      console.error('请使用 2.2.3 或以上的基础库以使用云能力')
    } else {
      wx.cloud.init({
        traceUser: true
      })
    }
    // this.globalData = {}
  },
  globalData: {
    WeChatPublic
  }
})

login.js

// 如果需要调用app.js里的函数,那么要
const app = getApp()
const wxFun = app.globalData.WeChatPublic

Page({
  // 页面的初始数据
  data: {},

  // 生命周期函数--监听页面加载
  onLoad() {
    wxFun.onGetSetting('../../home/pages/home/home', '')
  }
})

完成登录授权

小城市云函数使用起来非常简单,用模板自带的实例已经自带了获取openid的云函数,所以不用自己搭建后台,去写后台代码,只需要有一点点node知识就能写云函数代码了,具体使用可以看腾讯官方的文档,非常详细文档中心-云开发

使用分包的方式创建活动页面

// 进入
cd miniprogram

// 创建home
mkdir home

修改app.json

{
  ...
  // 使用分包
  "subpackages": [
    {
      "root": "home",
      "name": "home",
      "pages": ["pages/home/home"]
    }
  ],
  // 分包预加载
  "preloadRule": {
    "pages/login/login": {
      "network": "all",
      "packages": ["home"]
    }
  },
  ...
}

在login.js中编写逻辑

// 如果需要调用app.js里的函数,那么要
const app = getApp()
const wxFun = app.globalData.WeChatPublic

Page({
  // 页面的初始数据
  data: {},

  // 生命周期函数--监听页面加载
  onLoad() {
    wxFun.onGetSetting('../../home/pages/home/home', '')
  },

  // 获取用户信息授权
  onGetUserInfo(e) {
    if (e.detail.userInfo) {
      wx.redirectTo({
        url: '../../home/pages/home/home'
      })
      // 存贮storage里面,这个api是同步存贮,不带Sync是异步存贮
      wx.setStorageSync('UserInfo', JSON.stringify(e.detail.userInfo))
    }
  }
})

tips:写代码逻辑的时候,注意执行顺序,执行顺序很重要,完美的执行顺序能够大大提升你的代码执行速度!像是上面的代码,跳转存储,如果你把存贮写在跳转的前面,而你的存贮是同步的话,跳转要等到存贮完成,无形中就增加了代码执行的时间

封装一个请求函数

云开发小程序除了调用自己写的云函数之外,还可以正常调用Http请求,可以自己封装一个request请求,也可以使用别人已经封装好的库wx-promise-pro

这里提供了一个简单的request封装思路

// 进入
cd utils

// 新建request.js,api.js
vim request.js
vim api.js

request.js

export default class {
  constructor() {}

  // 判断请求状态是否成功,返回布尔值
  static isHttpSuccess(status) {
    return (status >= 200 && status < 300) || status === 304
  }

  // 请求
  static request(options = {}) {
    return new Promise((res, rej) => {
      wx.request(
        Object.assign({}, options, {
          success: r => {
            const isSuccess = this.isHttpSuccess(r.statusCode)
            if (isSuccess) {
              res(r.data)
            } else {
              rej({
                msg: `网络错误:${r.statusCode}`,
                detail: r
              })
            }
          },
          fail: err => {
            rej(err)
          }
        })
      )
    })
  }
}

api.js

import http from './request'
const apiUrl = 'https://xxxx'

// 这里可以自定义很多wx.request的参数,比如说url,header,data,method等等
export default class {
  constructor() {}

  // 获取热门列表
  static getHotList(data) {
    const url = `${apiUrl}/api/hotList`
    return http.request({ url, data })
  }

  // 获取最新列表
  static getLatestList(data) {
    const url = `${apiUrl}/api/latestList`
    return http.request({ url, data })
  }
}

在 WeChatPublic.js 中添加:

export default class {
  constructor() {}
  ...

  // 判断错误信息
  static errPicker(err) {
    if (typeof err === 'string') {
      return err
    }
    return (
      // err.errMsg小程序接口报错,err.detail && err.detail.errMsg 自定义接口报错
      err.msg || err.errMsg || (err.detail && err.detail.errMsg) || '未知错误'
    )
  }

  // 弹出错误
  static showErr(err) {
    const msg = this.errPicker(err)
    wx.showModal({
      showCancel: false,
      content: msg
    })
  }
}

使用:

app.js中引入

import WeChatPublic from './utils/WeChatPublic'
// 引入
import Http from './utils/api'

App({
  // 监听全局加载
  onLaunch() {
    if (!wx.cloud) {
      console.error('请使用 2.2.3 或以上的基础库以使用云能力')
    } else {
      wx.cloud.init({
        traceUser: true
      })
    }
    // this.globalData = {}
  },
  globalData: {
    WeChatPublic,
    // 引入
    Http
  }
})

然后在需要调用的页面:

const app = getApp()
const wxFun = app.globalData.WeChatPublic
const api = app.globalData.http

Page({
  // 页面的初始数据
  data: {},

  // 生命周期函数--监听页面加载
  onLoad() {
    api.getHotList({page: 1}).then(res => {
        console.log(res)
    }).catch(err => {
        wxFun.showErr(err)
    })
  },

  ...
})

活动页面逻辑

const app = getApp()
const wxFun = app.globalData.WeChatPublic

Page({
  // 页面的初始数据
  data: {},

  // 生命周期函数--监听页面加载
  onLoad() {
    wxFun.onGetSetting('', '../../../pages/login/login')
    this.onGetOpenid()
  },

  // 获取用户openid授权
  onGetOpenid() {
    // 调用云函数
    wx.cloud.callFunction({
      name: 'login',
      data: {},
      success: res => {
        console.log('[云函数] [login] user openid: ', res.result.openid)
        // 存贮openid
        wx.setStorageSync('openid', res.result.openid)
      },
      fail: err => {
        console.error('[云函数] [login] 调用失败', err)
        console.error(`
            请检查 login 云函数是否已部署
            1. 确保已通过工具栏云开发入口开通云开发
            2. 在 cloudfunctions/login 目录上右键上传并部署
            3. 回到首页,重新点击获取 openid
          `)
      }
    })
  },

  // 用户点击右上角分享
  onShareAppMessage() {
    return {
      title: '活动',
      imageUrl: '../../../pages/login/login.jpg'
    }
  }
})

小程序分享非常简单onShareAppMessage中定义一下就ok了

最后

删除掉多余的文件夹和多余的文件,一个简单的云函数小程序demo完成了,贴一下demo结构:

so,能力有限,有错误之处望各位大佬多多指出

参考

一个通用request的封装