Practical WeChat applet login, cloud development, webpack engineering

References:

WeChat official documentation

1. The applet framework wepy

Common frameworks: native applet, wepy (vue), uniapp (vue), taro (react)

  • Considering that the framework has not been changed in time after the original sound api is changed, the native applet framework can be used.
  • Cross-end and cross-platform requirements, it is recommended to use the applet framework

Wepy draws on vue grammar functions and supports vue writing features - vue technology friendly line

1. Life cycle

wepy life cycle is the same as native applet

  • application cycle

    • onLaunch is opened for the first time
    • onShow initialization completed
    • onHide toggle
  • page cycle

    • onLoad loads the page
    • onShow front and back switch
    • onHide front and back switching
    • onUnLoad redirect/routing switch
    • onPullDownRefresh pull down
    • onReachBottom pull up
    • onShareAppMessage Share
    • ……

2. Data Layer - Data Binding

this.setData({label: 'label'}) //原生小程序
this.label = 'label1' //wepy
复制代码
  1. How to monitor data changes, when setData multiple times, the number of communication is once or several times
  • In a rendering cycle, if setData is received multiple times, it will only be rendered once
  • jscore -> native ->web view
  1. How to Optimize Mini Program Data Communication and Improve Page Performance
  • Reduce calls to setData and merge multiple setData
  • It is best not to set data unrelated to interface rendering in data
  • Some data is not displayed on the page, contains complex data structures or super long strings, you should not use setData to set these data
  1. How does wepy do data binding optimization
  • Wepy internally implements a dirty data check mechanism, after the function is executed -> data-check
  • Compare newValue and oldValue. If there is any change, it will be added to the readyToSet queue, and finally a setData will be unified.
  • Only one dirty value checking process is allowed at a time

2. Double login state

1. Three states

visitor status, visitor status, member status

  • Guest state: unauthorized user information, no silent login
  • Guest mode: authorize user information and log in silently
  • Membership status: authorize the mobile phone number or use the account password to log in, use the mobile phone number for account association

2. Silent login

1. Login process

Use the applet login mechanism to achieve silent login, which is insensitive to customers.

  • 小程序:调用 wx.login() 获取临时登录凭证code ,并回传到开发者服务器。
    • code有效率期5min,短时间内多次获取code值不变,有缓存
  • 小程序:使用wx.request调用开发者服务器接口,上送code值。
  • 开发者服务器:调用auth.code2Session接口进行登录请求,获取用户唯一标识 OpenID、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key
    • 登录凭证校验接口:https://api.weixin.qq.com/sns/jscode2session
    • 上送:code + appid + appSecret
    • 接收:openid + session_key + unionid
    • 会话密钥 session_key 是对用户数据进行加密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥,code登录后会失效。
  • 开发者服务器:使用openid + unionid + session_key建立登录态,使用token鉴权或session鉴权,返回token或者sessionid
  • 小程序:将鉴权信息token或sessionid存入storage中,后续调用接口时携带鉴权信息。
  • 开发者服务器:根据上送鉴权信息,校验成功后,回传数据。
2、api解析
  • openid和unionid
    • openid
      • 客户在某一应用下的唯一标识:同一平台,不同应用,编号不同
      • 通过后台调用auth.code2Session登录凭证校验接口获取
    • unionid
      • 客户在同一个微信开放平台下的唯一标识:同一平台,不同应用,编号相同
      • 当前小程序已绑定到微信开放平台帐号可通过后台调用auth.code2Session接口获取
      • 前期通过getUseInfo获取,目前可通过wx.login获取,接口隔离
  • wx.getUserInfo
    • 存量:获取用户信息,获取unionid
    • 现状:匿名头像昵称、默认性别地区、加密后的身份认证
  • wx.getUserProfile
    • 弹出个人信息授权弹框
    • 成功后获取用户信息、调用失败
wx.getUserProfile({
    desc: 'desc',
    success: res => {
        console.log('wx.userProfile', res)
        app.globalData.userInfo = res.userInfo
        this.setData({
            userInfo: res.userInfo
        })
    }
})
复制代码
  • wx.login
    • 获取code
    • 获取unionid
wx.login({
    success: res => {
        console.log('wx.login', res)
        const _code = res.code
        app.globalData.code = _code
        this.setData({
            code: _code
        })
    }
})
复制代码
3、超时处理
  • 小程序到开发服务器认证超时:校验sessionkey,重新进行登录或重新发起请求
  • 开发者服务器到wx服务器认证超时:重新发起请求
  • 小程序到开发者服务器登录后交易超时:重新发送请求即可

3、用户登录

操作具体业务,需要会员及用户体系时,添加用户登录流程,弹出登录弹框,通常使用微信一键登录或账号密码登录两种方式,一般使用手机号进行用户体系关联。

  • 微信一键登录:提示用户授权手机号使用,getPhoneNumber
    • 授权使用手机号,则用手机号进行账号关联绑定,进行登录操作
    • 未授权使用手机号,登录失败,跳转至登录弹框
  • 账号密码登录:使用账号和密码认证登录
    • 登录成功后,进行账号关联绑定
    • 登录失败返回登录弹框

4、用户体系

账号saas系统中,同一账号关联:账号体系、套餐、动态权限等,同一账号查找不同属性。

三、云开发

参考资料:

  1. 微信官方文档
  2. 云开发实战

1、基础能力

  • 云函数:在云端运行的代码,微信私有的天然鉴权,开发者只需编写自身业务逻辑代码,相当于后端的NodeJs服务。
  • 作用:无需搭建服务器(省去了运维)。
  • 具体应用
    • 获取appId
    • 获取openId
    • 生成分享图
    • 调用腾讯云SDK
    • ...
  • 云数据库: 一个可以在小程序端操作,也能够在云函数中读写的json数据库。
  • 作用:无需自己建数据库。
  • 具体应用:数据的增加,删除,修改,查询。
  • 云存储: 可在小程序前端直接上传或下载云端文件,在云开发控制台可视化管理。
  • 作用:无需自建存储和 CDN。
  • 具体应用
    • 管理文件
    • 上传文件
    • 下载文件
    • 分享文件
    • ...
  • 云调用:基于云函数免鉴权使用小程序开放接口的能力,包括服务端调用、获取开放数据等能力。
  • 作用: 原生微信服务集成。
  • 具体应用
    • 服务器端调用,在云函数中使用云调用,调用服务器接口无需换取 access_token
    • 开放数据调用,对于返回一些敏感信息,例如数字签名秘钥,会话秘钥等
    • 模板消息推送

2、小程序云开发

1、设置云函数的路径

在项目根目录找到 project.config.json 文件,新增 cloudfunctionRoot 字段,指定本地已存在的目录作为云函数的本地根目录(在根目录下手动创建一个cloudfunction的文件夹,然后在project.config.json中进行配置一下),这个目录相当于后端Nodejs,它是可以通过终端npm安装一些第三方模块的。

{
    cloudfunctionRoot: './cloudfunction'
}
复制代码
2、初始化云环境

微信小程序的app.js中onLaunch生命周期中初始化云开发 picture.png

onLaunch: function () {
    //调用API从本地缓存中获取数据
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    if (!wx.cloud) {
        console.error('当前环境不支持云能力,请升级')
    } else {
        // 云能力的初始化
        wx.cloud.init({
            /**
             * env 参数说明:
             * env 参数决定接下来小程序发起的云开发调用(wx.cloud.xx)会默认请求到哪个云环境的资源; 此处请填写环境ID,环境ID可打开云控制台查看
             */
            traceUser: true
        })
    }
    this.globalData = {}
},
复制代码
3、引用云数据库
// 引用云数据库
const db = wx.cloud.database()

function getData(db_name) {
    const _userInfo = getApp().globalData.userInfo || {}
    const _token = _userInfo.token;

    return new Promise((resolve, reject) => {
        // 查询当前环境,获取表
        db.collection(db_name).where({
            _openid: 'user_openId'
        }).get({
            success: res => {
                console.log('[数据库][查询]:成功', res)
                //可以一次性获取多条记录。通过调用集合上的 `where` 方法可以指定查询条件
                const data = res.data[0];
                console.log('find result', data)
                resolve(data)
            },

            fail: err => {
                wx.showToast({
                    title: '查询失败',
                })
                reject(err)
            }
        })
    })
}
复制代码
  • 数据渲染
getData: function(){
    // 云化
    api.getData('list').then(feed => {
        const feed_data = feed.data
        console.log('getListData', feed_data)
        this.setData({
            feed:feed_data,
            feed_length: feed_data.length
        });
    })
}
复制代码

四、webpack工程化

参考资料:

  1. wx-mini
  2. mina-webpack

1、 安装项目依赖包

  • npm install --save-dev babel-core babel-loader babel-plugin-lodash babel-plugin-transform-runtime 安装babel,babel的作用是将es6的语法编译成浏览器认识的语法es5
  • npm install --save-dev file-loader 用于打包文件
  • npm install --save-dev sass-loader node-sass 用于编译sass
  • npm install webpack webpack-cli clean-webpack-plugin copy-webpack-plugin 用于webpack.config.babel.js配置
  • npm install --save lodash 一个一致性、模块化、高性能的 JavaScript 实用工具库
"dependencies": {
    "lodash": "^4.17.21",
    "moment": "^2.29.1"

},

"devDependencies": {
    "@babel/core": "^7.17.5",
    "@babel/preset-env": "^7.16.11",
    "@tinajs/mina-runtime-webpack-plugin": "^1.3.7",
    "babel-loader": "^8.2.3",
    "clean-webpack-plugin": "^4.0.0",
    "copy-webpack-plugin": "^6.0.0",
    "webpack": "^4.46.0",
    "webpack-cli": "^4.9.2"
},
复制代码

2、新建webpack.config.js

用于编译打包小程序

const { resolve } = require("path")
const CopyWebpackPlugin = require("copy-webpack-plugin")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const MinaRuntimePlugin = require("@tinajs/mina-runtime-webpack-plugin")
const webpack = require("webpack")
const debuggable = process.env.BUILD_TYPE !== "release"

module.exports = {
    context: resolve("src"),
    entry: {
        "app": "./app.js",
        "pages/index/index": "./pages/index/index.js",
        "pages/logs/logs": "./pages/logs/logs.js"
    },

    output: {
        path: resolve("dist"),
        filename: "[name].js",
        globalObject: "wx"
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: "babel-loader"
            }
        ]
    },

    plugins: [
        new webpack.EnvironmentPlugin({
            NODE_ENV: JSON.stringify(process.env.NODE_ENV) || "none",
            BUILD_TYPE: JSON.stringify(process.env.BUILD_TYPE) || "debug"
        }),

        new CleanWebpackPlugin({
            cleanStaleWebpackAssets: false
        }),

        new CopyWebpackPlugin({
            patterns: [{
                from: "**/*",
                to: "./",
                globOptions: {
                    ignore: ["**/*.js"],
                }
            }]
        }),

        new MinaRuntimePlugin({
            // scriptExtenstions: [".js"],
            // assetExtensions: [".less"]
        })
    ],

    optimization: {
        splitChunks: {
            chunks: "all",
            name: "common",
            minChunks: 2,
            minSize: 0
        },
        runtimeChunk: {
            name: "runtime"
        }
    },

    mode: debuggable ? "none" : "production"
}
复制代码

3、在package.json文件中加入指令

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "serve": "webpack --watch --progress",
    "build": "cross-env NODE_ENV=prodution BUILD_TYPE=release webpack"
},
复制代码

4、新建 .babelrc 文件,es语法转换

{
    "presets": ["@babel/env"]
}
复制代码

五、微信小程序问题汇总

  1. 自定义tabbar在页面存在下拉更新(scrollview)的时候,页面被下拉,tabbar也会跟着下拉。
  • 提前沟通,修改为原生tabbar
  1. require在小程序中不支持绝对路径,只能用相对路径去选取'../../../utils/tool.js'
//app.js  
App({
      require: function($uri) {
          return require($url);
      }
})

//comp.js
const Api = app.require('utils/tool.js'); //利用require返回uri带上/
复制代码
  1. 组件引用资源路径不能解析特殊字符或汉字
  • 规范文件命名
  1. {{}}模板中不能执行特殊方法,只能处理简单的四则运算
//期望:'34万元'
const money = 345678; 
<view>{{ money }}</view>
复制代码
  • 方案 利用wxs的format vue wxs 实现format
const fnToFixed = function(num) {
  return num.toFixed(2);
}
module.exports = {
  fnToFixed
}
<wxs src='../../../xxx.wxs' module="filters">
<view>{{ filters.fnToFixed(money) }}</view>
复制代码
  1. wxs无法使用new Date()
  • 方案: 使用getDate()方法
  1. setData过程中需要注意对象覆盖
  data: {
      a: '1',
      b: {
        c: 2,
        d: 3
      }
  }
  //会覆盖原对象b
  this.setData({
      b: { 
        c: 4
      }
  });
  //解决办法1
  const { b } = this.data;
  b.c = 4;
  this.setData({ b });
  //解决办法2: wx-update-data库
复制代码
  1. IOS的date不支持2020-06-26格式,必须要转成2020/06/26
  2. wx接口不promise,可使用wx-promise-pro库。

六、相关面试题

  1. 小程序优势:无需下载安装,直接使用,运行速度快

  2. 小程序页面构成:index.js(js交互逻辑)\index.json(页面配置)\index.wxml(html)\index.wxss(样式)

  3. 为何部分npm包在小程序中无法直接使用?小程序开发中遇到过执行环境问题吗?

  • 因为小程序的执行环境中,包解析编译时注入了上下文和全局环境
  • 如何解决:通用方式直接克隆源码,手动编译;使用工程化webpack
  1. 小程序与H5的区别:

    1. 运行环境:H5的宿主环境是浏览器,小程序基于浏览器内核重构的内置解析器,无dom、bom对象
    2. 系统权限:小程序能获得更多的系统权限
    3. 渲染机制:小程序逻辑层和渲染层是分开的,而H5页面UI渲染和js执行都是一个线程,会出现阻塞。
  2. 小程序生命周期:

    1. 应用的生命周期

      1. 首次打开小程序,触发onLaunch
      2. 初始化完成,触发onShow方法,监听小程序显示
      3. 从后台进入前台,触发onShow方法
      4. 从前台进入后天,触发onHide方法
      5. 小程序后台运行一定时间,或系统资源占用过高,会被销毁
    2. 页面的生命周期

      1. 小程序注册完成,加载页面,触发onLoad方法
      2. 页面载入后触发onShow方法
      3. 首次显示页面,触发onReady方法,渲染页面元素和样式,一个页面只会调用一次
      4. 小程序由前台进入后台运行或跳转其他页面时,触发onHide方法
      5. 小程序由后台到前台或重新进入页面时,触发onShow方法
      6. When using the redirect method wx.redirectTo or closing the current page and returning to the previous page wx.navigateBack(), the onUnload event is triggered
  3. Dual-threaded architecture of applet

    1. The rendering layer and logic layer of the applet are managed by two threads:
    • Rendering layer: All tasks related to page rendering are executed in the webview thread. There are multiple interfaces in a small program, so there are multiple webview threads in the rendering layer.
    • Logic layer: use jsCore thread to run js script
    1. The view layer and the logic layer communicate through the WeixinJsBridge of the system layer: the logic layer notifies the view layer of data changes, triggers the update of the view layer, and the view layer sends the triggered events to the logic layer for business processing.
    2. The specific process of page rendering is: in the rendering layer, the host environment will parse the js object from wxml. When the data changes in the logic layer, we pass the data from the logic layer to the rendering layer through the setData method provided by the host environment, and then go through the setData method provided by the host environment. Compare the difference before and after, apply the difference to the original DOM tree, and render the correct UI page.
  4. Mini Program Operation Mechanism

    1. Hot start: The user has already opened a certain applet, and then opens the applet again within a certain period of time, no need to restart at this time, just switch the applet in the background to the foreground
    2. Cold start: The user opens the applet for the first time or opens it again after being actively destroyed by WeChat, and the applet is reloaded and started.
    3. Destruction: Only when the applet enters a certain time in the day after tomorrow, or the system occupies too much resources, will it be really destroyed.

Guess you like

Origin juejin.im/post/7079336177387601933