标记语言
如前所述,小程序不是用纯 HTML 编写的,而是用 HTML 的方言编写的。如果您曾经处理过 Vue.js 文本插值和指令,那么您会立即感到熟悉,但类似的概念早在 XML 转换 (XSLT) 中就已存在。下面展示的是微信的 WXML 代码示例,但该概念适用于所有小程序平台,包括支付宝的 AXML、百度的 Swan Element、字节跳动的 TTML(尽管开发者工具将其称为 Bxml)和快应用的 HTML。与 Vue.js 一样,小程序底层编程概念是 model-view-viewmodel (MVVM)。
数据绑定
数据绑定对应于 Vue.js 的文本插值。
<!-- wxml -->
<view>{{message}}</view>
// page.js
Page({
data: {
message: "Hello World!",
},
});
列表呈现
列表渲染的工作方式与 Vue.js v-for 指令类似。
<!-- wxml -->
<view wx:for="{{array}}">{{item}}</view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5],
},
});
条件渲染
条件渲染的工作方式与 Vue.js 的 v-if 指令类似。
<!-- wxml -->
<view wx:if="{{view == 'one'}}">One</view>
<view wx:elif="{{view == 'two'}}">Two</view>
<view wx:else="{{view == 'three'}}">Three</view>
// page.js
Page({
data: {
view: "three",
},
});
模板
WXML 模板可以通过链接到模板定义的 is 属性以声明方式使用,而无需强制性地克隆 HTML 模板的 content。
<!-- wxml -->
<template name="person">
<view>
First Name: {{firstName}}, Last Name: {{lastName}}
</view>
</template>
<template is="person" data="{{...personA}}"></template>
<template is="person" data="{{...personB}}"></template>
<template is="person" data="{{...personC}}"></template>
// page.js
Page({
data: {
personA: { firstName: "Alice", lastName: "Foo" },
personB: { firstName: "Bob", lastName: "Bar" },
personC: { firstName: "Charly", lastName: "Baz" },
},
});
样式
样式设置通过 CSS 方言实现。微信的名称为 WXSS。对于支付宝,其 CSS 称为 ACSS;百度则简称为 CSS;而对于字节跳动,其 CSS 方言称为 TTSS。它们的共同之处在于,它们都使用自适应像素扩展了 CSS。在编写常规 CSS 时,开发者需要转换所有像素单位,以适应宽度和像素宽高比各不相同的移动设备屏幕。TTSS 支持 rpx 单位作为其底层,这意味着小程序会接管开发者的工作,并根据指定的 750rpx 屏幕宽度代表开发者转换单位。例如,在屏幕宽度为 393px(设备像素比为 2.75)的 Pixel 3a 手机上,使用 Chrome 开发者工具检查时,响应式 200rpx 在实际设备上会变为 104px(393px / 750rpx * 200rpx ≈ 104px)。在 Android 中,同一概念称为密度无关像素。
/* app.wxss */
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0; /* ← responsive pixels */
box-sizing: border-box;
}
由于组件(请参阅下文)不使用 Shadow DOM,因此在网页上声明的样式会影响所有组件。常见的样式表文件组织方式是,使用一个根样式表来设置全局样式,并使用单独的页面级样式表来设置微应用的每个页面的特定样式。可以使用 @import 规则导入样式,该规则的行为类似于 @import CSS @ 规则。与 HTML 中一样,样式也可以内联声明,包括动态文本插值(请参阅之前)。
<view style="color:{{color}};" />
设计脚本
小程序支持 JavaScript 的“安全子集”,其中包括对使用各种语法(让人想起 CommonJS 或 RequireJS)的模块的支持。无法通过 eval() 执行 JavaScript 代码,也无法使用 new Function() 创建函数。脚本执行上下文在设备上为 V8 或 JavaScriptCore,在模拟器中为 V8 或 NW.js。通常可以使用 ES6 或更新的语法进行编码,因为如果 build 目标是具有较旧 WebView 实现的操作系统(请参阅下文),特定的开发者工具会自动将代码转译为 ES5。超级应用提供商的文档明确提到,其脚本语言不应与 JavaScript 混淆,并且与 JavaScript 不同。不过,此声明主要指的是模块的工作方式,即它们尚不支持标准 ES 模块。
如前文所述,小程序编程概念是 model-view-viewmodel (MVVM)。逻辑层和视图层在不同的线程上运行,这意味着用户界面不会因长时间运行的操作而受阻。从 Web 角度来看,您可以将脚本视为在 Web Worker 中运行。
微信的脚本语言称为 WXS,支付宝的称为 SJS,字节跳动的同样称为 SJS。百度在提及自己的 JavaScript 时,会使用 JS。这些脚本需要使用特殊类型的标记(例如微信中的 <wxs>)进行包含。相比之下,快应用使用常规 <script> 标记和 ES6 JS 语法。
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view>{{m1.message}}</view>
也可以通过 src 属性加载模块,或通过 require() 导入模块。
// /pages/tools.wxs
var foo = "'hello world' from tools.wxs";
var bar = function (d) {
return d;
};
module.exports = {
FOO: foo,
bar: bar,
};
module.exports.msg = "some msg";
<!-- page/index/index.wxml -->
<wxs src="./../tools.wxs" module="tools" />
<view>{{tools.msg}}</view>
<view>{{tools.bar(tools.FOO)}}</view>
// /pages/logic.wxs
var tools = require("./tools.wxs");
console.log(tools.FOO);
console.log(tools.bar("logic.wxs"));
console.log(tools.msg);
JavaScript 桥接 API
连接小程序与操作系统的 JavaScript 桥接器可让您使用操作系统功能(请参阅访问强大的功能)。它还提供了许多便捷方法。如需了解概览,您可以查看WeChat、Alipay、Baidu、ByteDance和快应用的不同 API。
功能检测非常简单,因为所有平台都提供了一个(字面意义上称为)canIUse() 方法,其名称似乎受到了网站 caniuse.com 的启发。例如,ByteDance 的 tt.canIUse() 允许对 API、方法、参数、选项、组件和属性进行支持检查。
// Testing if the `<swiper>` component is supported.
tt.canIUse("swiper");
// Testing if a particular field is supported.
tt.canIUse("request.success.data");
更新
小程序没有标准化的更新机制(关于潜在标准化的讨论)。所有小程序平台都有一个后端系统,可供小程序开发者上传其小程序的新版本。然后,超级应用会使用该后端系统来检查和下载更新。有些超级应用完全在后台执行更新,微应用本身无法影响更新流程。其他超级应用则会向小程序本身提供更多控制权。
以下段落以一个复杂流程为例,更详细地介绍了 WeChat 的小程序更新机制。在以下两种情况下,微信会检查是否有可用更新:
- 只要微信在运行,就会定期检查最近使用过的小程序的更新。如果找到更新,系统会下载更新,并在用户下次冷启动小程序时同步应用更新。当用户打开小程序时,如果小程序当前未运行(微信会在小程序进入后台 5 分钟后强制关闭小程序),则会冷启动小程序。
- 当小程序冷启动时,微信也会检查更新。对于用户长时间未打开的小程序,系统会同步检查并下载更新。在下载更新时,用户必须等待。下载完成后,系统会应用更新并打开迷你应用。如果下载失败(例如,由于网络连接不良),小程序仍会打开。对于用户最近打开过的小程序,任何潜在的更新都会在后台异步下载,并在用户下次冷启动小程序时应用。
小程序可以使用 UpdateManager API 选择加入更早的更新。它提供以下功能:
- 在检查更新时通知微应用。
(
onCheckForUpdate) - 在下载并提供更新后通知小程序。
(
onUpdateReady) - 在无法下载更新时通知微应用。
(
onUpdateFailed) - 允许小程序强制安装可用更新,这会重启应用。(
applyUpdate)
微信还在其后端系统中为小程序开发者提供了其他更新自定义选项: 1. 其中一种方案允许开发者针对已安装特定最低版本的小程序的用户选择停用同步更新,并强制将更新设为异步更新。 2. 另一种方案允许开发者设置其小程序所需的最低版本。这样一来,如果异步更新的版本低于所需的最低版本,则在应用更新后会强制重新加载小程序。如果更新下载失败,系统还会阻止打开旧版微应用。
致谢
本文已由以下人员审核:Joe Medley、Kayce Basques、Milica Mihajlija、Alan Kent 和 Keith Gu。