小程序开发要先注册小程序账号,有了小程序账号才可以使用开发者工具。小程序是一种特殊的开发形式,里面的 API 和组件都是自己定制的,因此在普通的浏览器中不能预览,要预览功能和页面就需要使用开发者工具。
先准备一个没有注册过公众号的邮箱,然后访问小程序介绍页面并点击底部的「前往注册」按钮,再按照提示填写个人信息,最后进入邮箱激活账号即可。


详细流程请参考官方文档。
小程序有自己的开发者工具,可以编写代码,实时查看页面和功能效果,还能在开发者工具中进行 debug。小程序开发者工具是使用 NW.js 编写的。
开发者工具下载地址:微信开发者工具
WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。包含 button、cell、dialog、 progress、 toast、article、actionsheet、icon 等各式组件。
WeUI 有两个版本,一个是普通的 HTML5 版本,另外是小程序版本。本节我们通过 WeUI 来简单学习开发者工具的使用。
首先下载 WeUI 源码:
# https 方式(推荐)
git clone https://github.com/Tencent/weui-wxss.git
# 或者 ssh 方式
git clone git@github.com:Tencent/weui-wxss.git
打开开发者工具,使用注册时绑定的微信账号扫码登录,这时在进入的界面中选择「小程序项目」,如果是初次使用小程序开发者工具,没有创建过小程序项目,就会进入下面的页面:

在这个页面,先选择我们 clone 下来的 WeUI 项目的 dist 文件夹。对于 AppID 选项,如果已经有了小程序账号,可以在账号后台找到 AppID 并填写上;若还没有注册小程序账号,可以直接在「或使用测试号:」后面单击「小程序」,就会自动填好。然后给项目起个名字,比如「WeUI 演示」,点击确定后就打开了 WeUI 项目。这时候看到的是开发者工具的开发界面,如下图所示,开发界面主要由三部分组成:模拟器、编辑器和调试器。

Tips: 常用 IDE 推荐
除了三个重要组成部分之外,在开发者工具的顶部还有各种操作按钮。左侧主要是模拟器、编辑器、调试器和小程序云开发控制台的视图开关,可以控制对应视图的开启关闭。

中间部分是跟开发、编译、测试和上线相关的各种按钮,我们在开发和测试小程序中会经常使用,最常用的有:
最后介绍的是开发者工具右上角的「详情」。

详情下面主要有三个 Tab:项目设置、域名信息和腾讯云状态。
request 等访问的域名采用了白名单形式,在这里可以看到小程序管理后台设置的域名白名单小程序的开发语言跟前端开发者比较熟悉的 HTML5 非常相似(甚至相同),小程序的视图层由 WXML 和 WXSS 组成,分别对应 HTML 和 CSS,逻辑层则跟 HTML5 一样,也是 JavaScript 语言实现。
微信小程序运行在三端:iOS、Android 和用于调试的开发者工具
除了普通的 JavaScript,小程序还支持一种类似 JS 的 WXS 语言,WXS 对于小程序开发不是必需的,它的主要目的是为了增强 WXML 的数据处理能力而新引入一种技术实现,其实际解析的语言规范还是 JS,并没有引入新的语法,仅仅对 JS 做了上层的封装和限制,所以学习上基本没什么成本,大致了解下开发文档马上就能上手。本小册实战部分也会涉及简单的 WXS 编写。
对于 WXS 和 JavaScript 的性能比较,官方给出的数据是:由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 Android 设备上二者运行效率无差异。
小程序项目由配置文件、页面文件、静态资源和其他相关(比如组件、小程序云函数等)内容组成,一般小程序会由四类文件组成:
.json 后缀的 JSON 配置文件.wxml 后缀的 WXML 模板文件.wxss 后缀的 WXSS 样式文件.js 后缀的 JS 脚本逻辑文件小程序项目的目录结构组成没有严格的要求,按照前端项目的经验,一般会分为:配置、页面、静态资源、基础库、组件等多个目录,例如下面的目录结构:
├── app.js 小程序全局app相关js
├── app.json 小程序配置文件
├── app.wxss 小程序全局app样式
├── cloud-functions 云函数目录
│ ├── decrypt
│ ├── geocoder
│ ├── he-air
│ ├── he-weather
│ ├── jscode2session
│ └── weather
├── components 组件库
│ └── icon
├── images 图片等静态资源
│ └── cloud.jpg
├── pages 页面目录
│ ├── diary
│ └── weather
└── project.config.json 工具项目配置文件
当然根据不同的项目,可能目录结构不同,但是小程序必需的 app.json 和页面组成是必不可少的。另外,在开发复杂的项目时,我们会用到开发框架或者编译工具,这时候目录结构只需要保证编译之后的目录结构符合规范即可。
小程序有三个重要的配置,分别放在三个 JSON 文件内:project.config.json(工具项目配置)、app.json(小程序配置)、page.json(单页面配置)
project.config.json:这个是配置项目工具相关的,比如开发者工具的编译设置(是否使用 ES6 语法等)、界面设置,以及云函数相关的 cloudfunctionRoot,详细可以参考项目配置文件app.json:小程序的全局配置,包括了所有页面路径、界面表现、网络超时时间、底部 tab、插件等,常用的两个配置是 window 和 pages,详细配置参考全局配置page.json:是相对于 app.json 更细粒度的单页面配置,详细参考页面配置小程序页面是由各种组件组成的,组件可以类比成原生 HTML5 的标签。
小程序内部定义了很多组件,可以对应 HTML5 的标签和基础能力来理解,小程序的组件根据实现不同,可以分为 Web 组件和 Native 组件,Web 组件是由 HTML5 原生 Web 组件封装的组件,比如 view、image 等;Native 组件是为了增强小程序的体验,用客户端技术实现的组件,包括一些交互复杂、原生 Web 组件性能不高的组件,例如 input、map、canvas、video 等。
小程序一共提供 8 大类 30 多个组件:
小程序本身支持很多组件,比如地图、按钮等,开发者也可以自己做项目内公共组件,比如我们后面实战部分会介绍做一个 icon 组件,放在 components 目录下面,这样此小程序的任何页面如果要使用这个 icon 公共组件,只需在自己的 page.json 中添加如下字段:
"usingComponents": {
"icon": "../../components/icon/index"
}
添加完成之后,在页面代码中就可以直接使用 <icon> 的 tag 了。官方文档有更加详细的介绍。
插件是对一组 JS 接口、自定义组件或页面的封装,用于提供给第三方小程序调用。简单来说,插件是组件的升级版本,组件只能在自己项目中使用,插件则更独立,是可以发布到全网,供其他开发者使用的。例如实战中,笔者使用了一款日历插件,则需要在 app.json 中增加 plugins 字段:
"plugins": {
"calendar": {
"version": "1.1.3",
"provider": "wx92c68dae5a8bb046"
}
}
如果想开发一个插件,则可以参考官方文档。
微信小程序是由数据驱动的开发框架,本小节主要介绍小程序开发中的基础概念和知识。
微信小程序是数据驱动模型,在 WXML 中可以对页面的数据进行绑定,小程序的 WXML 内使用的是 Mustache 语法,在 {{}} 内可以将变量名包裹起来。例如:
<view>{{ message }}</view>
Page({
data: {
message: 'Hello MINA!'
}
})
但是小程序不支持复杂的表达式,目前支持简单的三元、加减和逻辑判断,如果要使用形如 {{parseInt(num)}} 的函数调用语法,需要 WXS 支持:
WXML 内容:
<wxs src="./demo.wxs" module="tools" />
<view>{{ tools.toNumber(num) }}</view>
WXS 内容:
// demo.wxs
function toNumber(n){
return parseInt(n)
}
module.exports.toNumber = toNumber
小程序内对页面的数据修改只能通过 setData 方法,不能使用直接赋值的方式 this.data.key = value:
Page({
data: {
message: 'Hello MINA!'
},
onLoad(){
this.setData({
message: 'hello world~'
})
}
})
记住:修改页面数据,只能使用 this.setData 修改!
在小程序内,除了标准 HTML5 中遇见的 touchstart 等事件外,增加了 tap 类的事件,主要包括以下几种:
事件名称 | 说明 |
|---|---|
tap | 手指触摸后马上离开 |
longpress | 手指触摸后,超过 350ms 再离开,如果指定了事件回调函数并触发了这个事件,tap 事件将不被触发 |
longtap | 手指触摸后,超过 350ms 再离开(推荐使用 longpress 事件代替) |
小程序内,事件的绑定是通过在 WXML 标签增加 bind* 属性来实现的,比如新鲜天气的生活指数,笔者是绑定了一个 tap 事件,当用户点击之后,会响应对应页面 JS 的函数:
<view class="life-style">
<view class="item" wx:for="{{lifeStyle}}" data-name="{{item.name}}" data-detail="{{item.detail}}" bindtap="indexDetail">
<view class="title">
<icon type="{{item.icon}}"></icon>
{{item.name}}
</view>
<view class="content">{{item.info}}</view>
</view>
</view>
上面的代码绑定了 tap 事件,事件处理函数为 indexDetail。
小程序内的事件分为可冒泡和不可冒泡的事件,除了 submit、input 之类的事件,多数是可冒泡的事件,对于事件的绑定,除了 bind* 的方式,还可以通过 catch* 的方式来绑定,两者的区别在于:
bind 不会阻止冒泡,变形写法为 bind:*catch 会阻止事件继续冒泡,变形写法为 catch:*小程序内,触摸类事件支持捕获阶段,捕获是先于冒泡的触发,绑定捕获事件,可以使用 capture-bind、capture-catch,后者将中断捕获阶段和取消冒泡阶段,下面是官方的示例:
在下面的代码中,点击 inner view 会先后调用 handleTap2、handleTap4、handleTap3、handleTap1。
<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">
outer view
<view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
inner view
</view>
</view>
如果将上面代码中的第一个 capture-bind 改为 capture-catch,将只触发 handleTap2。
<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
outer view
<view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
inner view
</view>
</view>
关于事件的详细说明,建议阅读官方的文档,以获取更大的帮助。
当事件触发时,处理函数会响应,传入 event 对象,通过 event 对象可以获取事件触发时候的一些信息,包括时间戳、detail 等。
因为小程序内的事件绑定都是在 WXML 中实现的,所以传递参数只能通过 WXML 上面的属性值来传递,例如下面的代码中,indexDetail 处理函数需要接收生活指数的名称和详情,来弹出弹层提示,这时候需要在标签上增加 data-xx 这样的属性,data-name 和 data-detail 就是两个属性,通过这两个值,可以在 indexDetail 内 event 对象的 target/currentTarget 的 dataset 获取参数。
<view class="life-style">
<view class="item" wx:for="{{lifeStyle}}" data-name="{{item.name}}" data-detail="{{item.detail}}" bindtap="indexDetail">
<view class="title">
<icon type="{{item.icon}}"></icon>
{{item.name}}
</view>
<view class="content">{{item.info}}</view>
</view>
</view>
// weather/index.js
// 响应事件的处理函数
indexDetail(e) {
const {name, detail} = e.currentTarget.dataset
wx.showModal({
title: name,
content: detail,
showCancel: false
})
}
按照官方文档,target 和 currentTarget 都有个 dataset,正确获取 dataset 的姿势是使用 currentTarget 的,但是有时候 target 和 currentTarget 的数据又是完全一样的,如果这里使用 target 的话,那么有时候点击会弹出弹窗,有时候不会弹出,这两者究竟是怎样的关系呢?官方的解释有点模棱两可:
target:触发事件的源组件currentTarget:事件绑定的当前组件这里笔者做下详细解释:
target:触发事件的源组件,上面的代码中,target 可能是 view.title、view.content、view.item 任意触发事件的组件currentTarget:事件绑定的当前组件,上面的代码中,只能是真正绑定了 bindtap 的 view.item下面再来看下例子:
<view id="outer" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" bindtap="handleTap3">
inner view
</view>
</view>
</view>
点击 inner view 时,handleTap3 收到的事件对象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件对象 target 就是 inner,currentTarget 就是 middle。 由此一看,可以简单总结出来:
target是事件触发源头的地方,即事件开始的地方,可以冒泡到父节点触发父节点的绑定事件;而currentTarget是开发者自己绑定事件的地方,即实际的绑定事件的节点。所以,如果绑定的事件有子节点,那么target不会等于currentTarget,有可能是冒泡触发的,由此可见,获取dataset的时候使用currentTarget是靠谱的。
由上面数据驱动和事件监听的处理方式可见,小程序是一套数据和事件驱动的模型,即下面的形式:

关于小程序的运行机制,在第 4 节中会有更加详细的介绍。
在小程序内,不能像 HTML5 中 a 标签那样,随便跳转,也不能像 location 对象中对应的属性那样随意跳转,小程序提供了对应 a 标签和 location 对象的方法:navigator 组件和 wx 中的导航相关函数。
在小程序中,路由是由路由栈来维护的,小程序的路由栈中最多维护 5 个页面,这样在 5 个页面内,小程序维护其渲染页面,可以实现快速的切换。
小程序中跳转页面可以通过下面两种方式:
<navigator url="跳转页面URL" >跳转到新页面</navigator>
wx 中的导航相关函数:<view bindtap="gotoUrl">跳转页面</view>
Page({
gotoUrl(){
let url = 'pages/another/url'
wx.navigateTo({
url
})
}
})
微信内的 JavaScript 相对于浏览器中的有限制也有增强,增强的部分是基于小程序 Native 端能力做的增强,比如增强的文件操作类(相册、录音等);除了增强,跟 HTML5 浏览器环境最大的不同是限制部分。
小程序的执行环境是没有浏览器了,所以浏览器环境特有的 window 对象、BOM 和 DOM 等相关 API 都存在缺失(有对应的补充 API),小程序的执行环境是类似于 Node.js 的一种执行环境。因为没有浏览器环境,所以跟浏览器相关的操作如 cookie、Ajax 请求(XMLHttpRequest)、DOM 选择器、DOM 事件、路由 history、缓存、设备信息、位置等都不存在,与之相对应的是小程序的私有 API,比如我们在小程序中不能使用 XMLHttpRequest,但是可以使用功能更加强大的 wx.request 方法。
本小节介绍小程序布局相关的知识。
小程序 WXSS 中使用了 rpx 这个长度单位,可以用于表示元素的宽高和边距、字体的大小等。对于习惯使用 px 或者 rem 来做页面的前端来说,这可能让人有点迷糊。rpx 是以小程序容器宽度(等于设备宽度)恒等于 750rpx 来做定义的。对于 iPhone 6 来说,因为 dpr 为 2,所以 iPhone 的宽度为 375px,这样在 iPhone 6 上使用 rpx 的话,换算关系为 2rpx=1px。根据这样的关系类推,得到官方给的表格:
设备 | rpx换算 px (屏幕宽度/750) | px 换算 rpx (750/屏幕宽度) |
|---|---|---|
iPhone 5 | 1rpx = 0.42px | 1px = 2.34rpx |
iPhone 6 | 1rpx = 0.5px | 1px = 2rpx |
iPhone 6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
看起来很麻烦,但是只需要按照官方建议,让设计师按照 iPhone 6 的视觉稿标准出图即可,即宽度为 750px,按照 750px 出图,那么我们写页面时直接使用测量的尺寸来设置 rpx 就行了。
在 HTML5 标准中,flex 布局可以简便、完整、响应式地实现各种页面布局,小程序作为晚于 flex 标准创建的 Hybrid 解决方案,自然在布局设计上采用了先进的 flex 布局。
关于 flex 布局相关知识,可以参考阮一峰的 flex 布局教程:语法篇和实例篇。
本节从小程序账号注册说起,依次介绍了小程序开发者工具、小程序开发语言、小程序项目、开发和布局相关的基础知识,内容由浅到深,全面地帮助大家入门小程序开发。
更多微信小程序的基础知识可以参考官方文档:简易教程、框架、组件、API。
通过小册可以学到:
以上是掘金小册的试读部分,个人感觉整个册子值得看看
原文: https://juejin.im/book/5b70f101e51d456669381803/section/5b70f117518825612a2277ea
作者:三水清