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
- Initial request -> Request user authorization -> Grant authorization (-> Deny authorization -> End) -> Use the corresponding function
- 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 will
Verify 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