微信小程序
一:項目開始
- 申請小程序賬號
- AppID:
- 服務(wù)器域名:小程序發(fā)請求必須先配置請求的服務(wù)器域名
- 安裝微信開發(fā)者工具
- 使用微信開發(fā)者工具初始化項目
注意
服務(wù)器域名:
- 域名只支持 https (request蚊锹、uploadFile、downloadFile) 和 wss (connectSocket) 協(xié)議姚炕;
- 一個月內(nèi)僅能修改5次
- 小程序必須使用 HTTPS 請求丢烘。小程序內(nèi)會對服務(wù)器域名使用的HTTPS證書進(jìn)行校驗,如果校驗失敗播瞳,則請求不能成功發(fā)起(跳過域名校驗)
二:項目構(gòu)成
- app.js :
全局邏輯
- app.json:
全局配置
,包括小程序的所有頁面路徑忧侧、界面表現(xiàn)牌芋、網(wǎng)絡(luò)超時時間、底部 tab 等 - app.wxss:
全局css
- project.config.json:
微信開發(fā)者工具配置
- page:
頁面
- logs
- index
- json 后綴的 JSON 配置文件:
頁面的單獨配置
- wxml 后綴的 WXML 模板文件:
頁面結(jié)構(gòu)
- wxss 后綴的 WXSS 樣式文件:
頁面樣式
(僅對當(dāng)前頁面生效) - js 后綴的 JS 腳本邏輯文件:
頁面邏輯
(可通過getApp()獲取全局應(yīng)用實例)
- json 后綴的 JSON 配置文件:
注意:為了方便開發(fā)者減少配置項肯夏,描述頁面的四個文件必須具有相同的路徑與文件名
三:生命周期
前臺、后臺定義: 當(dāng)用戶點擊左上角
關(guān)閉
驯击,或者按了設(shè)備Home 鍵離開微信
,小程序并沒有直接銷毀,而是進(jìn)入了后臺苹熏;當(dāng)再次進(jìn)入微信或再次打開小程序,又會從后臺進(jìn)入前臺袱耽。
注意:只有當(dāng)小程序進(jìn)入后臺一定時間干发,或者系統(tǒng)資源占用過高,才會被真正的銷毀
屬性 | 描述 |
---|---|
onLoad(option) | 監(jiān)聽頁面加載: componentWillMount |
onReady | 監(jiān)聽頁面初次渲染完成 -- 結(jié)構(gòu)渲染:相當(dāng)于componentDidMount |
onShow | 監(jiān)聽頁面顯示 -- 前后臺切換 |
onHide | 監(jiān)聽頁面隱藏 -- 前后臺切換 |
onUnload | 監(jiān)聽頁面卸載 -- 跳轉(zhuǎn)頁面 |
- Page.prototype.setData:頁面重新渲染
-
Page.prototype.route:頁面路由
四:視圖層
4.1 wxml
用于描述頁面的結(jié)構(gòu)
data: {
str: 'str',
num1: 1,
num2: 2,
length: 5,
arr: [
{name: 'arr1', id: 1},
{name: 'arr2', id: 2},
],
obj: {
a: 'obj1',
b: 'obj2'
}
}
4.1.1 數(shù)據(jù)綁定
<!-- 數(shù)據(jù)綁定 -->
<view> {{str}} </view>
<view> {{obj.a}} </view>
<!-- 運算 -->
<view>{{num1 + num2}}</view>
<!-- 屬性內(nèi)調(diào)用需要包裹在引號內(nèi) -->
<view id="{{str}}">屬性</view>
<!-- 三元運算 -->
<view id="{{str === '123' ? 1 : 2}}">三元運算</view>
4.1.2 列表渲染
<!-- 默認(rèn)index冀续、item -->
<view wx:for="{{arr}}">
{{index}}: {{item.name}}
</view>
<!-- 修改index洪唐、item -->
<view wx:for="{{arr}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.name}}
</view>
<!-- 渲染多個節(jié)點 -->
<block wx:for="{{[1, 2, 3]}}">
<view> {{index}} </view>
<view> {{item}} </view>
</block>
<!-- 注意wx:key來指定列表中項目的唯一的標(biāo)識符吼蚁,以保證效率和狀態(tài) -->
<view wx:for="{{arr}}" wx:key="id">
{{index}}: {{item.name}}
</view>
<!-- or -->
<view wx:for="{{arr}}" wx:key="*this">
{{index}}: {{item.name}}
</view>
4.1.3 條件渲染
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<!-- 多個節(jié)點 -->
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注意:
<block/>
并不是一個組件,它僅僅是一個包裝元素肝匆,不會在頁面中做任何渲染,只接受控制屬性
wx:if
vs hidden
-
hidden
:始終會渲染 -
wx:if
:可能會渲染
如果有頻繁的切換枯怖,選擇hidden
能曾,否則wx:if
4.1.4 模板
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
<template is="msgItem" data="{{index: 1, msg: 'aaa', time: '2017-1-1'}}"/>
4.1.5 引用
WXML 提供兩種文件引用方式import和include
- import:引用部份
- include:引用全部
import
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
<!-- index.wxml -->
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
include
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
4.2 事件
事件類型
- 冒泡事件:當(dāng)一個組件上的事件被觸發(fā)后,該事件會向父節(jié)點傳遞
- 非冒泡事件:當(dāng)一個組件上的事件被觸發(fā)后塘淑,該事件不會向父節(jié)點傳遞
事件綁定
- bind事件綁定不會阻止冒泡事件向上冒泡
- catch事件綁定可以阻止冒泡事件向上冒泡
- capture-bind事件綁定會觸發(fā)捕獲事件向下捕獲
- capture-catch 中斷捕獲階段和取消冒泡階段
<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>
dataset
事件的參數(shù)
<view bindtap="handleClick" data-alphaBeta="2">click me!</view>
Page({
handleClick: function(e){
console.log(111, e)
}
})
4.3 wxs
WXS(WeiXin Script)是小程序的一套腳本語言蚂斤,結(jié)合 WXML,可以構(gòu)建出頁面的結(jié)構(gòu)
<wxs module="m1">
var msg = "hello world";
var fun = function(num1, num2){
var res = num1 + num2
return res.toFixed(2)
}
module.exports.message = msg;
module.exports.fun = fun;
</wxs>
<view> {{m1.message}} </view>
<view>{{m1.fun(num1, num2)}}</view>
4.4 wxss
WXSS 具有 CSS 大部分特性
全局wxss和page的wxss會自動引用捌治,不需要手動導(dǎo)入
4.4.1 尺寸單位
- rpx(responsive pixel): 可以根據(jù)屏幕寬度進(jìn)行自適應(yīng)
4.4.2 樣式導(dǎo)入
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
import "common.wxss";
.middle-p {
padding:15px;
}
4.4.3 內(nèi)聯(lián)樣式
<view style="color: red;" />
五:組件
降低耦合,利于維護(hù)代碼
5.1 創(chuàng)建組件
page
// page json
{
"component": true,
"usingComponents": {
"comtext": "path/to/the/custom/component"
}
}
引用組件的路徑寫 相對路徑
<!-- page wxml -->
<view>
<!-- 以下是對一個自定義組件的引用 -->
<comtext inner-text="Some text"></comtext>
</view>
引用組件的屬性名采用連寫
component
<!-- component wxml -->
<view class="inner">
{{innerText}}
</view>
<slot></slot>
<slot>
標(biāo)簽用于顯示子節(jié)點
/* component wxss */
.inner {
color: red;
}
注意:在組件wxss中不應(yīng)使用ID選擇器兼吓、屬性選擇器和標(biāo)簽名選擇器(嘗試后可以用標(biāo)簽名選擇器森枪,但建議用class選擇器)
// component js
Component({
properties: {
// 這里定義了innerText屬性,屬性值可以在組件使用時指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 這里是一些組件內(nèi)部數(shù)據(jù)
someData: {}
},
ready: function(){
console.log(this, 'this')
},
methods: {
// 這里是一個自定義方法
customMethod: function(){}
}
})
properties
的屬性名采用駝峰
5.2 事件
page與component之間的事件
page
<comtext inner-text="Some text" bind:parentEvent="parentEvent">
<view bindtap="childEvnet">我是component的子節(jié)點</view>
</comtext>
Page({
parentEvent: function(e){
console.log('parentEvent', e.detail)
}
})
component
<view id="inner">
<text bind:tap="childEvent">{{innerText}}</text>
</view>
<slot></slot>
Component({
properties: {
// 這里定義了innerText屬性浑娜,屬性值可以在組件使用時指定
innerText: {
type: String,
value: 'default value',
}
},
data: {
// 這里是一些組件內(nèi)部數(shù)據(jù)
someData: {}
},
methods: {
// 這里是一個自定義方法
childEvent: function (e) {
console.log('childEvent')
var myEventDetail = {
data: 1
} // detail對象式散,提供給事件監(jiān)聽函數(shù)
var myEventOption = {} // 觸發(fā)事件的選項
this.triggerEvent('parentEvent', myEventDetail, myEventOption)
}
}
})
5.3 behaviors
抽離共用的組件js代碼
behaviors 是用于 組件間 代碼 共享 的特性,類似于一些編程語言中的
mixins
或traits
behavior
// my-behavior.js
module.exports = Behavior({
behaviors: [],
properties: {
myBehaviorProperty: {
type: String
}
},
data: {
myBehaviorData: {}
},
attached: function(){},
methods: {
myBehaviorMethod: function(){}
}
})
component
// my-component.js
var myBehavior = require('my-behavior')
Component({
behaviors: [myBehavior],
properties: {
myProperty: {
type: String
}
},
data: {
myData: {}
},
attached: function(){},
methods: {
myMethod: function(){}
}
})
5.4 組件間關(guān)系
注意:必須在 兩個組件 定義中都加入relations定義漓滔,否則不會生效
page
<!-- page -->
<custom-ul>
<custom-li> item 1 </custom-li>
<custom-li> item 2 </custom-li>
</custom-ul>
custom-ul
<!-- custom-ul wxml -->
<view>
<slot></slot>
</view>
// custom-ul js
Component({
relations: {
'../custom-li/custom-li': {
type: 'child', // 關(guān)聯(lián)的目標(biāo)節(jié)點應(yīng)為子節(jié)點
linked: function (target) {
console.log(target, 'ul-linked')
},
linkChanged: function (target) {
console.log(target, 'ul-linkChanged')
},
unlinked: function (target) {
console.log(target, 'ul-unlinked')
}
}
},
methods: {
_getAllLi: function () {
// 使用getRelationNodes可以獲得nodes數(shù)組乖篷,包含所有已關(guān)聯(lián)的custom-li,且是有序的
var nodes = this.getRelationNodes('../custom-li/custom-li')
console.log(nodes, 'nodes-before')
nodes[0].setData({
name: 2
}, () => {
console.log(nodes, 'nodes-after')
})
}
},
ready: function () {
this._getAllLi()
}
})
custom-li
<!-- custom-li wxml -->
<text>{{name}}</text>
// custom-li js
Component({
data: {
name: 1
},
relations: {
'../custom-ul/custom-ul': {
type: 'parent', // 關(guān)聯(lián)的目標(biāo)節(jié)點應(yīng)為父節(jié)點
linked: function (target) {
console.log(target, 'li-linked')
},
linkChanged: function (target) {
console.log(target, 'li-linked')
},
unlinked: function (target) {
console.log(target, 'li-linked')
}
}
}
})
六:請求
這是一個demo
const url = "https://cnodejs.org/api/v1"
const fetch = function (method = 'get', uri, data = {}, success = () => {}){
wx.request({
method,
url: `${url}/${uri}`,
data,
header: {
'content-type': 'application/json'
},
success
})
}
module.exports = {
url,
fetch
}
<!--pages/demo/demo.wxml-->
<view wx:for="{{category}}" wx:key="id" bindtap="handleTap" class="{{item.del ? 'del' : ''}}" id="{{item.id}}">
{{index}} - {{item.title}}
</view>
.del{
text-decoration: line-through;
}
const { fetch } = require('../../config/api.js')
Page({
data: {
category: []
},
onLoad: function (options) {
this.getList()
},
getList: function(){
fetch('get', '/topics', {}, res => {
const val = res.data.map(v => {
let obj = v
obj.del = false
return obj
})
this.setData({
category: val
})
})
},
handleTap: function(e){
const id = e.currentTarget.id
const index = this.data.category.findIndex(v => v.id == id)
let category = this.data.category
category[index].del = !category[index].del
this.setData({
category
})
}
})