1. 程式人生 > >微信小程式上手篇(3)

微信小程式上手篇(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 的值以兩種形式提供

  1. 字串,代表在 for 迴圈的 array 中 item 的某個 property,該 property 的值需要是列表中唯一的字串或數字,且不能動態改變。
  2. 保留關鍵字 *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全部研究透徹,作為微信小程式開發學習,我們要學以致用,從學習中舉一反三,祝大家早日開發出自己的小程式!