微信小程序
代码构成
.json
后缀的JSON
配置文件.wxml
后缀的WXML
模板文件,参考.wxss
后缀的WXSS
样式文件,参考.js
后缀的JS
脚本逻辑文件.wxs
后缀的WeiXin Script
脚本语言,不能跟JS、微信API等交互,但是性能优于JS(一些纯前端的逻辑,如:format处理等可以使用wxs处理),参考、详细文档
json配置
注意:JSON文件中无法使用注释,试图添加注释将会引发报错
app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部tab等
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true
}
project.config.json 是开发者工具相关配置
开发者工具
详情(右上)-> 本地设置 -> 不校验合法域名... -> 反勾选,看看能不能本地调试
快捷键
工具 -> 设置 -> 快捷键设置
- 选择所有找到的查找匹配项 -> alt + q
- 将下一个查找匹配项添加到选择 -> alt + d
- 将上次选择移动到下一个查找匹配项 => alt + k + d
图标
CSS样式
/* 方式1:矢量字体图标,需在iconfont网站设置字体对应的unicode编码 */
/* 尝试使用不同的字体源兼容不同的设备 */
/* 小程序中建议使用TTF和WOFF格式,WOFF2在低版本IOS上不兼容 */
@font-face {
font-family: 'iconfont';
src: url('//at.alicdn.com/t/font_1716930_3m30jvz589y.eot');
src: url('//at.alicdn.com/t/font_1716930_3m30jvz589y.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_1716930_3m30jvz589y.woff2') format('woff2'),
url('//at.alicdn.com/t/font_1716930_3m30jvz589y.woff') format('woff'),
url('//at.alicdn.com/t/font_1716930_3m30jvz589y.ttf') format('truetype'),
url('//at.alicdn.com/t/font_1716930_3m30jvz589y.svg#iconfont') format('svg');
}
@font-face {
font-family: 'iconfont';
src: url('//at.alicdn.com/t/font_1716930_3m30jvz589y.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-sun:before {
content: "\e603";
color: red;
font-size: 20px;
}
/* 方式2:在iconfont网站下载svg图标,然后转成base64后使用 */
.svg-icon{
display: block;
width: 200px;
height: 200px;
background-repeat: no-repeat;
background: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNTg5MjEzNjE0NDc2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjggMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEzMDEiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNTE0LjEzMzMzMyA1MDkuODY2NjY3bS0yNTYgMGEyNTYgMjU2IDAgMSAwIDUxMiAwIDI1NiAyNTYgMCAxIDAtNTEyIDBaIiBmaWxsPSIjZDQyMzdhIiBwLWlkPSIxMzAyIj48L3BhdGg+PHBhdGggZD0iTTUxNC4xMzMzMzMgMTcwLjY2NjY2N2MtMTkuMiAwLTMyLTE0LjkzMzMzMy0zMi0zMlYyOS44NjY2NjdjMC0xNy4wNjY2NjcgMTIuOC0yOS44NjY2NjcgMjkuODY2NjY3LTI5Ljg2NjY2N2gyLjEzMzMzM2MxNy4wNjY2NjcgMCAzMiAxNC45MzMzMzMgMzIgMzJ2MTA4LjhjMCAxNC45MzMzMzMtMTQuOTMzMzMzIDI5Ljg2NjY2Ny0zMiAyOS44NjY2Njd6TTUxNC4xMzMzMzMgMTAyNGMtMTkuMiAwLTMyLTE0LjkzMzMzMy0zMi0zMnYtMTA4LjhjMC0xNy4wNjY2NjcgMTQuOTMzMzMzLTMyIDMyLTMyaDIuMTMzMzM0YzE3LjA2NjY2NyAwIDMyIDE0LjkzMzMzMyAzMiAzMnYxMDguOGMtMi4xMzMzMzMgMTcuMDY2NjY3LTE3LjA2NjY2NyAzMi0zNC4xMzMzMzQgMzJ6TTg1My4zMzMzMzMgNTA5Ljg2NjY2N2MwLTE5LjIgMTQuOTMzMzMzLTMyIDMyLTMyaDEwOC44YzE3LjA2NjY2NyAwIDMyIDE0LjkzMzMzMyAzMiAzMnYyLjEzMzMzM2MwIDE3LjA2NjY2Ny0xNC45MzMzMzMgMzItMzIgMzJoLTEwOC44Yy0xNy4wNjY2NjctMi4xMzMzMzMtMzItMTcuMDY2NjY3LTMyLTM0LjEzMzMzM3pNMCA1MDkuODY2NjY3YzAtMTkuMiAxNC45MzMzMzMtMzIgMzItMzJoMTA4LjhjMTcuMDY2NjY3IDAgMzIgMTQuOTMzMzMzIDMyIDMydjIuMTMzMzMzYzAgMTcuMDY2NjY3LTE0LjkzMzMzMyAzMi0zMiAzMkgzMmMtMTcuMDY2NjY3LTIuMTMzMzMzLTMyLTE3LjA2NjY2Ny0zMi0zNC4xMzMzMzN6TTc0Mi40IDI0Ny40NjY2NjdjLTEyLjgtMTIuOC0xMi44LTMyLTIuMTMzMzMzLTQ0LjhsNzYuOC03Ni44YzEyLjgtMTIuOCAzMi0xMi44IDQ0LjggMFYxMjhjMTIuOCAxMi44IDEyLjggMzIgMCA0NC44bC03Ni44IDc2LjhjLTEwLjY2NjY2NyAxMC42NjY2NjctMzIgMTAuNjY2NjY3LTQyLjY2NjY2Ny0yLjEzMzMzM3pNMTM4LjY2NjY2NyA4NTEuMmMtMTIuOC0xMi44LTEyLjgtMzQuMTMzMzMzLTIuMTMzMzM0LTQ0LjhsNzYuOC03Ni44YzEyLjgtMTIuOCAzMi0xMi44IDQ0LjggMGwyLjEzMzMzNCAyLjEzMzMzM2MxMi44IDEyLjggMTIuOCAzMiAwIDQ0LjhMMTgzLjQ2NjY2NyA4NTMuMzMzMzMzYy0xMi44IDEwLjY2NjY2Ny0zMiAxMC42NjY2NjctNDQuOC0yLjEzMzMzM3pNNzQwLjI2NjY2NyA3MjcuNDY2NjY3YzEyLjgtMTIuOCAzNC4xMzMzMzMtMTIuOCA0NC44LTIuMTMzMzM0bDc2LjggNzYuOGMxMi44IDEyLjggMTIuOCAzMiAwIDQ0LjhsLTIuMTMzMzM0IDIuMTMzMzM0Yy0xMi44IDEyLjgtMzIgMTIuOC00NC44IDBsLTc2LjgtNzYuOGMtMTAuNjY2NjY3LTEyLjgtMTAuNjY2NjY3LTMyIDIuMTMzMzM0LTQ0Ljh6TTEzNi41MzMzMzMgMTIzLjczMzMzM2MxMi44LTEyLjggMzQuMTMzMzMzLTEyLjggNDQuOC0yLjEzMzMzM2w3Ni44IDc2LjhjMTIuOCAxMi44IDEyLjggMzIgMCA0NC44bC0yLjEzMzMzMyAyLjEzMzMzM2MtMTIuOCAxMi44LTMyIDEyLjgtNDQuOCAwTDEzNi41MzMzMzMgMTY4LjUzMzMzM2MtMTAuNjY2NjY3LTEyLjgtMTAuNjY2NjY3LTMyIDAtNDQuOHoiIGZpbGw9IiNGRkM0NDUiIHAtaWQ9IjEzMDMiPjwvcGF0aD48L3N2Zz4=");
}
图标使用
<icon class="iconfont icon-sun"></icon>
<icon class="svg-icon"></icon>
wxml模板
跟vue的模板类似,具体参考:wxml模板
wxss样式
wxss具有css大部分的特性,小程序在wxss也做了一些扩充和修改,具体参考:wxss样式
跟app.json类似,可以写一个app.wxss作为全局样式
wxss在底层支持新的尺寸单位rpx(responsive pixel)来兼容不同尺寸的设备,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差
rpx把屏幕分成750个单位,每个单位是1/750。iPhone6上屏幕宽度是350px,那么每个RPX约等于0.5px,此时60rpx = 30px
wxss变量使用
/* app.wxss 中定义全局变量*/
Page {
--txf-main-color: #1aad19;
}
/* test.wxss 中使用变量 */
.title {
color: var(--txf-main-color, 'red');
}
/* 计算 */
.test {
height:calc(100vh - 170rpx);
}
常用伪类选择器
/* 当用户将鼠标悬停在元素上时应用样式 */
button:hover {
background-color: blue;
}
/* 当用户点击元素时应用样式 */
button:active {
background-color: red;
}
/* 当元素获得焦点时应用样式,通常用于表单元素 */
input:focus {
border: 1px solid blue;
}
/* 选择作为某个元素的第一个子元素的元素 */
div > p:first-child {
color: green;
}
/* 选择作为某个元素的最后一个子元素的元素 */
ul > li:last-child {
border-bottom: none;
}
/* 选择作为某个元素的特定序号的子元素的元素 */
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 选择被选中的单选按钮或复选框 */
input[type="checkbox"]:checked {
background-color: yellow;
}
/* 选择不符合特定条件的元素 */
div:not(.highlight) {
color: grey;
}
/* 选择文档的根元素,通常用于定义全局变量
小程序中使用:root无效,使用Page{--main-color: #ff0000;}代替
*/
:root {
--main-color: #ff0000;
}
wxss命名规范
wxss: 模块__模块元素-描述符
weui-cell__radio
weui-cell__radio-selected
全局
txf__input
具体页面
覆盖: txf__input
不覆盖: txf-login__input
指定字段: txf-login__input-password
指定字段聚焦: txf-login__input-password:focus
js逻辑
跟vue的写法类似,可以调用微信封装的一些API,具体参考:事件 API
小程序宿主环境
小程序的运行环境分成渲染层和逻辑层,其中WXML模板和WXSS样式工作在渲染层,JS脚本工作在逻辑层
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView进行渲染;逻辑层采用JsCore线程运行JS脚本
一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(Native)做中转,逻辑层发送网络请求也经由Native转发,如下图:
微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地,app.json的pages字段的第一个页面就是这个小程序的首页
小程序启动之后,在app.js定义的App实例的onLaunch回调会被执行,整个小程序只有一个App实例,是全部页面共享的
- 增加App和Page方法,进行程序注册和页面注册
- 增加getApp和getCurrentPages方法,分别用来获取App实例和当前页面栈
- 提供丰富的API,如微信用户数据,扫一扫,支付等微信特有能力
- 提供模块化能力,每个页面有独立的作用域
- 小程序框架 小程序组件
注册小程序
// app.js
App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
获取全局实例
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
注册页面
//index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// 页面创建时执行
},
onShow: function() {
// 页面出现在前台时执行
},
onReady: function() {
// 页面首次渲染完毕时执行
},
onHide: function() {
// 页面从前台变为后台时执行
},
onUnload: function() {
// 页面销毁时执行
},
onPullDownRefresh: function() {
// 触发下拉刷新时执行
},
onReachBottom: function() {
// 页面触底时执行
},
onShareAppMessage: function () {
// 页面被用户分享时执行
},
onPageScroll: function() {
// 页面滚动时执行
},
onResize: function() {
// 页面尺寸变化时执行
},
onTabItemTap(item) {
// tab 点击时执行
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// 事件响应函数
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
// 自由数据
customData: {
hi: 'MINA'
}
})
页面生命周期

Hello World
hover-class属性,单击变样式
hover-start-time属性,触发单击变样式的默认时间,默认50毫秒
bindtap会向父组件冒泡,catchtap不会向父组件冒泡
<!-- This is our View -->
<view> Hello {{name}}! </view>
<button hover-class="bg_red" bindtap="changeName"> Click me! </button>
// This is our App Service.
// This is our data.
var helloData = {
name: 'Weixin'
}
// Register a Page.
Page({
data: helloData,
changeName: function(e) {
// sent data change to view
this.setData({
name: 'MINA'
})
}
})
Component构造器
Page构造器适用于简单的页面。但对于复杂的页面,更建议使用Component构造器,参考
类似于自定义组件
Component({
data: {
text: "This is page data."
},
methods: {
onLoad: function(options) {
// 页面创建时执行
},
onPullDownRefresh: function() {
// 下拉刷新时执行
},
// 事件响应函数
viewTap: function() {
// ...
}
}
})
路由相关
模块化
可以将一些公共的代码抽离成为一个单独的js文件,作为一个模块
微信API
其他
事件相关
内置组件可以使用wxs来处理事件(前提是纯前端逻辑,可以提升性能)
网络
api.weixin.qq.com不能用wx.request请求,需要在服务器请求
app.json可配置超时时间,默认是60s
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
}
只要成功接收到服务器返回,无论statusCode是多少,都会进入success回调。请开发者根据业务逻辑对返回值进行判断
sitemap配置
可以理解成小程序SEO,参考:sitemap配置
场景值
场景值用来描述用户进入小程序的路径。完整场景值的含义请查看场景值列表,参考 详细配置
第三方组件
weui样式库、weui组件库,可以使用扩展声明的方式直接在小程序中使用。app.json -> useExtendedLib中添加对weui的引用。开发者工具 -> 工具 -> 构建npm
weui滑动删除举例:usingComponents中添加mp-slideview的引用
parser: 渲染HTML
painter、wxml-to-canvas:视图生成为图片
文档阅读顺序
开发前,看一看
使用组件时,找一找
使用前端API时,找一找
使用后端API时,找一找
指南细分
- 调试
- Skyline渲染引擎
- glass-easel组件框架
- 性能与体验
- 等等
npm包
示例
npm init
npm install @vant/weapp -S --production
详情 -> 工具 -> 勾选使用npm模块
工具 -> 构建npm
app.json
{
// 去掉
"style": "v2",
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-area": "@vant/weapp/area/index",
...
}
}
app.wxss
/* 引入全局样式 */
@import '/miniprogram_npm/@vant/weapp/common/index.wxss'
骨架屏
骨架屏是页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容
setData
// [] 动态指定属性名称
this.setData({
[`formData.${field}`]: e.detail.value
});
自定义导航栏
{
"navigationStyle": "custom",
"styleIsolation": "apply-shared" // isolated | apply-shared | shared
}
其他
wx.getSystemInfo({
success: (res) => {
// 如果能找到ios肯定在最左,如:ios 10.0.1。0 + 1 = 1
// 如果找不到,-1 + 1 = 0
// !!快速转bool
// IOS工具栏高度:44 Android工具栏高度:48
var ios = !!(res.system.toLowerCase().search('ios') + 1)
console.log(ios)
}
})