微信小程式上手篇(3)
還只剩最後一個page需要研究了,勝利的曙光就在眼前。
在這個檔案中,程式碼並不多,而且也比較容易。
//logs.js var util = require('../../utils/util.js') Page({ data: { logs: [] }, onLoad: function () { this.setData({ logs: (wx.getStorageSync('logs') || []).map(function (log) { return util.formatTime(new Date(log)) }) }) } })
在一開始demo引入了一個工具,其實就是utils資料夾中的檔案:
var util = require('../../utils/util.js')
我們可以看到微信是用require來引入的,其實在官方文件中還有import和include引入,不過各司其職,需要讀者自己去看官方文件研究。
對了,在上一篇中沒有提到,在App({...})或者Page({...})方法外定義的變數是一個全域性變數,在這個檔案中都可以使用。
照例,在這個page檔案的data中定義了一個logs陣列變數,這個變數是個老朋友,因為在app.js中也有一個這樣類似的變數:
var logs = wx.getStorageSync('logs') || []
在onLoad中應證了我的想法,他用到了本地快取中的logs:
logs: (wx.getStorageSync('logs') || []).map(function (log) {
return util.formatTime(new Date(log))
})
這個時候唯一不太明白的是map方法和util這個變數的方法。首先看map方法,這個必須結合頁面來看,它達到的效果是:
首先我們肯定的是logs是一個數組,wx.getStorageSync('logs')獲取的正是一個數組,所以說map是一個數組方法。其次頁面上展示了一行一行的時間,所以說map會遍歷陣列,從0開始(所有語言陣列幾乎都是從0開始),其次map的引數是一個方法,其中這個方法還帶了一個引數log,我大膽猜測這個log即是陣列中的內容,因此,map會遍歷陣列每一項而且都會進行一次function(log){}方法(筆者曾試過百度map方法,查到的內容比較規範但是特別雜繁瑣,針對本demo而言我覺得更適合用拆分方法來解釋map的用法)。
既然清楚了map的方法實現,我們再來看看util變數實現了什麼方法:
util.formatTime(new Date(log))
我們直接跳轉到utils資料夾,點選看原始碼:
function formatTime(date) {
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
module.exports = {
formatTime: formatTime
}
這是個簡單的js檔案,而在這個檔案中我們沒有看到App({...})或者Page({...})類似的方法,只是單純的羅列了三個方法function formatTime(),function formatNumber(),module.exports,顯而易見的是前面兩個方法應該是一個公開方法,因為在logs.js中已經呼叫過formatTime:
util.formatTime(new Date(log))
我們可以嘗試呼叫formatNumber(),是否能夠成功:
var n = util.formatNumber(1)
成功了麼?答案是否定的,而且控制檯報了這樣的錯誤:util.formatNumber is not a function;at "pages/logs/logs" page lifeCycleMethod onLoad function
這是為什麼?答案就在這裡:
module.exports = {
formatTime: formatTime
}
有幸的是筆者在這之前接觸過php的第三方框架thinkPhp,裡面正好有類似的程式碼。這個有什麼用呢?簡單來說就是讓你這裡的方法公開給其他類使用,我們可以看到這裡我們只公開了formatTime方法(第一個是我們取的方法名,第二個是util.js中需要公開的方法名),如果我們把formatNumber()方法也公開了,就不會出現上面的錯誤了:
fn : formatNumber
為了區別兩個引數的不同,筆者專門把自己自定義的方法名簡寫了,然後將
var n = util.formatNumber(1)
改寫為
var n = util.fn(1)
為了更加直觀,筆者直接將結果顯示在了頁面上:
紅框中的01正是方法的返回值,所以說如果想要寫工具類讓其他類使用,需要module.exports來定義你的公開方法。
function formatTime(date) {
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
現在簡單說說這幾行程式碼的意思:傳入一個date引數,然後使用date的方法獲取年月日時分秒,返回這個時間點的格式化內容。格式化方法是這個:
[year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
將年月日放進陣列,並用map遍歷,獲取格式化的日期,formatNumber就是格式化的方法。formatNumber中獲取到n為時間,將它字串轉換,然後檢查這個字串是單是雙,由n[1]就可以判斷單雙,因為如果是單隻有n[0],如果是雙就是n[0][1]。所以判斷出單雙後,如果是單新增一個0到數字前方,如果是雙則直接返回。這樣做的結果最簡單的體現就是當為1,則會返回01;如果是10則返回10。
之後有一個join('/')方法,這個最直觀的從介面上就可以判斷出在陣列每一項後面加上/,並且在最後一個下標的值忽略不實現,這樣我們就可以獲得我們經常看到的年月日格式2017/01/10。在後面的時分秒也是同理。
基本上logs.js也看完了,接下來分析logs.json。在這裡有一些內容,並不是全空的:
{
"navigationBarTitleText": "檢視啟動日誌"
}
記得在app.json中也有個引數叫做navigationBarTitleText:
"navigationBarTitleText": "WeChat",
我們在這裡同樣寫了這個東西有什麼用呢?很簡單直接把我們的標題改變了唄:
由此我們得到一個結論,子類的配置檔案json修改相同引數,優先顯示子類的json配置,然後再顯示父類的。當然,可以應證一下原理,我們在logs.json中把標題改為藍色,這樣的效果應該是首頁的WeChat顏色不變,而檢視啟動日誌變為了藍色:
"navigationBarTextStyle":"blue"
bingo,原理正確。
在logs.wxml中我們又看到了有趣的東西:
<!--logs.wxml-->
<view class="log-list">
<block wx:for="{{logs}}" wx:for-item="log" wx:key="*this">
<text class="log-item">{{index + 1}}. {{log}}</text>
</block>
</view>
<block>這個東西,block英文是塊,所以說這個就是一塊一塊的意思。我們記得{{}}中的是js中的變數,所以logs是一個數組。在這裡為了顯示陣列資料,微信用的是wx:for這個語句。這倒是像我們寫for int i = 0;i < count;i++的迴圈語句。wx:for-item獲取到的應該是陣列每一個值,而"log"則被賦予了這個值的別名,我們用log就能代表陣列中的值。wx:key="*this"很晦澀難懂,在這裡我們感覺是一個毫無相關的東西,因此完全不能亂猜,這裡我們最好的解決方案:查詢官方文件。
文件內容:
wx:key
如果列表中專案的位置會動態改變或者有新的專案新增到列表中,並且希望列表中的專案保持自己的特徵和狀態(如
<input/>
中的輸入內容,<switch/>
的選中狀態),需要使用 wx:key
來指定列表中專案的唯一的識別符號。
wx:key
的值以兩種形式提供
- 字串,代表在 for 迴圈的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字串或數字,且不能動態改變。
- 保留關鍵字
*this
代表在 for 迴圈中的 item 本身,這種表示需要 item 本身是一個唯一的字串或者數字,如:
當資料改變觸發渲染層重新渲染的時候,會校正帶有 key 的元件,框架會確保他們被重新排序,而不是重新建立,以確保使元件保持自身的狀態,並且提高列表渲染時的效率。
如不提供 wx:key
,會報一個
warning
, 如果明確知道該列表是靜態,或者不必關注其順序,可以選擇忽略。
文件中所述最簡單的解釋在這裡就是*this指的是陣列中的item本身,而且在靜態陣列中有了這個值提高了渲染效率。這個引數暫時在這裡不深入研究,筆者也只是略懂了點皮毛,技術有限請諒解。
這裡還有一個神奇的引數index,這個應該是預設生成給開發者呼叫下標用的,咱們用就是了。
在這裡我們還是沒有清楚block的用法,最簡單的還是得結合圖看:
我們通過block的方法,獲得了一個列表,所以不用想,block就是一行一行的資料,它的用法就是將內容以塊來顯示,然後批量使用。在這裡我們block中只有text,所以暫時看不出block的強大,我們再加一個view進去:
logs.wxml中
<!--logs.wxml-->
<view class="log-list">
<block wx:for="{{logs}}" wx:for-item="log" wx:key="*this">
<text class="log-item">{{index + 1}}. {{log}}</text>
<view class="blockView">asd</view>
</block>
</view>
logs.wxss中
.log-list {
display: flex;
flex-direction: column;
padding: 40rpx;
background: gray;
}
.log-item {
margin: 10rpx;
text-align: center;
}
.blockView {
background: blue;
}
再來看顯示結果:
現在很明顯了,以block中的內容為一塊內容,我們創建出了一個列表。在以後的開發中,我相信大家會使用更多的block,實踐出真知,大家會越用越熟練的。
最後的一個wxss檔案我就不加闡述了,樣式這個東西除了練還是練,希望筆者與大家一起進步,早日練到運用自如。自此,整個demo全部研究透徹,作為微信小程式開發學習,我們要學以致用,從學習中舉一反三,祝大家早日開發出自己的小程式!