After a period of wechat small program development, summed up some code snippets, mainly in the following aspects:

  • Applets (authorization, networking, recording, image)
  • Mpvue (subcontracting, global variables, SVG components, component class bindings)

Small program

Authorization logic

  1. Initial request -> Request user authorization -> Grant authorization (-> Deny authorization -> End) -> Use the corresponding function
  2. Second request -> jump applet setting page modal -> set page -> open scope -> use the corresponding function
const checkPermission = scope => new Promise((resolve, reject) => { wx.getSetting({ success: Res = > {/ / whether there is any authentication configuration let hasAuthorized = res. AuthSetting. HasOwnProperty (scope) if (hasAuthorized) {/ / authorized the if (res.authSetting[scope]) {resolve(' authorized ') return} So use modal wx.showModal({title: 'no permission ', content:' You need to authorize the permission to experience this function, now go to Settings to enable ', success: Res => {if (res.confirm) {reject(' reject ') wx.opensetting ()} else if (res.cancel) {reject(' reject ')}}})}}, fail: err => { reject(err.errMsg) } }) })Copy the code

network

Differences of network requests in different environments of wechat applets:

  • Preview and play mode willVerify the legitimate domain name, Web-view (service domain name), TLS version, and HTTPS certificate, you need to set the allowed request,upload and other domain names in the background
  • In the debug and test environment mode, you can skip the verification by selecting no verification option in the details

Network requests and interceptors

You can use fly.js as a web request library for small programs, and it’s also convenient when using features like interceptors.

The wx. UploadFile method of the applet can be encapsulated as follows: POST requests with content-Type multipart/ formData cannot be sent as custom requests.

const formDataRequest = (url, filePath, params = {}) => new Promise((resolve, reject) => { let token = wx.getStorageSync("token") wx.uploadFile({ url, filePath, name: "file", header: {token}, formData: params, success: async res => {// resolve(res.data) }, fail: err => { reject(err) } }); });Copy the code

Check whether online

Use the getNetworkType method

export const isOnline = () => new Promise((resolve, reject) => { wx.getNetworkType({ success(res) { const networkType = res.networkType resolve(networkType ! == 'none') }, failed(res) { reject(res) } }) })Copy the code

The recording process

Mainly recording API detection, state control and event listener processing.

If (wx.getRecorderManager) {this.recorder = wx.getRecorderManager() this.addRecorderListener()} else {wx.showModal({title: 'prompt ', showCancel: false, content:' The current wechat version is too early to use this function, please upgrade to the latest wechat version and try again. '})} // 2. Scope. Record authorization async startRecordHandle() {if (! this.recorder) return try { await this.checkPermission('scope.record') } catch (err) { return } this.recorder.start(this.audioOption) }, // 3. Add event listener addRecorderListener() {if (! this.recorder) return this.recorder.onStart(() => { ... this.recording = true }) this.recorder.onStop(path => { ... this.recording = false this.audioPath = path.tempFilePath }) }Copy the code

To achieve the long-press recording scenario, you can combine lonepress event and setTimeout to achieve it.

<template> <g-button type="primary" ... @long-press="longPressHandle" /> </template> <script> export default { methods: {longPressHandle() {this.canrecordStart = true}, TouchStartHandle () {this.canrecordStart = true let delay = 400 setTimeout(() => {if (this.canrecordStart)  { this.startRecordHandle() } }, delay) }, touchEndHandle() { if (! this.canRecordStart) return this.canRecordStart = false this.stopRecordHandle() }, } } </script>Copy the code

The image processing

Get picture information

wx.getImageInfo

Both CDN images and locally selected images need to use getImageInfo to obtain the basic information of the image

getImageInfo(img) { return new Promise((resolve, reject) => { wx.getImageInfo({ src: img, success: Res = > {resolve (res)}, fail: () = > {reject (' failed to get the picture information ')}})})}Copy the code

Choose picture

wx.chooseImage

Let the user select the images in or taken in the local album, using the selection of individual images as an example:

const MB = 1024 * 1024 chooseSingleImage() { return new Promise((resolve, reject) => { wx.chooseImage({ count: SizeType: ['original', 'compressed'], // set sourceType: ['album', 'camera'], // Specify whether the source is album or camera, default both success: // let {size} = file // if (size > 20 * MB) {// if (size > 20 * MB) { Reject (' picture size should be less than 20 MB)} resolve (file)}, fail: () = > {reject (' picture selection failure ')}})})}Copy the code

Read the pictures

wx.getFileSystemManager()

Read file contents using the FS API of the applet

readFileInBase64(filePath) { return new Promise((resolve, Reject) => {if (wx.getFilesystemManager) {wx.getFilesystemManager ().readfile ({filePath: filePath, encoding: 'base64', success: res => { resolve(res) }, file: () => {reject(' reject file failed ')}})} else {// Compatible processing, if not supported prompt update wx.showModal({title: 'prompt ', showCancel: false, content: 'The current wechat version is too early to use this function. Please upgrade to the latest wechat version and try again. '})}})}Copy the code

Drawing an image on Canvas

Using the CanvasContext API in applets is in much the same form as in H5. It should be noted that the canvas size in the applet is px, not reactive RPX.

Note that the API of CanvasContext has changed a lot since the base library 1.9.90.

export const drawPoint = (ctx, x, y) => { let pointColor = '#2ba5ff' ctx.beginPath() ctx.arc(x, y, 1, 0, Math.PI * 2, ClosePath () if (ctx.fillstyle) {// 1.9.90+ ctx.fillstyle = pointColor} else { ctx.setFillStyle(pointColor) } ctx.fill() } export const drawRect = (ctx, x, y, width, Height) => {let marginColor = '#ff0000' if (ctx.strokestyle) {// 1.9.90+ ctx.strokestyle = marginColor} else { ctx.setStrokeStyle(marginColor) } ctx.lineWidth = 1 ctx.strokeRect(x, y, width, height) }Copy the code

mpvue

Subcontracting and subcontracting preloading

Mpvue – loader: ^ 1.1.2

SubPackages can be configured directly in app.json:

{... "subPackages": [ { "root": "pages/module-bob/", "pages": ["subpage-a/main", "subpage-b/main", "subpage-c/main"] }, { "root": "pages/module-alice/", "pages": ["subpage-d/main", "subpage-e/main", "subpage-f/main"] } ], "preloadRule": { "pages/index/main": { "network": "wifi", "packages": ["pages/module-bob"] } } ... }Copy the code

Where preloadRule is the preloading configuration, the above Settings mean that the module-Bob subpackage is preloaded when entering the Index page for wifi network.

  • Segmentfault.com/a/119000001…

Use the globalData global variable

Mount the built-in [globalData]() to vue’s prototype methods in the applet.

Add the following code at the end of main.js in SRC:

import Vue from 'vue' import App from './App' ... Const app = new Vue(app) app.$mount() vue.prototype.$globalData = getApp()Copy the code

You can then use this command to manipulate global variables on other pages

// page A
this.$globalData.userInfo = {name: 'yrq110'}
// page B
console.log(this.$globalData.userInfo)
// page C
this.$globalData.userInfo.name: 'yrq110'
Copy the code

Note that when using globalData in child pages, assigning variables to data is invalid, as follows:

Export default {data() {// Invalid // isIPX: this.$globaldata.isipx}, computed: {isIPX() {return this.$globaldata.isipx}},}Copy the code

Default versus default sizes for SVG icon components

The size on the parent tag is used as the default size when loading SVG in the icon component, and the default size is used when passing in specific props parameters.

The business encountered this problem and solved it by binding the loaded raw size to the style in the load event handler of the Image component.

This is done: 1. The default SVG tag size is used; 2. The default size is used when passing the size attribute

<template> <image ... @load="loadHandle" :style="{ width: ! size ? iconWidth + 'rpx' : '100%', height: ! size ? iconHeight + 'rpx' : '100%'}" ... /> </template> <script> export default { ... Data () {return {iconWidth: 0, iconHeight: 0, loaded: false}}, props: {... size: String }, computed: { ... getSizeClass() { let { size } = this return size || '' }, setSizeStyle() { if (! this.loaded || this.size) return {} return { width: this.iconWidth + 'rpx', height: this.iconHeight + 'rpx' } } }, methods: LoadHandle (e) {this.loaded = true // Use the default size const {detail} = e.p this.iconwidth = detail.width * 2 this.iconHeight = detail.height * 2 } } ... } </script>Copy the code

Trick cannot be bound to a class on a component

Pass the keyword as a prop property to the component and bind it to the class via a Computed property, so that you can set a custom style based on the keyword when external references are made.

The key code in the component is as follows:

<template>
  <div :class="customClass">
    <slot></slot>
  </div>
</template>

<script>
export default {
  ...
  props: {
    type: String,
    ...
  },
  computed: {
    customClass() {
      let type = this.type || ''
      return type
    }
  }
  ...
}
</script>
Copy the code

You can use custom classes to use styles externally when referencing externally:

<template> ... <g-button type="custom-button"></g-button> ... </template> ... <style lang="scss"> ... .custom-button { .text { margin-left: 10px; }... } </style>Copy the code