微信小程序-学习笔记

双线程模型

微信小程序基于 WebView 环境下使用双线程模型架构, 其实本质就相当于开了一个浏览器, 基于Webkit的JSCore渲染一个页面进行展示, 其包含 JS 逻辑和视图渲染(DOM树的创建, CSS解析, 样式计算, Layout, Paint)都会发生在同一线程, 但其执行过多的JS逻辑会阻塞渲染, 导致页面卡顿。

基于此, 小程序为了考虑性能和安全, 采用了[双线程]的架构。

开启两个 WebView 线程, 一个执行渲染, 一个调用 JSCore 处理js逻辑, 再通过原生(微信客户端)的桥接(bridge)计算实现两个 WebView 线程之间的通信, 以达到页面渲染更新的效果。

微信小程序后推出了Skyline渲染引擎, 其类似于Flutter渲染, 更加接近原生的体验。

为什么会出现 WXS

由于双线程模型, 主要关于视图渲染的线程是不能直接调用JS逻辑的, 可能是由于两个线程之间频繁通信对原生应用的开销太大, 微信小程序底层并没有设置这种直接通信的方式, 但为了能够实现开发者的需求, 于是推出了 WSX 语法, 也就是在负责渲染视图的线程中也可以调用 JSCore, 进而实现页面与JS逻辑的通信。

但尽量避免在 WSX 中编写复杂的逻辑, 因为其所在的线程还要进行视图渲染, 避免阻塞。

WXS 的使用方式一

通过 wxs 标签的形式, wsx 标签中包裹 js 代码, 只能是 ES5 的语法, 并且需要进行导出, 导出使用CommonJs的方式。

1
2
3
4
5
6
7
<wxs module="format">
function formatPrice(price) {
return '¥' + price
}

module.exports = { formatPrice: formatPrice }
</wxs>

要在 wxs 标签中明确编写module属性, 为每一个wxs设置一个独特的标识, 通过该表示使用其中定义的方法。

1
<text {{format.formatPrice('12414')}}</text>

WXS 的使用方式二

定义以.wxs为后缀名的文件, 如format.wxs

在其中编写JS代码

1
2
3
4
function formatPrice(price) {
return "¥" + price;
}
module.exports = { formatPrice: formatPrice };

wxml中通过wxs标签引入该文件

1
<wxs module="format" src="/utils/format.wxs">

组件的样式细节

组件内的样式对外部样式的影响

  • 组件内的class样式, 只对组件wxml内的节点生效, 对于引入组件的Page页面不生效

  • 组件内不能使用id选择器、属性选择器、标签选择器(会对外部样式造成影响)

外部样式对组件内样式的影响

  • 外部使用class样式, 只对外部wxml的class生效, 对组件内是不生效的

  • 外部使用了id选择器、属性选择器不会对组件内样式产生影响

  • 外部使用了标签选择器, 会对组件内产生影响

如何让class可以相互影响

  • 在Component对象中, 可以传入一个options属性, 其中options属性中有一个styleIsolation(隔离)属性

  • styleIsolation三个取值

    • isolated: 默认值, 表示启用样式隔离, 在自定义组件内外, 使用class指定的样式将不会互相影响
    • apply-shared: 表示页面wxss样式将影响到自定义组件, 但自定义组件wxss中指定的样式不会影响页面
    • shared: 表示页面wxss样式将影响到自定义组件, 自定义组件wxss中指定的样式也会影响页面和其他设置了

mark 传递参数的细节

mark语法: mark:[自定义名称]="xxx"

1
2
3
4
5
<view mark:dd="111">
<view mark:name="outer">
<view mark:name1="inner">1111</view>
</view>
</view>

通过mark传递参数, 会从被点击组件向上合并所有定义了mark属性的祖先组件, 得到一个合并后的mask对象, 即使事件通过catch拦截冒泡传递了。

自定义组件

组件生命周期

Component({})中的lifetimes中写入对应组件生命周期函数

1
2
3
4
5
6
7
8
9
10
11
12
13
Component({
lifetimes: {
created() {
console.log("组件被创建created");
},
attached() {
console.log("组件被添加到组件树中attached");
},
detached() {
console.log("组件从组件树中移除detached");
},
},
})
  • created: 组件实例被创建, 但节点树还未插入文档树

  • attached: 组件实例被插入文档树后触发

  • ready: 组件实例被创建, 并且节点树已经插入文档树后触发

  • moved: 组件实例被移动到文档树 another-component 之前触发

  • detached: 组件实例被从文档树移除后触发

  • error: 组件实例发生错误时触发

组件所在页面的生命周期

Component({})中的pageLifetimes中写入对应生命周期函数

1
2
3
4
5
6
7
8
9
10
Component({
pageLifetimes: {
show() {
console.log("页面显示show");
},
hide() {
console.log("页面隐藏hide");
},
},
})
  • load: 页面加载时触发

  • show: 页面显示时触发

  • hide: 页面隐藏时触发

插槽

微信小程序的自定义组件插槽与 Vue 的写法一致, 但微信小程序不支持默认插槽, 我们为了满足该业务需求, 我们可以通过伪类选择器:empty实现

wxml代码结构

1
2
3
4
<view class="content">
<slot></slot>
</view>
<view class="default">默认值</view>

wcss样式

1
2
3
4
5
6
.default {
display: none;
}
.content:empty + .default{
display: block;
}

多个插槽

微信小程序要想使用多个插槽, 需要在 Components 函数对象参数中的 options 配置 multipleSlots: true

1
2
3
4
5
6
Component({
options: {
multipleSlots: true,
},
});

微信小程序弹窗API

wx.showToast

官方文档

示例

1
2
3
4
5
6
wx.showToast({
title: "购买成功!",
icon: "success",
duration: 3000,
mask: true,
});

wx.showMoadl

官方文档

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wx.showModal({
title: "确定购买吗",
content: "1241414",
confirmColor: "red",
cancelColor: "blue",
success: (res) => {
if (res.cancel) {
console.log("cancel");
}

if (res.confirm) {
console.log("confirm");
}
},
});

wx.showActionSheet

官方文档

示例

1
2
3
4
5
6
7
8
9
10
11
wx.showActionSheet({
alertText: "提示",

itemList: ["选项1", "选项2", "选项3"],
success: (res) => {
console.log(res.tapIndex);
},
fail: (err) => {
console.log(err);
},
});

微信小程序获取地址API

API: wx.getLocation

使用该API的前提需要在app.json中进行配置

1
2
3
4
5
6
7
8
"requiredPrivateInfos": [
"getLocation"
],
"permission": {
"scope.userLocation": {
"desc": "获取位置信息"
}
},

示例

1
2
3
4
5
wx.getLocation({
success: (res) => {
console.log(res);
},
});

微信小程序获取界面上的节点信息

场景: swiper 轮播图组件有默认的高度, 假如其中放置图片, 但图片的高度不适配, 改动图片的 mode 属性为 aspectFill 会裁剪图片, 显得不美观, 为了解决此, 尝试获取图片高度, 改变 swiiper 的高度, 以是图片完美展示

步骤一

创建 SelectorQuery, SelectorQuery 为查询节点信息的对象

1
const query = wx.createSelectorQuery();

步骤二

获取图片组件的信息, 用NodesRef SelectorQuery.select(string selector),
并通过 SelectorQuery NodesRef.boundingClientRect(function callback) 添加节点的布局位置的查询请求。

NodesRef SelectorQuery.select(string selector): 在当前页面下选择第一个匹配选择器 selector 的节点。返回一个 NodesRef 对象实例,可以用于获取节点信息。

1
query.select(".banner-image").boundingClientRect();

步骤三

NodesRef SelectorQuery.exec(function callback): 执行所有的请求。请求结果按请求次序构成数组, 在callback的第一个参数中返回。

1
2
3
query.exec((res) => {
console.log(res.height)
});

对该操作进行封装

1
2
3
4
5
6
7
8
9
export function querySelect(selector) {
return new Promise((resolve) => {
const query = wx.createSelectorQuery();
query.select(".banner-image").boundingClientRect();
query.exec((res) => {
resolve(res);
});
});
}

微信小程序音源播放操作

创建 InnerAudioContext 实例

1
const audioContext = wx.createInnerAudioContext();

设置 InnerAudioContext 实例的 src 和 autoplay 属性

  • src: 音频资源地址

  • autoplay: 是否自动播放

进行以上设置后, 在页面或相应的生命周期中加载完后即可自动播放

但仅仅是用于可播放, 对于其更精细的操作可以查阅对应的官方文档

图片懒加载没生效问题

1
<image src="/assets/xxx.png" mode="" show-menu-by-longpress lazy-load />

lazy-load的图片不是出现在屏幕上才会开始加载,而是提前3个屏幕高度就会加载。所以说三个屏幕高度以内的图片是不会懒加载的,上下三屏即为三个屏幕高度。

text 组件

注意:

在进行页面跳转时,需要在路径的前面添加 / 斜线,否则跳转不成功到商品列表页面

  • navigate:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,保留上一级页面

  • redirect:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,关闭上一级页面

  • switchTab:只能跳转到 TabBar 页面,不能跳转到非 TabBar 页面,关闭其他所有的非 TabBar 页面

  • reLaunch:关闭所有页面,然后打开小程序中某一个页面

  • navigateBack返回上一页或者返回前几页,默认只能返回上一页

    • delte:返回的层级,默认是 1,如果想返回几级,就写几