轉載請注明原創地址,謝謝
小程序代碼構成
- JSON 配置
- WXML 模版
- WXSS 樣式
- JS 邏輯交互
JSON 配置
在小程序中,JSON扮演的靜態配置的角色。
小程序配置 app.json
{
"pages": ["pages/index/index", "pages/logs/logs"],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
}
}
- pages字段 —— 用於描述當前小程序所有頁面路徑,這是為了讓微信客戶端知道當前你的小程序頁面定義在哪個目錄。
- window字段 —— 定義小程序所有頁面的頂部背景顏色,文字顏色定義等。
全局配置
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
tabBar
如果小程序是一個多 tab 應用(客戶端窗口的底部或頂部有 tab 欄可以切換頁面),可以通過 tabBar 配置項指定 tab 欄的表現,以及 tab 切換時顯示的對應頁面。
其中 list 接受一個數組,只能配置最少 2 個、最多 5 個 tab。tab 按數組的順序排序,每個項都是一個對象
{
"pages": ["pages/index/index", "pages/logs/index"],
"tabBar": {
"list": [
{
"iconPath": "assets/fonts/首頁.png",
"selectedIconPath": "assets/fonts/home.png",
"pagePath": "pages/index/index",
"text": "首頁"
},
{
"pagePath": "pages/logs/logs",
"text": "日志"
}
]
}
}
tabBar 還有其他屬性
顏色僅支持十六進制,定位僅支持top和bottom,其中top時不支持圖標。
{
"tabBar": {
"color": "#ff00ff",
"selectedColor": "#0000ff",
"backgroundColor": "#00ff00",
"position":"bottom"
}
}
頁面配置
每一個小程序頁面也可以使用 .json 文件來對本頁面的窗口表現進行配置。頁面中配置項在當前頁面會覆蓋 app.json 的 window 中相同的配置項
頁面配置中只能設置 app.json 中 window 對應的配置項,以決定本頁面的窗口表現,所以無需寫 window 這個屬性。
WXML 模版
WXML 充當的就是類似 HTML 的角色。
<view class="container">
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}">獲取頭像昵稱</button>
<block wx:else>
<image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
block標簽的作用是直接解析里面的內容,不解析自身block標簽。
WXSS 樣式
WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些擴充和修改。
-
新增了尺寸單位。在寫 CSS 樣式時,開發者需要考慮到手機設備的屏幕會有不同的寬度和設備像素比,采用一些技巧來換算一些像素單位。WXSS 在底層支持新的尺寸單位 rpx ,開發者可以免去換算的煩惱,只要交給小程序底層來換算即可,由於換算采用的浮點數運算,所以運算結果會和預期結果有一點點偏差。
-
提供了全局的樣式和局部樣式。和前邊 app.json, page.json 的概念相同,你可以寫一個 app.wxss 作為全局樣式,會作用於當前小程序的所有頁面,局部頁面樣式 page.wxss 僅對當前頁面生效。
-
此外 WXSS 僅支持部分 CSS 選擇器
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxss.html
iPhone6 1rpx = 0.5px 1px = 2rpx
JS 邏輯交互
<view>{{ msg }}</view>
<button bindtap="clickMe">點擊我</button>
Page({
data:{
msg: '小程序'
},
clickMe() {
this.setData({msg: 'Hello World'})
}
})
更詳細的資料:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
小程序宿主環境
- 渲染層和邏輯層
- 程序與頁面
- 組件
- API
渲染層和邏輯層
小程序的運行環境分成渲染層和邏輯層,其中 WXML 模板和 WXSS 樣式工作在渲染層,JS 腳本工作在邏輯層。
小程序的渲染層和邏輯層分別由2個線程管理:渲染層的界面使用了WebView 進行渲染;邏輯層采用JsCore線程運行JS腳本。一個小程序存在多個界面,所以渲染層存在多個WebView線程,這兩個線程的通信會經由微信客戶端(Native)做中轉,邏輯層發送網絡請求也經由Native轉發。
程序與頁面
微信客戶端在打開小程序之前,會把整個小程序的代碼包下載到本地。
緊接着通過 app.json 的 pages 字段就可以知道你當前小程序的所有頁面路徑。
整個小程序只有一個 App 實例,是全部頁面共享的,具體內容查看注冊程序 App https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/app.html
組件
小程序提供了豐富的組件
https://developers.weixin.qq.com/miniprogram/dev/component/
<navigator
url="/page/navigate/navigate?title=navigate"
hover-class="navigator-hover"
>
跳轉到新頁面
</navigator>
<navigator
url="../../redirect/redirect/redirect?title=redirect"
open-type="redirect"
hover-class="other-navigator-hover"
>
在當前頁打開
</navigator>
<navigator
url="/page/index/index"
open-type="switchTab"
hover-class="other-navigator-hover"
>
切換 Tab
</navigator>
API
為了讓開發者可以很方便的調起微信提供的能力,例如獲取用戶信息、微信支付等等,小程序提供了很多 API 給開發者去使用。
wx.scanCode({
success: (res) => {
console.log(res)
}
})
https://developers.weixin.qq.com/miniprogram/dev/api/index.html
視圖層
- WXML
- WXS
- 事件系統
- 動畫
- 組件
WXML
WXML(WeiXin Markup Language)是框架設計的一套標簽語言,結合基礎組件、事件系統,可以構建出頁面的結構。
數據綁定
<!--wxml-->
<view>{{message}}</view>
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/data.html
列表渲染
默認數組的當前項的下標變量名默認為 index,數組當前項的變量名默認為 item
<!--wxml-->
<view wx:for="{{array}}">{{item}}</view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5]
}
})
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/list.html
如不提供 wx:key,會報一個 warning
<switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;">
{{item.id}}
</switch>
Page({
data: {
objectArray: [
{id: 5, unique: 'unique_5'},
{id: 4, unique: 'unique_4'},
{id: 3, unique: 'unique_3'},
{id: 2, unique: 'unique_2'},
{id: 1, unique: 'unique_1'},
{id: 0, unique: 'unique_0'}
]
}
})
條件渲染
<!--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'
}
})
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/conditional.html
wx:if vs hidden
wx:if 是惰性的,如果在初始渲染條件為 false,框架什么也不做,在條件第一次變成真的時候才開始局部渲染。
相比之下,hidden 就簡單的多,組件始終會被渲染,只是簡單的控制顯示與隱藏。
一般來說,wx:if 有更高的切換消耗而 hidden 有更高的初始渲染消耗。因此,如果需要頻繁切換的情景下,用 hidden 更好,如果在運行時條件不大可能改變則 wx:if 較好。
<view hidden="{{hidden}}">
內容
</view>
模板
<!--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'}
}
})
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/template.html
引用
WXML 提供兩種文件引用方式import和include。
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/import.html
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在 index.wxml 中引用了 item.wxml,就可以使用item模板:
<import src="item.wxml" />
<template is="item" data="{{text: 'forbar'}}" />
WXS
WXS(WeiXin Script)是小程序的一套腳本語言,結合 WXML,可以構建出頁面的結構。
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxs/
頁面渲染
<!--wxml-->
<wxs module="m1">
var msg = "hello world"; module.exports.message = msg;
</wxs>
<view>{{m1.message}}</view>
頁面輸出:
hello world
事件系統
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
什么是事件
- 事件是視圖層到邏輯層的通訊方式。
- 事件可以將用戶的行為反饋到邏輯層進行處理。
- 事件可以綁定在組件上,當達到觸發事件,就會執行邏輯層中對應的事件處理函數。
- 事件對象可以攜帶額外信息,如 id, dataset, touches。
事件的使用方式
<view id="tapTest" data-hi="WeChat" bindtap="tapName">Click me!</view>
Page({
tapName(event) {
console.log(event)
}
})
事件綁定和冒泡
事件綁定的寫法同組件的屬性,以 key、value 的形式。
- key 以bind或catch開頭,然后跟上事件的類型,如bindtap、catchtouchstart。
- value 是一個字符串,需要在對應的 Page 中定義同名的函數。不然當觸發事件的時候會報錯。
bind事件綁定不會阻止冒泡事件向上冒泡,catch事件綁定可以阻止冒泡事件向上冒泡。
如在下邊這個例子中,點擊 inner view 會先后調用handleTap3和handleTap2(因為tap事件會冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父節點傳遞),點擊 middle view 會觸發handleTap2,點擊 outer view 會觸發handleTap1。
<view id="outer" bindtap="handleTap1">
outer view
<view id="middle" catchtap="handleTap2">
middle view
<view id="inner" bindtap="handleTap3">
inner view
</view>
</view>
</view>
事件的捕獲階段
需要在捕獲階段監聽事件時,可以采用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>
動畫
方案1:寫css樣式
#box2{
height: 100px;
width: 100px;
background: blue;
}
#box2:hover{
transform: rotate(180deg) scale(.5, .5);
background: red;
transition: background 2s ease, transform 2s ease-in 1s;
}
方案2:animate.css 庫
// app.wxss 在主頁面引入,page頁面就都可以使用了
@import './assets/animate.wxss';
<view class='{{a}}'></view>
this.setData({
a : ['box', 'animated', 'fadeOutRight']
})
方案3:寫js函數
https://developers.weixin.qq.com/miniprogram/dev/api/wx.createAnimation.html
<button bindtap="fn">動畫</button>
<view
animation="{{animationData}}"
style="background:red;height:100rpx;width:100rpx;position: absolute;top:1000rpx;"
></view>
data: {
animationData: {}
},
fn() {
const animation = wx.createAnimation({
duration: 3000
})
this.animation = animation
animation.scale(2, 2).rotate(45).step().width(400).top(10).step()
this.setData({
animationData: animation.export()
})
}
step方法表示動畫完成。一組動畫中的所有動畫會同時開始,一組動畫完成后才會進行下一組動畫。
導出動畫隊列。export 方法每次調用后會清掉之前的動畫操作。
組件
定義組件
鼠標右鍵->新建組件,會生成一組文件。
// components/toast/toast.js
Component({
//組件的屬性列表
properties: {
str : String
},
//組件的生命周期函數
lifetimes: {
attached() {
// 在組件實例進入頁面節點樹時執行
console.log('attached:', this.properties.str);
},
detached() {
// 在組件實例被從頁面節點樹移除時執行
console.log('刪除')
}
},
// 組件的初始數據
data: {
},
// 組件的方法列表
methods: {
show(){
}
}
})
// components/toast/toast.wxml
<view>
傳過來的屬性:{{str}}
</view>
使用組件
// pages/mine/mine.json
{
"usingComponents": {
"toast":"/components/toast/toast"
}
}
// pages/mine/mine.wxml
<toast id="abc" str="hello"></toast>
// pages/mine/mine.js
Page({
data: {
},
fn(){
this.toast = this.selectComponent("#abc");
this.toast.show();
}
})
邏輯層
- 生命周期
- 路由
- 模塊化
生命周期
page頁的生命周期:https://developers.weixin.qq.com/miniprogram/dev/guide/framework/page-life-cycle.html
page頁生命周期鈎子函數的示例代碼:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html
component頁的生命周期:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html
組件的生命周期,指的是組件自身的一些函數,這些函數在特殊的時間點或遇到一些特殊的框架事件時被自動觸發。
其中,最重要的生命周期是 created attached detached ,包含一個組件實例生命流程的最主要時間點。
- 組件實例剛剛被創建好時, created 生命周期被觸發。此時,組件數據 this.data 就是在 Component 構造器中定義的數據 data 。 此時還不能調用 setData 。 通常情況下,這個生命周期只應該用於給組件 this 添加一些自定義屬性字段。
- 在組件完全初始化完畢、進入頁面節點樹后, attached 生命周期被觸發。此時, this.data 已被初始化為組件的當前值。這個生命周期很有用,絕大多數初始化工作可以在這個時機進行。
- 在組件離開頁面節點樹后, detached 生命周期被觸發。退出一個頁面時,如果組件還在頁面節點樹中,則 detached 會被觸發。
自小程序基礎庫版本 2.2.3 起,組件的的生命周期也可以在 lifetimes 字段內進行聲明(這是推薦的方式,其優先級最高)。
Component({
lifetimes: {
attached() {
// 在組件實例進入頁面節點樹時執行
},
detached() {
// 在組件實例被從頁面節點樹移除時執行
},
},
// 以下是舊式的定義方式,可以保持對 <2.2.3 版本基礎庫的兼容
attached() {
// 在組件實例進入頁面節點樹時執行
},
detached() {
// 在組件實例被從頁面節點樹移除時執行
},
// ...
})
頁面路由
在小程序中所有頁面的路由全部由框架進行管理。
頁面棧
https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/route.html
打開新頁面
調用 API wx.navigateTo
保留當前頁面,跳轉到應用內的某個頁面。但是不能跳到 tabbar 頁面。
wx.navigateTo({
url: 'test?id=1'
})
// test.js
Page({
onLoad(option) {
console.log(option.query)
}
})
使用組件
<navigator open-type="navigateTo"/>
頁面重定向
調用 API wx.redirectTo
關閉當前頁面,跳轉到應用內的某個頁面。但是不允許跳轉到 tabbar 頁面。
wx.redirectTo({
url: 'test?id=1'
})
使用組件
<navigator open-type="redirectTo"/>
頁面返回
調用 API wx.navigateBack
關閉當前頁面,返回上一頁面或多級頁面。
// 注意:調用 navigateTo 跳轉時,調用該方法的頁面會被加入堆棧,而 redirectTo 方法則不會。見下方示例代碼
// 此處是A頁面
wx.navigateTo({
url: 'B?id=1'
})
// 此處是B頁面
wx.navigateTo({
url: 'C?id=1'
})
// 在C頁面內 navigateBack,將返回A頁面
wx.navigateBack({
delta: 2
})
使用組件
<navigator open-type="navigateBack">
用戶按左上角返回按鈕
Tab 切換
調用 API wx.switchTab
跳轉到 tabBar 頁面,並關閉其他所有非 tabBar 頁面
{
"tabBar": {
"list": [
{
"pagePath": "index",
"text": "首頁"
},
{
"pagePath": "other",
"text": "其他"
}
]
}
}
wx.switchTab({
url: '/index'
})
使用組件
<navigator open-type="switchTab"/>
用戶切換 Tab
重啟動
調用 API wx.reLaunch
關閉所有頁面,打開到應用內的某個頁面
wx.reLaunch({
url: 'test?id=1'
})
使用組件
<navigator open-type="reLaunch"/>
模塊化
CommonJS規范
可以將一些公共的代碼抽離成為一個單獨的 js 文件,作為一個模塊。模塊通過 module.exports 能對外暴露接口。
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
module.exports.sayHello = sayHello
const common = require('common.js')
Page({
helloMINA() {
common.sayHello('MINA')
}
})
文件作用域
在 JavaScript 文件中聲明的變量和函數只在該文件中有效;不同的文件中可以聲明相同名字的變量和函數,不會互相影響。
通過全局函數 getApp 可以獲取全局的應用實例,如果需要全局的數據可以在 App 中設置,如:
// app.js
App({
globalData: 1
})
// a.js
// Get the app instance.
const app = getApp()
// Get the global data and change it.
app.globalData++
// b.js
// 如果是從a跳轉到b,那么這次輸出的是2
console.log(getApp().globalData)
能力
- 網絡
- 存儲
網絡
服務器域名配置
每個微信小程序需要事先設置一個通訊域名,小程序只可以跟指定的域名與進行網絡通信。包括普通 HTTPS 請求(wx.request)、上傳文件(wx.uploadFile)、下載文件(wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)
跳過域名校驗
在微信開發者工具中,可以臨時開啟 開發環境不校驗請求域名、TLS版本及HTTPS證書 選項,跳過服務器域名的校驗。此時,在微信開發者工具中及手機開啟調試模式時,不會進行服務器域名的校驗。
wx.request({
url: 'test.php', // 僅為示例,並非真實的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默認值
},
success(res) {
console.log(res.data)
}
})
https://developers.weixin.qq.com/miniprogram/dev/api/wx.request.html
存儲
每個微信小程序都可以有自己的本地緩存
設置
單個 key 允許存儲的最大數據長度為 1MB,所有數據存儲上限為 10MB。
wx.setStorage({
key: 'key',
data: 'value'
})
try {
wx.setStorageSync('key', 'value')
} catch (e) { }
獲取
wx.getStorage({
key: 'key',
success(res) {
console.log(res.data)
}
})
const value = wx.getStorageSync('key')
清理本地所有數據
wx.clearStorage({
success(){}
})
wx.clearStorageSync()
刪除指定的key
wx.removeStorage({
key: 'key',
success(res) {
console.log(res.data)
}
})
wx.removeStorageSync('key')
界面交互
顯示消息提示框
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
顯示模態對話框
wx.showModal({
title: '提示',
content: '這是一個模態彈窗',
success(res) {
if (res.confirm) {
console.log('用戶點擊確定')
} else if (res.cancel) {
console.log('用戶點擊取消')
}
}
})
loading 提示框
顯示 loading 提示框。需主動調用 wx.hideLoading 才能關閉提示框
wx.showLoading({
title: '加載中',
})
setTimeout(function () {
wx.hideLoading()
}, 2000)
顯示操作菜單
wx.showActionSheet({
itemList: ['A', 'B', 'C'],
success(res) {
console.log(res.tapIndex)
},
fail(res) {
console.log(res.errMsg)
}
})
結束
微信小程序當然還提供其他能力,具體應查看官方文檔。