Questions related to WeChat Mini Programs (1)

Article directory


This article is a summary of the problems or experience encountered in developing small programs at work. The purpose is to sort out some functional details and deepen the understanding of the process;

1. Introduce vant-weapp UI

1. Open the terminal of the applet project, execute it mpn init, and initialize the package.json file;
2. Execute it npm i @vant/weapp -S, install the vant-weapp component library, and a node_module dependency package will be generated after success;
3. On the WeChat developer tool, click "Tools" in the upper left corner " Click "Build npm", and the miniprogram_npm file will be generated after success;
4. “style”:"V2"Remove the from , because the new version of the mini program has added many styles to the basic components, which is difficult to cover;
5. Modify the project.config.json file: setting
insert image description here
6. Use: global
import: configure in app.json

"usingComponents": {
    "van-button":"@vant/weapp/button/index"
  },

Partial import: configure in the json file corresponding to the page (same as above)

2. Configure the applet tabBar

Configure in app.json

"tabBar": {
    "color": "#999999",
    "selectedColor": "#0071D0",
    "backgroundColor": "#ffffff",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "",
        "selectedIconPath": ""
      },
      {
        "pagePath": "pages/me/index",
        "text": "我的",
        "iconPath": "",
        "selectedIconPath": ""
      }
    ]
  },

3. Mini Program login authorization process

1. Determine whether there is a token, check the validity of the token if it exists, continue if it is valid, and clear the token if it is invalid;
2. If the token is invalid or does not exist, go through the login process, first call wx:openSetting(open the setting page authorization) to determine whether the user is authorized, If not authorized, let the user authorize;
3. If authorized, call to wx.loginget login credential code, send the code to the server, get openid, session_key and other information, and store it locally;
4. The user clicks the button (set open-type as needed) to trigger the event , get iv, encryptedData, you can check the timeliness of the code;
5. Call the server interface, get the token and cache it;

// 定义 login.js 文件
//获取到openid, session_key等信息
const login = () => {
  return new Promise((resolve, reject) => {
    // 调用微信登录接口获取用户临时登录凭证 code
    wx.login({
      success: (res) => {
        if (res.code) {
          // 登录成功,将 code 发送到开发者服务器
          wx.request({
            url: 'https://example.com/login',
            data: {
              code: res.code
            },
            success: (res) => {
              // 获取用户唯一标识 OpenID 和会话密钥 session_key
              const { openid, session_key } = res.data;
              // 将用户信息存储到缓存中,生成自定义登录态
              wx.setStorageSync('openid', openid);
              wx.setStorageSync('session_key', session_key);
              resolve();
            },
            fail: (err) => {
              reject(err);
            }
          });
        } else {
          reject(res.errMsg);
        }
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
};
// 判断用户是否已授权
const checkAuth = () => {
  return new Promise((resolve, reject) => {
    // 获取用户当前设置状态
    wx.getSetting({
      success: (res) => {
        // 判断用户是否已授权
        if (res.authSetting['scope.userInfo']) {
          resolve();
        } else {
           // 用户未授权,引导用户打开设置页面进行授权
		    wx.showModal({
		      title: '提示',
		      content: '检测到您未授权登录,请先进行授权。',
		      showCancel: false,
		      success: (res) => {
		        if (res.confirm) {
		          wx.openSetting({
		            success: (res) => {
		              if (res.authSetting['scope.userInfo']) {
		                // 用户已授权,可进行相关操作
		                resolve();
		              }
		            }
		          });
		        }
		      }
		    });
        }
      },
      fail: (err) => {
        reject(err);
      }
    });
  });
};
// 在需要登录的页面调用 login() 方法进行登录授权和判断用户是否已授权
onLoad(){
	login();
}
//下面是用户手动触发的getPhoneNumber方法
getPhoneNumber(e){
	//这里可以使用 wx.checkSession 校验一下code 的有效性
	//e 里面可以拿到iv、encryptedData;发送给服务器获取到登录token
}

I have used the interface to return after getting the user's information from the server here; you can also use a wx.getUserInfoto get the user's information;

Note : When calling the wx.openSetting() method, you need to add the corresponding permission settings in the applet's app.json file. For example, if you want to use the user information component, you need to add the following code in app.json:

"permission": {
  "scope.userLocation": {
    "desc": "获取你的地理位置信息"
  },
  "scope.userInfo": {
    "desc": "获取你的个人信息"
  }
}

4. Small program payment (WeChat payment)

Qualification:

1. The mini program has completed real-name authentication: you need to submit relevant personal or business information for review, and the payment function can only be activated after passing; 2. The
mini program has activated WeChat payment: in the management background of the mini program, you need to activate the WeChat payment function first, configure Relevant parameters and keys;
3. Binding WeChat merchant account: the merchant account must be associated to activate the payment function;

process:

1. It is necessary to register a merchant account on the WeChat Pay merchant platform, and conduct relevant qualification certification and review. After passing the review, you can obtain information such as WeChat Pay's merchant ID, API key, and certificate;
2. Apply for the WeChat payment function in the mini program and bind the merchant ID;
3. Use the wx.request method to call 统一下单the interface to obtain prepaid bill information , pass the obtained information to wx.requestPaymentthe method to initiate a payment request;

wx.requestPayment({
  timeStamp: payParams.timeStamp,
  nonceStr: payParams.nonceStr,
  package: payParams.package,
  signType: payParams.signType,
  paySign: payParams.paySign,
  success(res) {
    console.log('支付成功', res);
  },
  fail(err) {
    console.log('支付失败', err);
  }
});

5. Small program sharing

The WeChat Mini Program provides the wx.showShareMenu API, which can be used to enable the sharing function of the Mini Program page. After enabling the sharing function, the user can share the Mini Program page with other users or group chat.

1. Call wx.showShareMenuthe method to enable the sharing function. This method can be called in the onReady lifecycle function.

onReady: function() {
  wx.showShareMenu({
    withShareTicket: true,
    success: (res) => {
      // 分享功能开启成功
    }
  });
},

2. Define a custom button on the Mini Program page to trigger the sharing operation. Bind the onShare method in the button's bindtap attribute.

<button type="primary" bindtap="onShare">分享</button>

3. Define an onShare method in the applet page to trigger the share operation. In this method, call the wx.shareAppMessage method to generate share parameters and open the share interface.

onShare: function() {
  return {
    title: '分享标题',
    path: '/pages/index/index',
    imageUrl: '/images/share.png'
  };
},

4. Add the sharing statistics code in the Mini Program page. You can call the background interface in the onShareAppMessage lifecycle function to record share events and upload data.

onShareAppMessage: function(res) {
  const { from, target, webViewUrl } = res;
  // 调用后台接口记录分享事件
  // ...
  return {
    title: '分享标题',
    path: '/pages/index/index',
    imageUrl: '/images/share.png'
  };
},

Both the 1st and 4th can open the sharing in the upper right corner,

6. The applet opens the built-in map (Tencent map)

uni.openLocation({
 	latitude: 31.230416, // 上海的纬度
  	longitude: 121.473701, // 上海的经度
  	name: '上海市', // 地点名称
  	address: '中国上海市黄浦区人民广场', // 地址的详细说明
  	scale: 18, // 缩放比例
  	success: function(res) {
    console.log('打开地图成功');
  },
  fail: function(err) {
    console.log('打开地图失败', err);
  }
});

Display the marked points of the specified location on the map, and support calling the built-in map for navigation; after opening the map, click the navigation icon in the lower right corner to pop up an option pop-up window, allowing the user to choose which map application to use for navigation;

7. The applet opens the app

According to the official instructions, you cannot jump from the applet to any app, you can only jump back to the app, that is, you can only jump from the app to the applet, and then jump back from the applet to the app; the applet needs to be triggered by the user to return to the app, so it is not controlled by the API. To call, it needs to be triggered by clicking the button component whose open-type value is set to launchApp;

If you need to pass parameters to the APP when opening the APP, you can set app-parameter as the parameter to be passed. The error event of opening APP can be monitored through bindererror.

<button open-type="launchApp" app-parameter="wechat" binderror="launchAppError">打开APP</button>
Page({
  launchAppError (e) {
    console.log(e.detail.errMsg)
  }
})

Reference: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/launchApp.html

Note:
1. The applet cannot open the default browser of the mobile phone;

8. The applet opens other applets

Users need to click and confirm the jump to open another published applet. There is no limit to jump between applets when writing articles, and you can jump at will;

wx.navigateToMiniProgram({
  appId: 'wx1234567890', // 要打开的小程序的appId
  path: '/pages/index', // 打开的页面路径,如果为空则打开首页
  extraData: {
    foo: 'bar' // 需要传递给目标小程序的数据,格式为键值对
  },
  success(res) {
    console.log('打开小程序成功', res);
  },
  fail(err) {
    console.log('打开小程序失败', err);
  }
});

It is necessary to ensure that the user has authorized and logged in the target applet, otherwise the jump will fail; path parameters can be obtained through options in the onLoad life cycle of the opened page; extraData can e.referrerInfobe obtained

If you want to return to the previous mini-program, you can use: wx.navigateBackMiniProgram can only be called successfully when the current mini-program is opened by other mini-programs;

9. The applet obtains the current geographic location

First, you need to configure the location permission in app.json; (uni-app needs to be set in mp-weixin in manifest.json)

"permission": {
    "scope.userLocation": {
      "desc": "你的位置信息将用于小程序内的定位服务"
    }
  }

Requesting authorization and obtaining location information are both asynchronous operations, and the results need to be processed in the callback function. In addition, if the user refuses to authorize or is not authorized, the wx.getLocation method will fail;

// 请求授权
wx.authorize({
  scope: 'scope.userLocation',
  success: function() {
    // 授权成功,获取位置信息
    wx.getLocation({
      type: 'wgs84', // 坐标类型,默认为wgs84,可选gcj02
      success: function(res) {
        const latitude = res.latitude; // 纬度
        const longitude = res.longitude; // 经度
        const speed = res.speed; // 速度,单位m/s
        const accuracy = res.accuracy; // 位置精度
        console.log('获取位置信息成功', res);
      },
      fail: function(err) {
        console.log('获取位置信息失败', err);
      }
    });
  },
  fail: function() {
    // 授权失败,提示用户开启权限
    wx.showModal({
      title: '未授权地理位置信息',
      content: '请在设置中打开地理位置权限',
      showCancel: false,
      confirmText: '确定'
    });
  }
});

Extra: select address

In the applet management background, "Development" - "Development Management" - "Interface Settings" self-activate the interface permission;

wx.chooseAddress({
      success(res){
        console.log(res)
      },
      fail(err){
        console.log(err)
      }
    })

The original interface for editing the delivery address can be invoked; an existing address can be selected, or a new address can be added;

10. Automatically detect version updates

in app.js

App({
  onLaunch() {
    this.autoUpdate();
  },
  globalData: {
    userInfo: null
  },
  //检测版本更新
  autoUpdate(){
    //检测当前设备是否可用getUpdateManager api
    if(wx.canIUse('getUpdateManager')){
      const updateManasger = wx.getUpdateManager();
      //检测是否有版本更新
      updateManasger.onCheckForUpdate(function(res){
        if(res.hasUpdate){
          wx.showModal({
            title: '更新提示',
            content: '需要重启小程序完成更新',
            success: (res) => {
              if (res.confirm) {
                //更新成功,强制重启小程序并使用新版本
                updateManasger.onUpdateReady(function(){
                  updateManasger.applyUpdate();
                })
                //更新失败,提示用户删除小程序重新进入
                updateManasger.onUpdateFailed(function(){
                  wx.showModal({
                    title: '更新提示',
                    content: '小程序更新失败,请您删除当前小程序,重新搜索打开!'
                  })
                })
              }
            }
          })
        }
      })
    }
  }
})

11. Configure applets in enterprise WeChat

1. Log in to the corporate WeChat background: Apps and Mini Programs-Mini Programs-Associated Mini Programs; or log into the Mini Program background: Settings-Association Settings-Associated Corporate WeChat; 2. The mini-program administrator authorization is required during the association process;
3
. The visible range of the applet is set; in this way, members of WeChat Work can see the applet on the workbench;

12. Scan QR code, take photo, photo album

To realize the functions of scanning codes, taking photos and photo albums in the applet, you can use the API interface provided by WeChat. The following is the specific implementation method:
1. Scanning the code
needs to obtain the camera permission. User authorization can be requested through the wx.authorize interface, or set in the app.json file"permission": {"scope.camera": {"desc": "用于扫码"}}

scanCode: function() {
    wx.scanCode({
      onlyFromCamera: true,
      success(res) {
        console.log('扫码成功', res.result)
      },
      fail(res) {
        console.log('扫码失败', res)
      }
    })
  }

2. Taking pictures
also requires access to camera permissions;

wx.chooseMedia({
      count: 1,
      sizeType: ['original'],
      sourceType: ['camera'],
      success(res) {
        console.log('选择照片成功', res.tempFilePaths)
      },
      fail(res) {
        console.log('选择照片失败', res)
      }
    })

3. Photo album
Need to obtain photo album access permission. User authorization can be requested through the wx.authorize interface, or set in the app.json file"permission": {"scope.writePhotosAlbum": {"desc": "用于保存图片到相册"}}

wx.chooseMedia({
      count: 1,
      sizeType: ['original'],
      sourceType: ['album'],
      success(res) {
        console.log('选择照片成功', res.tempFilePaths)
      },
      fail(res) {
        console.log('选择照片失败', res)
      }
    })

13. Configure customer service

Move to: Wechat applet access customer service function

14. API encapsulation

Create a new folder api under the same directory;
1. Create a new http.js: define baseUrl for later maintenance;
2. Create a new request.js:

import { baseUrl } from "./http"
import storage from "../utils/storage";
module.exports={
  request:function(url, method, data){
    let fullUrl = `${baseUrl}${url}`;
    let token = storage.get('token');
    wx.showLoading({ title: '数据请求中' });
    return new Promise((resolve,reject)=>{
      wx.request({
        url: fullUrl,
        method,
        data,
        header:{
          'content-type': 'application/json', 
          'Authorization': 'Bearer' + token
        },
        success(res){
          wx.hideLoading();
          if(res.data.status == 200){
            resolve(res.data);
          }else if(res.data.status == 401){
            wx.showToast({
              title: '登录失效',
              icon: "none"
            })
            wx.reLaunch({
              url: '/pages/login/index',
            })
          }else{
            wx.showToast({
              title: res.data.message,
              icon: "none"
            })
            reject(res.data.message);
          }
        },
        fail(err){
          wx.reLaunch({
            url: '/pages/login/index',
          })
          wx.hideLoading();
          wx.showToast({
            title: err.errMsg,
            icon: "none"
          })
          reject(err);
        }
      })
    })
  }
}

3. Create a new module api file (user_api)

import { request } from "./request"
module.exports = {
  user: (data) => request("user","get",data)
}

4. Page call

const user_api = require("../../api/user_api");
user_api.user(data).then(res=>{
      console.log(res)
})

15. Local storage package

Create a storage.js file under the utils folder

/**
 - 同步新增:get(key)
 - 同步修改、删除:set(key,value);只传递 key 就可以删除对应的key:value
 - 同步清空:clear()
*/
export default class storage {
  //同步获取
  static get(key){
    if(!key) return null;
    return wx.getStorageSync(key);
  }
  //同步存储、删除
  static set(key, value){
    if(!key) return;
    if(value == null || value == 'undefined'){
      return wx.removeStorageSync(key);
    }else{
      return wx.setStorageSync(key, value);
    }
  }
  //同步清空
  static clear(){
    return wx.clearStorageSync();
  }
}

16. Bottom safety distance component

Encapsulate a global component safe, with env (safe-area-inset-botton)

<!--全局组件:底部安全距离-->
<view style="padding-bottom: env(safe-area-inset-botton);">
  <solt></solt>
</view>

17. Form verification tool package

Encapsulation verification tool class

// 表单校验工具
export class validator {
  constructor(rules){
    this.rules = rules
    this.error= []
  }
  
  validate(form){
    this.error = [];
    Object.keys(form).forEach(key=>{
      let rule = this.rules[key];
      let required = this.rules[key].required;
      let message = this.rules[key].message;
      let maxLength = this.rules[key].maxLength;
      let fn = this.rules[key].fn;
      if(rule){
        if(required && !this.checkValue(form[key]) && !Array.isArray(form[key])){
          return this.error.push(message || ('请填写'+key));
        }
        //校验key是数组
        if(required && this.checkValueArr(form[key]).isNull && Array.isArray(form[key])){
          return this.error.push(message || (`请完善${this.checkValueArr(form[key]).key}信息`));
        }
        if(maxLength && this.max(form[key], maxLength)){
          return this.error.push(`最多可输入${maxLength}个字!`);
        }
      }
    })
    return this.error;
  }
  checkValueArr(arr){
    let isNull = false;
    let key = null;
    for(let i in arr){
      if(!arr[i].value){
        isNull = true;
        key = arr[i].name;
        break;
      }
    }
    return {isNull,key}
  }
  checkValue(value){
    return value.toString().length > 0;
  }
  max(value, maxLength){
    return value && value.length > maxLength;
  }
}

page use

let rules = {
  test:{
    required:true,
    message:"请输入用户名"
  }
}
let fromVal = new validator(rules);

Use the class class to pass in the rules when new, and perform the following operations when submitting the verification, and pass in the form data for verification;

let err = fromVal.validate(this.data.form);

The above is a method I encapsulated according to my own project based on the ideas of the predecessors.

18. Rich text editor editor

editor is a component provided by the applet, and it works with the EditorContext api to realize the operation of the toolbar;

<!--富文本编辑器-->
<view style="margin: 20rpx; background: #f0f0f0;">
  <view style="display: flex; justify-content: space-around; padding-bottom: 20rpx;">
    <view class="item" bindtap="format" data-type="bold">加粗</view>
    <view class="item" bindtap="format" data-type="italic">斜体</view>
    <view class="item" bindtap="format" data-type="underline">下划线</view>
    <view class="item" bindtap="undo">撤回</view>
    <view class="item" bindtap="redo">恢复</view>
    <view class="item" bindtap="insertImg">插入图片</view>
    <view class="item" bindtap="clear">删除</view>
  </view>
  <editor 
  style="border-radius: 10rpx; border: 1rpx solid #ccc; background: #fff;"
  id="myEditor"
  placeholder="请输入"
  bindstatuschange="statusChange"
  bindready="onEditorReady"
  ></editor>
</view>
<van-button bindtap="submit">提交</van-button>
Component({
  properties: {

  },
  data: {
    editorCtx:''
  },
  methods: {
    // 初始化,获取到编辑器节点,缓存在data中,方便下面操作
    onEditorReady(){
      let that = this;
      let query = wx.createSelectorQuery();
      query.in(that).select("#myEditor").context();
      query.exec(res=>{
        that.editorCtx = res[0].context;
      })
    },
    undo(){
      console.log(1)
      this.editorCtx.undo();
    },
    redo(){
      this.editorCtx.redo()
    },
    insertImg(){
      let that = this;
      wx.chooseMedia({
        count:1,
        mediaType:["image"],
        sourceType:["album"],
        success(res){
          that.editorCtx.insertImage({
            src:res.tempFiles[0].tempFilePath
          })
        }
      })
    },
    clear(){
      this.editorCtx.clear()
    },
    submit(){
      this.editorCtx.getContents({
        success(res){
          console.log(res)
        }
      })
    },
    format(e){
      let type = e.currentTarget.dataset.type;
      this.editorCtx.format(`${type}`)
    }
  }
})

19. How does the applet operate the content of the previous page

back(){
    const pages = getCurrentPages();
    const prePage = pages[pages.length-2];
    console.log(prePage)
    prePage.setData({
      msg:'sssss'
    })
    wx.navigateBack();
  }

If you want to listen to the previous page, you can call the method of the previous page later;

other

1. The border of the applet disappears on the 33rd element of the circular list of some IOS models

1rpx The rendering pixels of some IOS models are relatively low, and occasionally it does not display. It can be set to 1px and then scale the border;

2. When using flex: 1 for multi-line overall layout, the page is a bit messy

Try to avoid using flex:1 for multi-line overall layout; because this 1 is allocated for the remaining space, not the width of the parent element;

3. The applet modifies object properties
let c = `arr[${i}].name`
this.setData({
	"obj.a":b,
	[c]:d
})
4. The applet prevents bubbling

Use catchtap to bind events;

5. Mini Program Life Cycle Sequence

Application: onLaunch onShow
Page: onLoad onShow onReady
Component: attached() -> ready() -> moved() -> detached()

6. Small program dynamic binding
class="name {
   
   {isOk?'a':'b'}}"
style="height:{
   
   {nav}}rpx"
7. Obtain the dom node information of the applet:

page:

var query = wx.createSelectorQuery();
query.select('.header').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec((res) => {
	var listHeight = res[0].height; // 获取list高度
	this.setData({
		height:listHeight
	})
})

Components:

var query = wx.createSelectorQuery().in(this);
query.select('.header').boundingClientRect()
query.selectViewport().scrollOffset()
query.exec((res) => {
	var listHeight = res[0].height; // 获取list高度
	this.setData({
		height:listHeight
	})
})

The method is placed in the ready cycle, if it is still not available, it is wrapped with a timer;

8. There is no problem with the display of custom components on the applet simulator, but not on the real machine

Add "component" to component json: true

9. The first scan code to open the applet interface data is blank, and it can be displayed normally when the debug mode is turned on

You only need to configure the server domain name as a legal domain name in the background of the applet

10. When using the scan code link to open the applet, the configured test account must be completely consistent with the address, parameters, and parameter values ​​of the current request, otherwise it may scan the code to 404;
11. The priority of canvas is too high, covering other label issues

1. Use the cover-view, cover-image and other tags provided by uni-app;
2. Give the canvas tag a judgment control to display and hide;

12. Mini program custom header

Set navigationStyle:custom in the configuration, there is a difference between native and uni-app; get device header information: uni.getSystemInfo({}), get status bar height, navigation bar height;

13. Small program life cycle and jump

1. Differences in jumping methods

navigateTo: jump to the next page, keep the current page;
navigateBack: close the current page, jump to the previous page;
redirectTo: close the current page, jump to other pages;
reLaunch: close all pages, jump to a certain page ;
switchTab: close all non-tabBar pages and jump to the tabBar page; the path cannot carry parameters;

Use the method getCurrentPages() in js to get the current page;

2. Life cycle

onLaunch: triggered by the completion of the initialization of the applet, only once; (obtain user information)
onShow: triggered by the applet startup, and the background enters the foreground;
onHide: triggered by the applet entering the background from the foreground; onError: collect
error information;
When the time comes, use it to complain and deal with it;

onLoad: triggered by page initialization, a page is called only once; (send request, initialize data)
onShow: triggered by page display, background enters foreground;
onReady: triggered by page initialization, only called once;
onHide: triggered by switching to background;
onUnload: page unloaded Trigger;
onPullDownRefresh: page pull down refresh trigger
onReachButton:

3. The relationship between the two

navigateTo:onHide - onLoad - onShow - onReady
navigateBack:onUnload - onShow
redirectTo:onUnload - onLoad - onShow - onReady

14. The applet generates a QR code for access

Mini program background, upper right corner - tool; enter the page path entered after scanning the code;

15. WeChat developer tools simulate enterprise WeChat

Download the Enterprise WeChat plug-in (Settings-Extended Settings-Simulator Plug-in-Enterprise WeChat Simulator), and then adjust the mini-program mode to the Enterprise WeChat mini-program mode;

16. After using van-field to click on the applet, the input box will lose focus first and then click again to focus. It is normal in the development tool

Using the van-field component, you can check whether the configuration parameters of the component are correct, such as whether the auto-focus or focus parameter is set to true

17. ios jump failure problem

The page jumps, ios will occasionally fail to jump, and the callbacks of navigateTo success and completion can be printed out; the specific reason is unknown, delaying the jump for 1 second after the network request gets the result can reduce the probability of failure, but the jump still occurs The case of transfer failure;
the guess may be related to the asynchronous focus;
http://shop.jisuapp.cn/pecial/a79256.html

18. Vscode develops WeChat applets

Install the plug-in "WeChat applet plug-in", create a small program project with WeChat developer tools, and then open it with vscode; you can develop the code;

Guess you like

Origin blog.csdn.net/weixin_43299180/article/details/130699531