实战微信小程序登录、云开发,webpack工程化

1,348 阅读11分钟

参考资料:

微信官方文档

一、小程序框架wepy

常用框架:原生小程序、wepy(vue)、uniapp(vue)、taro(react)

  • 考虑到原声api变更后,框架未及时变更情况,可使用原生小程序框架。
  • 跨端和跨平台需求,建议使用小程序框架

wepy借鉴了vue语法功能,支持vue书写特征 - vue技术友好行

1、生命周期

wepy生命周期同原生小程序

  • 应用周期

    • onLaunch 首次打开
    • onShow 初始化完成
    • onHide 切换
  • 页面周期

    • onLoad 加载页面
    • onShow 前后台切换
    • onHide 前后台切换
    • onUnLoad 重定向 / 路由切换
    • onPullDownRefresh 下拉
    • onReachBottom 上拉
    • onShareAppMessage 分享
    • ……

2、数据层-数据绑定

this.setData({label: 'label'}) //原生小程序
this.label = 'label1' //wepy
  1. 如何做到监听数据改变,多次setData时候,通信次数是一次还是几次
  • 在一次渲染周期内,收到多次setData的话,只会渲染一次
  • jscore -> native ->web view
  1. 如何优化小程序数据通信,提升页面性能
  • 减少setData的调用,合并多个setData
  • 与界面渲染无关的数据最好不要设置在data
  • 有些数据不在页面中展示,包含复杂数据结构或者超长字符串,则不应该使用setData来设置这些数据
  1. wepy如何做数据绑定优化
  • wepy内部实现了一个脏数据检查机制,函数执行完成之后 -> data-check
  • newValue 和 oldValue做比较,如果有变化,就会加入到readyToSet的队列中,最后统一做一个setData
  • 同一时间只允许一个脏值检查流程进行

二、双重登录态

1、三种状态

访客态、游客态、会员态

  • 访客态:未授权用户信息,未静默登录
  • 游客态:授权用户信息,进行静默登录
  • 会员态:授权手机号或使用账号密码登录,使用手机号进行账号关联

2、静默登录

1、登录流程

利用小程序登录机制,实现静默登录,对客户无感。

  • 小程序:调用 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生命周期中初始化云开发 图片.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. 当使用重定向方法wx.redirectTo或关闭当前页面返回上一页wx.navigateBack(),触发onUnload 事件
  3. 小程序的双线程架构

    1. 小程序的渲染层和逻辑层分别由2个线程管理:

    • 渲染层:页面渲染相关的任务全部放在webview线程里执行,一个小程序存在多个界面,所以渲染层存在多个webview线程

    • 逻辑层:采用jsCore线程运行js脚本

    1. 视图层和逻辑层通过系统层的WeixinJsBridge进行通信:逻辑层把数据变化通知到视图层,触发视图层面的更新,视图层把触发的事件发送给逻辑层,进行业务处理。
    2. 页面渲染的具体流程是:在渲染层,宿主环境会吧wxml解析程js对象,在逻辑层发生数据变更的时候,我们通过宿主环境提供的setData方法把数据从逻辑层传到渲染层,再经过对比前后的差异,把差异应用在原来的dom树上,渲染出正确的ui页面。
  4. 小程序运行机制

    1. 热启动:用户已经打开某小程序,然后在一定时间内再次打开该小程序,此时无需重启启动,只需将后台的小程序切换到前台
    2. 冷启动:用户首次打开小程序或被微信主动销毁后再次打开,小程序重新加载启动。
    3. 销毁:只有当小程序进入后天一定时间,或者系统占用资源过高,才会被真正销毁。