微信小程序官方DEMO解读

    咱们在开始微信小程序开发的时候,对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,咱们大概了解到小程序的目录结构,和一些相关的基础知识,后面会在具体的开发工做中继续补充相关的知识。

相关文章
相关标签/搜索