咱們在開始微信小程序開發的時候,對JS,HTML等前端知識一無所知,完徹底全就是門外漢在嘗試一個新的方向。javascript
在下載好開發工具,微信就已經提供了一個DEMO例子:前端
從程序開發的角度來看這個陌生的目錄結構,pages是存放頁面的,utils是存放工具類的,而app開頭的三個文件既然放在根目錄級別,那麼按理講,應該是和配置有關。java
咱們看app.js文件的內容:json
//app.js App({ onLaunch: function () { //調用API從本地緩存中獲取數據 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) }, getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ //調用登陸接口 wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } }, globalData:{ userInfo:null } })
根據官方文檔的說明,這個文件用於編寫微信小程序的頁面邏輯。小程序
App函數用於註冊一個小程序,onLanuch用於處理小程序的初始化,當小程序初始化完成的時候會調用一次。微信小程序
onLanuch這裏的處理是取出wx中的log,而後再把當前日期添加進去。數組
wx是一個命名空間,至關於一個庫,它有不少公共方法。緩存
咱們這裏的操做和Android中使用SP(SharePreferences)是差很少的,wx有個本地緩存,這個緩存能夠根據相關的key值取出對應的內容。這裏有個有趣的語法:|| [],在javascript中,表示若是這個變量若是是undefined,null,NAN,false,0中的任意一種,就設置爲一個空的數組,能夠理解爲?:的用法。而後調用javascript的unshift方法,把當前日期插入數組的第一個元素。微信
getUserInfo是自定義的函數,傳入一個函數做爲參數,並且這裏還定義了全局對象globalData,它有一個字段userInfo,初始值爲null,經過判斷userInfo是否爲空,非空則在cb爲函數類型的狀況下調用cb,空的狀況下,則經過調用wx.login方法,在success的狀況下調用wx的getUserInfo獲取userInfo。網絡
這個js文件已經大概的展現了javascript的不少基本語法,由於javascript是動態語言,它是面向函數語言,所以和java這種面嚮對象語言在語義實現上,差異至關大,咱們能夠簡單的理解爲java操做的是對象,而javascript操做的是函數,而wx.login中的參數就是一個對象,所以用{}包起來,函數其實也是一個對象,因此它後面一樣也有{},這個對象就是loginObject,在它success的時候調用wx.getUserInfo函數。
不管是面向對象仍是面向函數,本質上都是體現開發人員理解問題的思路,只是語義實現上不一樣而已,畢竟javascript和java要解決的問題所在的領域有着至關大的差別。
咱們再看看app.json這個文件:
{ "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } }
根據文檔的解釋,這個文件是對微信小程序進行全局配置,決定頁面文件的路徑、窗口表現、設置網絡超時時間、設置多tab等。
pages用於設置頁面的路徑,是一個數組,咱們這個DEMO的頁面只有兩個:index和logs,其中第一個元素,index,是小程序的第一個頁面,每次新增或者刪除某個頁面,都要在這裏進行修改。
window用來設置默認的窗口的屬性,顯然app.json是設置整個小程序窗口的默認屬性,會被具體頁面的相關屬性覆蓋。
最後是app.wxss:
/**app.wxss**/ .container { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 200rpx 0; box-sizing: border-box; }
這個文件其實就是CSS文件,不過微信本身自己作了一些處理,這個文件的內容就是設置了container這個節點視圖的公共屬性。
從這三個根目錄的文件,咱們也大概知道一個小程序的頁面的組成結構,可是還少了一個文件,那就是頁面視圖的文件。
DEMO的logs頁面就包含了四個文件:.json,.js,.wxss和.wxml。
咱們看一下logs.wxml這個文件:
<!--logs.wxml--> <view class="container log-list"> <block wx:for="{{logs}}" wx:for-item="log" wx:key="*this"> <text class="log-item">{{index + 1}}. {{log}}</text> </block> </view>
<view/>表示一個視圖的節點,至關於Android中的ViewGroup,而後經過class賦予這個view一個或多個類名,wxss就是經過這個class來控制對應視圖的渲染效果,這裏是兩個類名:container和log-list,目的就是在一些屬性上覆蓋.container的設置。
<block/>表示這是一個多節點的視圖,也就是列表組件,經過wx:for表示這個列表組件的數組來源,在微信的設計中,{{}}表示數據綁定,這裏綁定了logs這個數組做爲數據來源。
wx:for-item指定了當前數組的元素名,咱們能夠理解爲java中的加強for的用法:for(item : array)。
wx:key表示一個惟一標識,由於這個數組是動態數組,會不斷增長本身自己的長度,而咱們不但願已經建立好的元素在從新渲染的時候會被修改,所以經過wx:key指定*this,表示for循環中的item只是被從新排序,而不是被從新建立,這樣是爲了提升渲染的效率。
最後咱們看一下<block/>裏面的子視圖,是一個text視圖,渲染的內容是數組中的元素,默認數組的下標變量名是index,元素名稱是item,所以{{index + 1}}表示取當前元素的下標,由於下標是從0開始,因此這裏加1來和人類世界中下標從1開始的共識達成一致,而log就是logs中的元素的內容,由於咱們已經經過wx:for-item指定了item的名稱爲log。
logs目錄下的logs.js也是至關有意思的:
//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)) }) }) } })
util.js是咱們utils目錄的文件,這裏的"../../utils/util.js"是經過相對路徑來導入這個js文件,按照咱們的理解,至關於import一個庫。
Page函數是用來註冊一個頁面,data聲明頁面的初始數據,這裏是一個logs數組,而data裏面的數據是經過json傳遞到頁面,所以這裏面的格式要確保徹底符合json格式。而後調用onLoad函數,在加載頁面的時候經過setData將邏輯層的數據傳遞到視圖層,也就是所謂的數據綁定,而且改變this.data的內容。
setData中的函數經過調用數組的map函數,將數組的內容從新映射成新的內容,這裏至關於初始化數組,map就是用來對數組內容進行賦值的。
咱們看一下util.js的內容:
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 }
這裏的內容很簡單,就是對log的日期進行格式化,不過咱們注意到最後的內容,module.exports執行了賦值操做。
這個實際上是和require搭配的,require返回的就是這個module.exports,而後定義了一個formatTime對象,也就是能夠調用的對象,而這個對象就是formatTime函數。
經過require和module.exports來肯定了這個js文件暴露出來的API。
咱們如今來關注一個很重要的語法:=和:這兩個操做符究竟是怎麼用的。
=就是賦值操做符,這個毋庸置疑,而:其實也是賦值操做,對於a:function,其實表示key值爲a的value的內容爲function,因此formatTime:formatTime就是表示util.formatTime這個屬性對應的是formatTime函數。
咱們再來看一下index目錄下的文件。
先看一下index.js:
//index.js //獲取應用實例 var app = getApp() Page({ data: { motto: 'Hell World', userInfo: {} }, //事件處理函數 bindViewTap: function() { wx.navigateTo({ url: '../logs/logs' }) }, onLoad: function () { console.log('onLoad') var that = this //調用應用實例的方法獲取全局數據 app.getUserInfo(function(userInfo){ //更新數據 that.setData({ userInfo:userInfo }) }) } })
咱們經過getApp函數來獲取小程序實例,由於咱們須要調用app.js中的函數,這裏調用的是getUserInfo,能夠理解爲app.js中定義的方法都是公共方法,由於這裏並無require和module.exports的調用。
這裏有一個新的知識點:bindViewTap。
這個是一個事件處理函數,事件是邏輯層到視圖層的通信方式,將用戶的行爲反饋到邏輯層進行處理,bindViewTap這個事件函數是用戶在點擊時候觸發的,至關於onClick,wx.navigateTo表示跳轉到url指定的頁面。
咱們看一下inde.wxml文件就知道了:
<!--index.wxml--> <view class="container"> <view bindtap="bindViewTap" class="userinfo"> <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </view> <view class="usermotto"> <text class="user-motto">{{motto}}</text> </view> </view>
要經過bindtap指定點擊事件函數。
事件分爲兩種:冒泡事件和非冒泡事件,冒泡事件會把事件往上傳遞,而非冒泡則反之。冒泡事件前綴是bind,而非冒泡事件是catch。
經過對這個DEMO,咱們大概瞭解到小程序的目錄結構,和一些相關的基礎知識,後面會在具體的開發工做中繼續補充相關的知識。