今天,接著往下講,教大家為小程式加入 JavaScript 指令碼,做出動態效果,以及如何跟使用者互動。學會了指令碼,就能做出複雜的頁面了。
本篇的難度要大於前兩篇,如果覺得不好理解,可以先跟著例子,動手做一遍,然後再讀文字說明,可能就容易理解了。
所有示例的完整程式碼,都可以從 GitHub 的程式碼倉庫下載。
一、資料繫結
前面的所有示例,小程式的頁面都是寫死的,也就是頁面內容不會變。但是,頁面資料其實可以透過指令碼傳入,透過指令碼改變頁面,實現動態效果。
小程式提供了一種特別的方法,讓頁面可以更方便地使用指令碼資料,叫做"資料繫結"(data binding)。
所謂"資料繫結",指的是指令碼里面的某些資料,會自動成為頁面可以讀取的全域性變數,兩者會同步變動。也就是說,指令碼里面修改這個變數的值,頁面會隨之變化;反過來,頁面上修改了這段內容,對應的指令碼變數也會隨之變化。這也叫做 MVVM 模式。
下面看一個例子。開啟home.js
檔案,改成下面這樣。
Page({ data: { name: '張三' } });
上面程式碼中,Page()
方法的配置物件有一個data
屬性。這個屬性的值也是一個物件,有一個name
屬性。資料繫結機制規定,data
物件的所有屬性,自動成為當前頁面可以讀取的全域性變數。也就是說,home
頁面可以自動讀取name
變數。
接著,修改home.wxml
檔案,加入name
變數。
<view> <text class="title">hello {{name}}</text> </view>
上面程式碼中,name
變數寫在{{...}}
裡面。這是小程式特有的語法,兩重大括號表示,內部不是文字,而是 JavaScript 程式碼,它的執行結果會寫入頁面。因此,{{name}}
表示讀取全域性變數name
的值,將這個值寫入網頁。
注意,變數名區分大小寫,name
和Name
是兩個不同的變數名。
開發者工具匯入專案程式碼,頁面渲染結果如下。
可以看到,name
變數已經自動替換成了變數值"張三"。
這個示例的完整程式碼,可以檢視程式碼倉庫。
頁面和指令碼對於變數name
是資料繫結關係,無論哪一方改變了name
的值,另一方也會自動跟著改變。後面講解到事件時,會有雙方聯動的例子。
二、全域性資料
資料繫結只對當前頁面有效,如果某些資料要在多個頁面共享,就需要寫到全域性配置物件裡面。
開啟app.js
,改寫如下。
App({ globalData: { now: (new Date()).toLocaleString() } });
上面程式碼中,App()
方法的引數配置物件有一個globalData
屬性,這個屬性就是我們要在多個頁面之間分享的值。事實上,配置物件的任何一個屬性都可以共享,這裡起名為globalData
只是為了便於識別。
然後,開啟home.js
,改成下面的內容,在頁面指令碼里面獲取全域性物件。
const app = getApp(); Page({ data: { now: app.globalData.now } });
上面程式碼中,getApp()
函式是小程式原生提供的函式方法,用於從頁面獲取 App 例項物件。拿到例項物件以後,就能從它上面拿到全域性配置物件的globalData
屬性,從而把app.globalData.now
賦值給頁面指令碼的now
屬性,進而透過資料繫結機制,變成頁面的全域性變數now
。
最後,修改一下頁面程式碼home.wxml
。
<view> <text class="title">現在是 {{now}}</text> </view>
開發者工具匯入專案程式碼,頁面渲染結果如下。
可以看到,頁面讀到了全域性配置物件app.js
裡面的資料。
這個示例的完整程式碼,可以檢視程式碼倉庫。
三、事件
事件是小程式跟使用者互動的主要手段。小程式透過接收各種使用者事件,執行回撥函式,做出反應。
小程式的常見事件有下面這些。
tap
:觸控後馬上離開。longpress
:觸控後,超過 350ms 再離開。如果指定了該事件的回撥函式並觸發了該事件,tap
事件將不被觸發。touchstart
:觸控開始。touchmove
:觸控後移動。touchcancel
:觸控動作被打斷,如來電提醒,彈窗等。touchend
:觸控結束。
上面這些事件,在傳播上分成兩個階段:先是捕獲階段(由上層元素向下層元素傳播),然後是冒泡階段(由下層元素向上層元素傳播)。所以,同一個事件在同一個元素上面其實會觸發兩次:捕獲階段一次,冒泡階段一次。詳細的介紹,請參考我寫的事件模型解釋。
小程式允許頁面元素,透過屬性指定各種事件的回撥函式,並且還能夠指定是哪個階段觸發回撥函式。具體方法是為事件屬性名加上不同的字首。小程式提供四種字首。
capture-bind
:捕獲階段觸發。capture-catch
:捕獲階段觸發,並中斷事件,不再向下傳播,即中斷捕獲階段,並取消隨後的冒泡階段。bind
:冒泡階段觸發。catch
:冒泡階段觸發,並取消事件進一步向上冒泡。
下面透過一個例子,來看如何為事件指定回撥函式。開啟home.wxml
檔案,改成下面的程式碼。
<view> <text class="title">hello {{name}}</text> <button bind:tap="buttonHandler">點選</button> </view>
上面程式碼中,我們為頁面加上了一個按鈕,併為這個按鈕指定了觸控事件(tap
)的回撥函式buttonHandler
,bind:
字首表示這個回撥函式會在冒泡階段觸發(字首裡面的冒號可以省略,即寫成bindtap
也可以)。
回撥函式必須在頁面指令碼中定義。開啟home.js
檔案,改成下面的程式碼。
Page({ data: { name: '張三' }, buttonHandler(event) { this.setData({ name: '李四' }); } });
上面程式碼中,Page()
方法的引數配置物件裡面,定義了buttonHandler()
,這就是<button>
元素的回撥函式。它有幾個地方需要注意。
(1)事件回撥函式的引數是事件物件event
,可以從它上面獲取事件資訊,比如事件型別、發生時間、發生節點、當前節點等等。
(2)事件回撥函式內部的this
,指向頁面例項。
(3)頁面例項的this.setData()
方法,可以更改配置物件的data
屬性,進而透過資料繫結機制,導致頁面上的全域性變數發生變化。
開發者工具匯入專案程式碼,點選按鈕後,頁面渲染結果如下。
可以看到,點選按鈕以後,頁面的文字從"hello 張三"變成了"hello 李四"。
這個示例的完整程式碼,可以檢視程式碼倉庫。
這裡要強調一下,修改頁面配置物件的data
屬性時,不要直接修改this.data
,這不僅無法觸發事件繫結機制去變更頁面,還會造成資料不一致,所以一定要透過this.setData()
去修改。this.setData()
是一個很重要的方法,有很多細節,詳細介紹可以讀一下官方文件。
四、動態提示 Toast
小程式提供了很多元件和方法,用來增強互動效果。比如,每次操作後,都顯示一個動態提示,告訴使用者操作的結果,這種效果叫做 Toast。
開啟home.js
檔案,為this.setData()
加上第二個引數。
Page({ data: { name: '張三' }, buttonHandler(event) { this.setData({ name: '李四' }, function () { wx.showToast({ title: '操作完成', duration: 700 }); }), } });
上面程式碼中,this.setData()
方法加入了第二個引數,這是一個函式,它會在頁面變更完畢後(即this.setData()
執行完)自動呼叫。
這個引數函式內部,呼叫了wx.showToast()
方法,wx
是小程式提供的原生物件,所有客戶端 API 都定義在這個物件上面,wx.showToast()
會展示微信內建的動態提示框,它的引數物件的title
屬性指定提示內容,duration
屬性指定提示框的展示時間,單位為毫秒。
開發者工具匯入專案程式碼,點選按鈕後,頁面渲染結果如下。
過了700毫秒,提示框就會自動消失。
這個示例的完整程式碼,可以檢視程式碼倉庫。
五、對話方塊 Modal
下面,我們再用小程式提供的wx.showModal()
方法,製作一個對話方塊,即使用者可以選擇"確定"或"取消"。
開啟home.js
檔案,修改如下。
Page({ data: { name: '張三' }, buttonHandler(event) { const that = this; wx.showModal({ title: '操作確認', content: '你確認要修改嗎?', success (res) { if (res.confirm) { that.setData({ name: '李四' }, function () { wx.showToast({ title: '操作完成', duration: 700 }); }); } else if (res.cancel) { console.log('使用者點選取消'); } } }); } });
上面程式碼中,使用者點選按鈕以後,回撥函式buttonHandler()
裡面會呼叫wx.showModal()
方法,顯示一個對話方塊,效果如下。
wx.showModal()
方法的引數是一個配置物件。title
屬性表示對話方塊的標題(本例為"操作確認"),content
屬性表示對話方塊的內容(本例為"你確認要修改嗎?"),success
屬性指定對話方塊成功顯示後的回撥函式,fail
屬性指定顯示失敗時的回撥函式。
success
回撥函式里面,需要判斷一下使用者到底點選的是哪一個按鈕。如果引數物件的confirm
屬性為true
,點選的就是"確定"按鈕,cancel
屬性為true
,點選的就是"取消"按鈕。
這個例子中,使用者點選"取消"按鈕後,對話方塊會消失,控制檯會輸出一行提示資訊。點選"確定"按鈕後,對話方塊也會消失,並且還會去呼叫that.setData()
那些邏輯。
注意,上面程式碼寫的是that.setData()
,而不是this.setData()
。這是因為setData()
方法定義在頁面例項上面,但是由於success()
回撥函式不是直接定義在Page()
的配置物件下面,this
不會指向頁面例項,導致this.setData()
會報錯。解決方法就是在buttonHandler()
的開頭,將this
賦值給變數that
,然後在success()
回撥函式里面使用that.setData()
去呼叫。關於this
更詳細的解釋,可以參考這篇教程。
這個示例的完整程式碼,可以檢視程式碼倉庫。
今天的教程就到這裡,對於初學者來說,已經講了很多東西,可能需要慢慢消化。如果對網頁開發和 JavaScript 語言不熟悉,你也許會覺得不容易完全理解,不用擔心,初學者只需要知道加入指令碼的方法,以及指令碼可以達到的效果就可以了,後面做到實際的專案,慢慢就會加深理解。
有了指令碼以後,就可以透過小程式 API,去呼叫微信的各種內建能力。下一篇教程將重點講解如何使用小程式 API。
(完)