• 微信小程序官方DEMO解读


        我们在开始微信小程序开发的时候,对JS,HTML等前端知识一无所知,完完全全就是门外汉在尝试一个新的方向。

        在下载好开发工具,微信就已经提供了一个DEMO例子:

        

        从程序开发的角度来看这个陌生的目录结构,pages是存放页面的,utils是存放工具类的,而app开头的三个文件既然放在根目录级别,那么按理讲,应该是和配置有关。

        我们看app.js文件的内容:

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

  • 相关阅读:
    在类中声明常量
    PHPStudy配置虚拟主机配置域名步骤
    PHPStudy配置虚拟主机步骤
    2019年7月22日星期一,简单的总结一下
    简单的面向对象
    session和cookie
    Jquery 事件绑定 bind 与on 的区别
    php try catch用法
    include,include_once,require,require_once的区别
    require与 include区别
  • 原文地址:https://www.cnblogs.com/wenjiang/p/6942638.html
Copyright © 2020-2023  润新知