2023-09-06
小程序
00
请注意,本文编写于 325 天前,最后修改于 325 天前,其中某些信息可能已经过时。

目录

背景
微信小程序架构
微信已经有了公众号生态为什么还要造个小程序生态
为什么采用Hybrid技术
双线程模型
为什么要采用双线程?
小程序的运行机制
小程序生命周期
组件系统
Exparser框架
内置组件
自定义组件
小程序核心语法
基本项目目录
基本配置
全局对象
常见API
视图层
WXML
WXSS
WXS
事件系统
基础组件
同层渲染原理
性能优化
合理使用setData
渲染性能优化
页面切换优化
资源加载优化
内存优化
从web开发者角度去看小程序开发
对比小程序原生开发与h5原生开发
对比小程序开发与vue开发
对比uniapp开发与小程序开发异同点
微信小程序开发调试相关问题

本文是基于微信小程序官网及网上的一些文章做的总结, 一些内容比较抽象主要用于复习巩固,对于没有小程序开发经验的同学还是推荐先阅读小程序官方文档,写写案例。

背景

  • 2016年,应用号 -> 小程序,1月张小龙提出应用号,11月微信小程序开发公测
  • 2017年,1月微信小程序正式发布
  • 2018年,1月大量企业、开发者、资本、运营入场;3月,十家手机厂商推出快应用;9月支付宝小程序正式上线、百度小程序入场、头条小程序入场,10月抖音小程序入场
  • 2022年,微信小程序日活用户超5亿

微信小程序架构

  • 双线程模型 逻辑层和渲染层是分开的
  • 使用类似于微信 JSSDK 这样的 Hybrid 技术(即界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力)。

微信已经有了公众号生态为什么还要造个小程序生态

公众号模式有哪些问题?

  • 如果任由a标签可以任意跳转 (跳到哪里微信不知道,跳出去的网站可能涉及安全问题)
  • js可以操作dom,如触发点击事件,可能在用户不知情的情况下获取了用户的隐私。
  • 任由ajax随便请求,存在CSRF攻击的风险,在微信生态下的问题,也会给微信带来一些商誉影响
  • eval、Function 等可能引发 XSS
  • 自己造轮子除了更强的把控商家用户的行为,也给用户带来更好的体验,如使用微信or原生api的能力。
  • 国家监控,国家会对微信提出一些整改要求,微信需要从技术层面限制把控商户的行为
  • 。。。

根本原因:

  • 公众号模式还是一个web应用模式,web讲究开放互联,对于web应用来说微信的感知能力要差很多。
  • 微信则是需要更加强有利的技术去感知商户及用户行为、管控商家、服务用户,增加用户黏性,获取更多的流量,塑造微信生态(形成超级APP),最后实现自己的商业壁垒。

直接原因:

  • 为了管控与安全的需要同时兼顾了性能。关于管控与安全,对内来说微信自身有这个诉求,对外国家对它也有这个诉求。

为什么采用Hybrid技术

首先介绍下三种UI渲染技术

  1. Native原生渲染:流畅可访问系统api 高留存;高成本、更新体验差
  2. Web技术渲染:成本低、跨平台;无法使用系统功能、低留存
  3. Hybrid混合渲染、web+native (cordovah5+

采用Hybrid技术有一下优势

  • 快速加载(本地加载资源+离线使用)体验优于web 接近原生体验
  • 提供移动端的能力以及自己的能力
  • 简单高效的开发及发布(web可以灵活发版,原生不能)

双线程模型

首先了解下双线程模型

image.png

  • 小程序的视图层和逻辑层分别由两个线程管理:视图层的界面使用Webview进行渲染;逻辑层采用JSCore运行JavaScript代码
  • 一个小程序有一个逻辑层(方便逻辑状态共享),视图层有多个webview (主要是性能原因,DOM简单,页面切换也快)
  • 两个线程间的通信则由 JSBridge 中转
    • iOS 是利用了WKWebView 的提供 messageHandlers 特性,
    • 而在安卓则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容层,主要提供了调用(invoke)和监听(on)这两种方法。
  • 使用双线程也是从管控与安全的角度考虑的,
    • 避免JS操作DOM
    • 提供一个沙箱环境来运行开发者的JavaScript 代码

image.png

  • 双线程缺点 : 天生的延时

为什么要采用双线程?

  • 为什么不使用浏览器线程模型?
  • 为什么不使用 Web Worker?

不使用浏览器线程模型主要有两个原因

  1. 前面提到的管控与安全
  2. 浏览器JS 是单线程的,JS执行阻塞dom渲染,dom渲染阻塞JS

不使用WebWorker的原因

  • worker本身非常耗资源,除了计算资源消耗还有和主线程通信的损耗也很严重;小程序逻辑层和试图层是同级线程性能相对可靠
  • web worker 限制也很多,不能跨域,双线程安全

小程序的运行机制

  1. 启动

image.png

  1. 更新机制

image.png

小程序生命周期

image.png

组件系统

也是从安全管控的要求考虑,不直接提供HTML的能力(如你不能使用<a>标签任意跳转); 微信设计一套组件框架——Exparser。基于这个框架,内置了一套组件,以涵盖小程序的基础功能,便于开发者快速搭建出任何界面。同时也提供了自定义组件的能力,开发者可以自行扩展更多的组件,以实现代码复用。

Exparser框架

Exparser的组件模型与WebComponents标准中的ShadowDOM高度相似。

内置组件

定义内置组件的原则: 没有这个组件的话,在小程序架构里无法实现或者实现不好某类功能

  • open-data组件提供展示群名称、用户信息
  • button组件里open-type属性

自定义组件

  • 运行原理
  • 组件间通信
    • WXML属性值传递 父到子
    • 事件系统 子到父
    • selectComponent 相当于vue$ref
    • relations 类似vueprovide/inject

小程序核心语法

基本项目目录

  • pages 页面目录
    • index 首页目录
      • index.js/json/wxml/wxss 首页逻辑、配置、模板、样式
  • app.js 全局入口文件
  • app.json 全局配置文件
  • app.wxss 全局样式文件
  • project.config.json 项目配置文件
  • sitemap.json 微信索引配置文件

基本配置

  • 全局配置
  • 页面配置
  • 索引地图配置

全局对象

  • 不管是逻辑层还是试图层,微信都做了一个沙盒环境
    • 逻辑层没有windowdocument等浏览器对象
  • 通过wx对象,提供一些移动端的能力及微信自身的能力
  • App Service
    • App() 注册程序
    • Page() 注册页面
    • getApp() 获取 APP 实例
    • getCurrentPages() 获取当前页面栈
    • API wx.xxx()
    • 模块化能力

常见API

  • 路由
    • wx.navigateTo / redirectTowx.switchTab / reLaunchwx.navigateBack 路由跳转
  • 界面
    • wx.showToast / showLoading / showModal 显示消息提示、加载提示、模态窗
  • 网络
    • wx.request / downloadFile / uploadFile 网络请求、文件下载、文件上传
  • 数据缓存
    • wx.setStorage / getStorage 缓存数据存取
  • 开放接口
    • wx.login / authorize / getUserInfo 登录、授权、获取用户信息
  • WXML
    • wx.createSelectorQuery 获取节点信息

视图层

  • WXML (WeiXin Markup lauguage):描述页面结构
  • WXSS (WeiXin Style Sheet):描述页面样式
  • WXS (WeiXin Script):小程序脚本语言

WXML

  • 数据绑定:wxml 动态数据来自 Page 中的 data
  • 语法规则:Mustache 语法 {{ }} 为运算标记,内部为表达式
  • 控制属性:wx:if / wx:for / model:value
  • 模板
  • 引用
    • <import> 引入目标文件的 template 模板
    • <include> 引入目标文件除 templatewxs 以外代码(相当于代码直接拷贝到该标签位置)

WXSS

  • 可使用绝大多数 CSS 特性
  • 扩展
    • 尺寸单位 rpx (responsive pixel)
      • iPhone6 / 375px /750 物理像素 —— 1px = 2rpx
    • 样式导入 @import
      • @import “common.wxss”

WXS

  • 优点:一定程度上可以缓解跨线程通信的开销
    • 非纯 JS 语法、不支持 ES6
    • 不能调用其他 JS 文件函数、不能使用小程序 API
    • 不能作为自定义组件的事件回调
  • 使用场景:过滤器、拖拽(频繁通信)

事件系统

  • 事件:用户行为反馈到逻辑层处理
  • 事件绑定 (与h5相比,不支持条件编程,如虚拟滚动的实现)
    • bind:[eventName]     冒泡事件
    • capture-bind:[eventName] 捕获事件
    • catch:[eventName]     冒泡事件(阻止事件继续冒泡)
    • capture-catch:[eventName] 捕获事件(阻止事件继续捕获、冒泡)
    • mut-bind:[eventName]   互斥事件
  • 绑定数据
    • data-[dataName]

基础组件

  • 内置组件:viewtextimagebuttoniconweb-view…
  • 原生组件(同层渲染技术):textareavideocanvasmapcameralive-player/pusherinput
  • 自定义组件

同层渲染原理

  • 同层渲染:通过一定技术手段,使原生组件直接在WebView层渲染
    • iOS:基于 WKWebView 的原生组件 WKChildScrollView
      • 创建 DOM 节点并设置 overflow: scroll(内核创建 WKChildScrollView)
      • 微信端找到 DOM 节点对应的 WKChildScrollView
      • 将原生组件挂载到对应 WKChildScrollView 容器
    • Android:基于 ChromiumWebPlugin 插件机制
      • 创建 <embed> DOM 节点并指定组件类型(内核创建 WebPlugin 实例,生成 RenderLayer
      • 将原生组件绘制到 RenderLayer 绑定的 SurfaceTexture
      • 通知 Chromium 渲染该 RenderLayer、渲染 embed 节点

性能优化

合理使用setData

  • 只包括渲染相关的数据
  • 控制setData频率 nextTick策略
  • 差量更新 this.setData({'obj.list.0.name':'差量更新'})
  • 避免在切后台后仍进行高频的 setData,例如倒计时更新

渲染性能优化

  • 滚动相关推荐优先使用滚动驱动动画或者wxs
  • 使用IntersectionObserver监听元素曝光
  • 控制WXML数量和层级

页面切换优化

  • 减少或避免在 onHide/onUnload 中执行耗时逻辑,如同步接口调用、setData

资源加载优化

  • 控制图片资源的大小
  • 预先给定图片的尺寸 预渲染优化

内存优化

  • 合理使用分包,
  • 按需注入,用时注入
  • 垃圾回收方面 事件监听要移除、清理定时器

从web开发者角度去看小程序开发

对比小程序原生开发与h5原生开发

  1. 文件名称三端到四段
  2. 标签名称
    1. 精简了
    2. 新增一些与移动端的组件
    3. cover-view 可覆盖原生组件的视图容器 cover-view需要多强调几句,uni-app的非h5端的videomapcanvastextarea是原生组件
  3. js方面
    1. 都遵从ecma规范,标准js语法和api都支持 ,运行环境从浏览器变成v8引擎
    2. 然而浏览器下的JS,如DOMBOM没有了
    3. 以前的dom操作,改成MVVM模式
    4. js api 发生变更
      1. alert/comfirm ==> wx.showModel
      2. ajax ==> wx.request
      3. cookie/session没有了 用localStorage实现
  4. css方面
    1. 通用选择器 没有了 body ==> body
    2. 单位 rpx
    3. 推荐使用flex
    4. css里背景图和字体文件 不能>40Kb 超过这个只要用base64或者外链
  5. 工程结构和页面管理
    1. h5工程化开发者自由实现,
    2. 小程序通过配置app.json管理页面、分包、tabbar、导航相关配置,
    3. 组件也是在json文件中配置

对比小程序开发与vue开发

  1. 生命周期 口述
  2. 模版语法
    1. 小程序的数据绑定参考了vue,但自己修改了一些。在uni-app中只支持标准的vue,不支持小程序的数据绑定语法(bindinput解决)
    2. 数据绑定 列表渲染 显示和隐藏
  3. 事件
    1. 写法
    2. 传值
  4. 响应式
    1. 小程序里的setDatauni-app里并不存在,因为vue是自动双向数据绑定的。直接通过赋值方式修改数据,如果数据绑定到界面上,界面会自动更新渲染
      1. 取值this.data.reason
  5. 组件通信
    1. 注册使用组件
    2. 父子组件通信 类似vue
      1. 子组件通知父组件 triggerEvent
      2. 父组件调用子组件 $ref
      3. 子组件样式 通过props传递或控制子组件样式 或者子组件类名前面加上父组件类名

对比uniapp开发与小程序开发异同点

  1. 跨端开发 各端小程序、h5app、快应用
  2. 条件编译 开放包容
  3. uni-app推荐使用flex布局,这个布局思路和传统流式布局有点区别。但flex的特色在于,不管是什么技术都支持这种排版,web、小程序/快应用、weex/rn、原生的iOSAndroid开发,全都支持flex。它是通吃所有端的新一代布局方案。
  4. 小程序的app.json被分成两段 page.jsonmainfest.json
  5. 原来的app.jsapp.wxss被合并到了app.vue

参考资料 白话uni-app 【也是html、vue、小程序的区别】 vue和微信小程序的区别、比较

微信小程序开发调试相关问题

  • 开发版 需要在微信小程序后台 添加为开发者才能进入,给开发着使用,能进行真机调试
  • 体验版 需要在小程序后台添加为项目成员,主要给测试、产品人员使用,
    • 同一个小程序体验版二维码永远不会变,可从微信小程序助手进入
    • 如果当前体验版是A上传的,A再次上传,体验版自动更新,如果是B上传,则需要在小程序后台切一下体验版
  • 生产版本, 对外开放,可以通过微信搜索找到
  • 真机调试
    • 微信扫码真机调试, 会新开一个干净的容器(无网络缓存、授权信息、数据缓存等)
    • 关闭真机调试,微信会留下一个开发版
    • 真机调试的开发版与开发着工具中的版本是相互隔离的
  • 开发版、体验版、生产版 共用同一个storage
  • VConsole
    • 开发版或体验版 打开调试 重启小程序后会有一个VConsole
  1. 简述小程序双线程模型
  2. 小程序与h5的区别
  3. 原生小程序与其他框架对比
  4. 小程序如何优化性能

参考资料:

本文作者:郭敬文

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!