微信小程序开发
CouriourC Lv4

微信小程序开发笔记

小程序发展史

小程序并非凭空冒出来的一个概念。当微信中的 WebView 逐渐成为移动 Web 的一个重要入口时,微信就有相关的 JS API 了。实际上,微信官方是没有对外暴露过如此调用的,此类 API 最初是提供给腾讯内部一些业务使用,很多外部开发者发现了之后,依葫芦画瓢地使用了,逐渐成为微信中网页的事实标准。2015年初,微信发布了一整套网页开发工具包,称之为 JS-SDK,开放了拍摄、录音、语音识别、二维码、地图、支付、分享、卡券等几十个API。给所有的 Web 开发者打开了一扇全新的窗户,让所有开发者都可以使用到微信的原生能力,去完成一些之前做不到或者难以做到的事情。

小程序与普通网页开发的区别

小程序的主要开发语言是 JavaScript ,小程序的开发同普通的网页开发相比有很大的相似性。对于前端开发者而言,从网页开发迁移到小程序的开发成本并不高,但是二者还是有些许区别的。

网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。

网页开发者需要面对的环境是各式各样的浏览器,PC 端需要面对 IE、Chrome、QQ浏览器等,在移动端需要面对Safari、Chrome以及 iOS、Android 系统中的各式 WebView 。而小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的微信客户端,以及用于辅助开发的小程序开发者工具,小程序中三大运行环境也是有所区别的,如表1-1所示。

表1-1 小程序的运行环境

运行环境逻辑层渲染层
iOSJavaScriptCoreWKWebView
安卓V8chromium定制内核
小程序开发者工具NWJSChrome WebView

微信小程序的开通注册流程

* 途径一

通过网站注册登陆–: (微信公众平台): https://mp.weixin.qq.com/ --: (登陆) 选择主体类型 – : 开通

具体流程 (因为我已经开通过了,所以无法再次回到那个页面,用的官方的图)— :

进入小程序注册页 根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号。

在这个小程序管理平台,你可以管理你的小程序的权限,查看数据报表,发布小程序等操作。

登录 小程序后台 ,我们可以在菜单 “开发”-“开发设置” 看到小程序的 AppID 了 。


小程序的 AppID 相当于小程序平台的一个身份证,后续你会在很多地方要用到 AppID (注意这里要区别于服务号或订阅号的 AppID)。

有了小程序帐号之后,我们需要一个工具来开发小程序。

安装开发工具

前往 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装,有关开发者工具更详细的介绍可以查看 《开发者工具介绍》

* 途径二

就是反着来,你直接在开发者工具生成了测试号,然后去登陆就行勒,一般为了方便,都是采用途径一

通过开发者工具上传,下次登陆微信公众平台的时候选择自己的测试号,需要注意的是个人主体 公众号 小程序号只能有一个,所以如果自己一开始开通了公众号将无法发布小程序,进入的界面也会不一样

安装微信小程序开发者工具


一般选用的是稳定版本,下载安装过程此处不再介绍,推荐别安装C盘;

界面

启动页
登录页

在登录页,可以使用微信扫码登录开发者工具,开发者工具将使用这个微信帐号的信息进行小程序的开发和调试。

具体工具使用此处不在讨论重点,所以此处略过;

进入正题之前的叨叨, 工程项目 && 模块化

对于工程项目: 一个工程项目,不只是模块化,还有项目的跟进更新,从代码规范,到项目整体设计,如何让项目越写越好写,而不是要么在埋坑,要么在堆垃圾代码,所以对项目的整体架构是十分重要的,不仅仅是后端,前端也一样,都会去考虑到项目本身之外的东西,而不是只专注于一个页面,或者功能点,做积木的人和堆积木的人之间的区别,或许就是为什么后者被人们称之为工程师的原因吧,因此对项目有一个整体的宏观考虑之后,再去做局部优化,也就是要有一个项目宏观的概念,由表及里,而模块化,也就是分开做积木,积木的稳健也会影响到整个成品的稳定程度,所以局部优化必不可少,但是如果能支撑起你目前的系统,请让它膨胀一会;

对模块化: 从一个因果论分析,结果上:程序连接起来了,并且正常运行,因:每个部分的代码正常运行了,你写的代码在程序里面了,程序找到了你的逻辑名字,比如你未定义一个变量,那么你去使用它,必然会报错,因为它压根就没有,又比如,你去调用一个对象的方法,但是他没有,那么它也必然报错,因为它压根就没有,所以你要让你分开的代码能相互认识,必然就涉及到引入,导入,告诉你的代码在哪里,组成的 部分在那里,所以模块的关键在于导入导出,为什么有导出呢,因为每一个模块本身是可以独立的,所以独立的模块有模块自由权,可以选择性的出现;

润氏吃面哲学 :我们都喜欢吃一根一根分开的拉面,而不是糊成饼的拉面, 拉面中粗细也各有不一致,同样的你的代码好不好吃,也是在于你怎么设计了.

😀进入正题项目概览

微信小程序项目文件主要由四大重要部分组成:

  1. JSON 配置文件
  2. WXML 类似于HTML
  3. WXSS 类似于CSS
  4. JS 就是JS
  5. WXS(可选这个不是主要必备的文件)

纵观所有的框架学习,无非就是使用工具,只是别人给的思想,给的哲学,或者给的API名字各有异同,因此对于小程序的学习或者其他的框架的学习,个人推荐的是按照项目配置穿成一条线去学习,把控不变量,掌握共同点,借他山之石,可以攻玉

JSON 配置文件

小程序的JSON 文件主要分为:

  1. 工程配置: project.config.json 主要是对编译过程中的一些配置,和对编译器的一些配置

    1. 通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。

      考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。

      其他配置项细节可以参考文档 开发者工具的配置

  2. 应用配置:app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部tab等。主要常用字段如下:

属性类型必填描述
entryPagePathstring小程序默认启动首页
pagesstring[]页面路径列表
windowObject全局的默认窗口表现
tabBarObject底部 tab 栏的表现 [其实经常会考虑自己实现]
networkTimeoutObject网络超时时间 [一般设置为 5000 也就是 5s]
functionalPagesboolean是否启用插件功能页,默认关闭
subpackagesObject[]分包结构配置 [一般在项目大了才会去配置,app.json整体配置类似]
workersstringWorker 代码放置的目录 ,小程序会单独开一个线程来允许,实现伪多线程
requiredBackgroundModesstring[]需要在后台使用的能力,主要配置项由[ “locations” , “audio”]
pluginsObject使用到的插件
preloadRuleObject分包预下载规则
resizablebooleanPC 小程序是否支持用户任意改变窗口大小(包括最大化窗口);iPad 小程序是否支持屏幕旋转。默认关闭
usingComponentsObject全局自定义组件配置
permissionObject小程序接口权限相关设置
sitemapLocationstring指明 sitemap.json 的位置
stylestring指定使用升级后的weui样式
useExtendedLibObject指定需要引用的扩展库
entranceDeclareObject微信消息用小程序打开
darkmodeboolean小程序支持 DarkMode
themeLocationstring指明 theme.json 的位置,darkmode为true为必填
lazyCodeLoadingstring配置自定义组件代码按需注入
singlePageObject单页模式相关配置
supportedMaterialsObject聊天素材小程序打开相关配置
  1. page.json 争对页面的一些配置,可以帮助你提前设置一些默认值,当然这个是可以通过程序进行修改的,我是指主要是样式类
属性类型默认值描述
navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
navigationBarTextStylestringwhite导航栏标题颜色,仅支持 black / white
navigationBarTitleTextstring导航栏标题文字内容
navigationStylestringdefault导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮。参见注 1。
backgroundColorHexColor#ffffff窗口的背景色
backgroundTextStylestringdark下拉 loading 的样式,仅支持 dark / light
backgroundColorTopstring#ffffff顶部窗口的背景色,仅 iOS 支持
backgroundColorBottomstring#ffffff底部窗口的背景色,仅 iOS 支持
enablePullDownRefreshbooleanfalse是否开启当前页面下拉刷新。 详见 Page.onPullDownRefresh
onReachBottomDistancenumber50页面上拉触底事件触发时距页面底部距离,单位为px。 详见 Page.onReachBottom
pageOrientationstringportrait屏幕旋转设置,支持 auto / portrait / landscape 详见 响应显示区域变化
disableScrollbooleanfalse设置为 true 则页面整体不能上下滚动。 只在页面配置中有效,无法在 app.json 中设置
usingComponentsObject页面自定义组件配置
initialRenderingCachestring页面初始渲染缓存配置,支持 static / dynamic[ 一般用在起手数据量比较大的时候,结合骨架屏效果,提升用户体验 ]
stylestringdefault启用新版的组件样式
singlePageObject单页模式相关配置
restartStrategystringhomePage重新启动策略配置
  1. component.json

    类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成。要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可将这一组文件设为自定义组件):

属性类型默认值必填描述
componentBooleantrue标识是否为组件,这个在之后讲到页面和组件的区别的时候就会提到
usingComponentsObject[]{}组件中用到的 自定义组件配置
styleIsolationStringpage-isolated 表示在这个页面禁用 app.wxss ,同时,页面的 wxss 不会影响到其他自定义组件; page-apply-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式不会影响到其他自定义组件,但设为 shared 的自定义组件会影响到页面; page-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式会影响到其他设为 apply-sharedshared 的自定义组件,也会受到设为 shared 的自定义组件的影响。此外,小程序基础库版本 2.2.3 以上支持 addGlobalClass 选项,即在 Componentoptions 中设置 addGlobalClass: true 。这个选项等价于设置 styleIsolation: apply-shared ,但设置了 styleIsolation 选项后这个选项会失效。也就是配置是否为局部样式,默认是,不受全局影响
pureDataPatternString从小程序基础库版本 2.10.1 开始,也可以在页面或自定义组件的 json 文件中配置 pureDataPattern (这样就不需在 js 文件的 options 中再配置)。此时,其值应当写成字符串形式:
componentGenericsObject{}配置抽象节点,节点的 generic 引用 generic:xxx="yyy" 中,值 yyy 只能是静态值,不能包含数据绑定。因而抽象节点特性并不适用于动态决定节点名的场景.
componentPlaceholderObject{}在使用如 分包异步化用时注入 等特性时,自定义组件所引用的其他自定义组件,在刚开始进行渲染时可能处于不可用的状态。此时,为了使渲染过程不被阻塞,不可用的自定义组件需要一个 「占位组件」(Component placeholder)。基础库会用占位组件替代不可用组件进行渲染,在该组件可用后再将占位组件替换回该组件。也就是配置骨架屏的位置
  1. sitemap.json 微信现已开放小程序内搜索,开发者可以通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler场景值1129。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中;

    也就是说这属于是微信的爬虫机制了,和web上的robot.txt有些类似,属于是sso优化,才会开始考虑到

属性类型必填描述
rulesObject[]索引规则列表

rules

rules 配置项指定了索引规则,每项规则为一个 JSON 对象,属性如下所示:

属性类型必填默认值取值取值说明
actionstring“allow”“allow”、“disallow”命中该规则的页面是否能被索引
pagestring“*”、页面的路径* 表示所有页面,不能作为通配符使用
paramsstring当 page 字段指定的页面在被本规则匹配时可能使用的页面参数名称的列表(不含参数值)
matchingstring“inclusive”参考 matching 取值说明当 page 字段指定的页面在被本规则匹配时,此参数说明 params 匹配方式
priorityNumber优先级,值越大则规则越早被匹配,否则默认从上到下匹配

matching 取值说明

说明
exact当小程序页面的参数列表等于 params 时,规则命中
inclusive当小程序页面的参数列表包含 params 时,规则命中
exclusive当小程序页面的参数列表与 params 交集为空时,规则命中
partial当小程序页面的参数列表与 params 交集不为空时,规则命中

小程序框架(简单知道有什么,这些能做什么即可,再循序渐进)

小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务。

实际上很多限制,做到了尽可能简单,但是开发上有特别多的限制,哎,我就受不了

整个小程序框架系统分为两部分:逻辑层(App Service)和 视图层(View)。小程序提供了自己的视图层描述语言 WXMLWXSS,以及基于 JavaScript 的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。

视图层 (WXML ,WXSS) 需要对HTML CSS 有一个基础的概念

WXML

WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件事件系统,可以构建出页面的结构。

要完整了解 WXML 语法,请参考WXML 语法参考

用以下一些简单的例子来看看 WXML 具有什么能力:

数据绑定

之后详细的讲

1
2
3
4
5
6
7
8
<!--wxml-->
<view> {{message}} </view>
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
列表渲染
1
2
3
4
5
6
7
8
<!--wxml-->
<view wx:for="{{array}}"> {{item}} </view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5]
}
})
条件渲染
1
2
3
4
5
6
7
8
9
10
<!--wxml-->
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({
data: {
view: 'MINA'
}
})
模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--wxml-->
<template name="staffName">
<view>
FirstName: {{firstName}}, LastName: {{lastName}}
</view>
</template>

<template is="staffName" data="{{...staffA}}"></template>
<template is="staffName" data="{{...staffB}}"></template>
<template is="staffName" data="{{...staffC}}"></template>
// page.js
Page({
data: {
staffA: {firstName: 'Hulk', lastName: 'Hu'},
staffB: {firstName: 'Shang', lastName: 'You'},
staffC: {firstName: 'Gideon', lastName: 'Lin'}
}
})
WXSS

WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

WXSS 用来决定 WXML 的组件应该怎么显示。

为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。

与 CSS 相比,WXSS 扩展的特性有:

  • 尺寸单位
  • 样式导入
尺寸单位
  • rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。

注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况。

样式导入

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。

示例代码:

1
2
3
4
5
6
7
8
9
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
内联样式

框架组件上支持使用 style、class 属性来控制组件的样式。

  • style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
1
<view style="color:{{color}};" />
  • class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。
1
<view class="normal_view" />
选择器

目前支持的选择器有:

选择器样例样例描述
.class.intro选择所有拥有 class=“intro” 的组件
#id#firstname选择拥有 id=“firstname” 的组件
elementview选择所有 view 组件
element, elementview, checkbox选择所有文档的 view 组件和所有的 checkbox 组件
::afterview::after在 view 组件后边插入内容
::beforeview::before在 view 组件前边插入内容
全局样式与局部样式

定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。

逻辑层+视图层结合WXS

WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

注意事项
  1. WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
  2. WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
  3. WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
  4. WXS 函数不能作为组件的事件回调。
  5. 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。

以下是一些使用 WXS 的简单示例,要完整了解 WXS 语法,请参考WXS 语法参考

页面渲染
1
2
3
4
5
6
7
8
<!--wxml-->
<wxs module="m1">
var msg = "hello world";

module.exports.message = msg;
</wxs>

<view> {{m1.message}} </view>

页面输出:

1
hello world
数据处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
}
})
<!--wxml-->
<!-- 下面的 getMax 函数,接受一个数组,且返回数组中最大的元素的值 -->
<wxs module="m1">
var getMax = function(array) {
var max = undefined;
for (var i = 0; i < array.length; ++i) {
max = max === undefined ?
array[i] :
(max >= array[i] ? max : array[i]);
}
return max;
}

module.exports.getMax = getMax;
</wxs>

<!-- 调用 wxs 里面的 getMax 函数,参数为 page.js 里面的 array -->
<view> {{m1.getMax(array)}} </view>
逻辑层 JS

和javascript 差不多,

JavaScript 支持情况
运行限制

基于安全考虑,小程序中不支持动态执行 JS 代码,即:

  • 不支持使用 eval 执行 JS 代码

  • 不支持使用new Function

    创建函数

    • new Function('return this') 除外
标准 ECMAScript 支持

小程序的 JS 执行环境 在不同平台上的执行环境存在差异,因此导致不同平台对 ECMAScript 标准的支持存在差异。

小程序基础库为了尽量抹平这些差异,内置了一份 core-js Polyfillcore-js 可以将平台环境缺失的标准 API 补齐。

需要注意的是,平台对 ECMAScript 语法的支持差异无法抹平,当你需要使用一些高级语法时(如 async/await 时,则需要借助代码转换工具来支持这些语法。

无法被 Polyfill 的 API

以下 API 在部分低版本客户端中无法使用,请注意尽量避免使用

  • Proxy 对象
与标准的差异
Promise 时序差异

由于实现原因与 iOS JavaScriptCore 限制,iOS 环境下的 Promise 是一个使用 setTimeout 模拟的 Polyfill。这意味着 Promise 触发的任务为普通任务,而非微任务,进而导致 在 iOS 下的 Promise 时序会和标准存在差异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var arr = []

setTimeout(() => arr.push(6), 0)
arr.push(1)
const p = new Promise(resolve => {
arr.push(2)
resolve()
})
arr.push(3)
p.then(() => arr.push(5))
arr.push(4)
setTimeout(() => arr.push(7), 0)

setTimeout(() => {
// 应该输出 [1,2,3,4,5,6,7]
// 在 iOS 小程序环境,这里会输出 [1,2,3,4,6,5,7]
console.log(arr)
}, 1000)

关于普通任务和微任务的区别可以自己谷歌✌


在对小程序中有什么了,以及各个部分是能做什么了,有了大概了解之后,就可以进行细节的学习了

 评论