logo头像

Renbo’s Blog

小程序入门学习笔记

张小龙说过,小程序是一个“为连接线上线下”而生的产品,尤其是有微信支付的加持,微信小程序在线上线下一体方面能力很强,且能构建核心支付交易闭环,这对很多商家有吸引力,目前打开小程序的方式即有:好友分享、扫二维码、用户手动查找、附近的店、微信群分享、以及与公众号的关联等等,能提供大量入口资源。

程序结构

  • 理解微信小程序的架构

    三个主要文件格式

    • .js后缀的是 脚本文件
    • .json后缀的文件是 配置文件
    • .wxss后缀的是 样式表文件
  • 小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。

    一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:

    • app.js 小程序的脚本代码,可以监听并处理小程序的生命周期函数、声明全局变量。 (必填)
    • app.json 是对整个小程序的全局配置 (必填)
    • app.wxss 是整个小程序的公共样式表 (必填)

    一个小程序页面由四个文件组成,分别是:

    • page_name.js 页面逻辑 (必填)
    • page_name.wxml 页面结构 (必填)
    • page_name.wxss 页面样式表 (选填)
    • page_name.json 页面配置 (选填)
  • 项目结构

    • |— empty-folder/ ·························· 项目所在目录
      |— pages/ ······································ 页面目录
      │ |— index/ ··································· index页面
      │ | |— index.js ····························· index页面逻辑(脚本文件)

      | | |—index.json ·························· index页面配置

      │ | |— index.wxml ······················· index页面结构
      │ | |─ index.wxss ························ index页面样式
      │ |─ logs/ ······································· logs页面
      │ |— logs.js ···································· logs页面逻辑
      │ |— logs.wxml ····························· logs页面结构
      │ |— logs.wxss ······························ logs页面样式
      |— utils/ ·········································· 公共脚本目录
      │ |— util.js ····································· 工具脚本
      |— app.js ········································ 应用程序逻辑

      |— app.json ··································· 应用程序配置
      |— app.wxss ·································· 应用程序公共样式

    • 文件说明:

      • app.js 用于定义整个应用的逻辑

        1. app函数是一个全局函数
        2. app函数作用就是用来创建一个应用程序实例
        3. 每个应用程序都会有他的生命周期
      • app.json 全局配置文件,页面的基本配置信息

      • app.wxss css代码,用来设置整个应用的样式

      • index页面:欢迎页

      • logs 页面:小程序启动日志的展示页

    • 页面结构

      • 每个页面组件也分为四个文件组成:
        1. page_name.js 文件:定义页面的逻辑,用于创建页面对象,以及处理页面生命周期控制和数据处理。
        2. page_name.json 文件:页面配置文件 设置当前页面工作时的window的配置,此处会覆盖app.json中的window设置,也就是说只可以设置window中设置的属性。
        3. page_name.wxml 文件:wxml指的是Wei Xin Markup Language。页面结构文件,用于定义页面中元素结构的,语法遵循XML语法,注意是XML语法,不是HTML语法。
        4. page_name.wxss 文件:wxml指的是Wei Xin Style Sheet。样式文件。用于定义页面样式的,语法遵循CSS语法,扩展了CSS基本用法和长度单位(主要就是rpx响应式像素)。
      • 每个文件夹内的文件名次统一,只有后缀名不同,因为json配置文件中最终会将所有的页面整合成一个页面。
      • 页面基本结构,几乎每个小程序都是这个结构:
        1. nav bar
        2. body
        3. tab bar

项目配置

  • 小程序中的配置文件分为两种:
    1. 全局配置文件,根目录下的 app.json
    2. 页面配置文件,每个页面目录下的 page_name.json

app.json文件(全局配置)

// 提示:这里要是严格的JSON格式,不能写注释,否则编译报错!
{
  // 设置小程序页面文件的路径,指定小程序由哪些页面组成(必填)
  // 格式:路径+文件名;
  // 数组的第一项代表小程序的初始页面。小程序中新增/减少页面,都需要对 pages 数组进行修改。
  // 文件名不需要写文件后缀,因为框架会自动去寻找路径.json,.js,.wxml,.wxss的四个文件进行整合。
  "pages": [
    "pages/index/index",
    "pages/logs/index"
  ],
  // 设置页面的窗口表现,如:状态栏、导航条、标题、窗口背景色等(选填)
  "window": {
    "navigationBarBackgroundColor": "#000000",    // 导航栏背景颜色
    "navigationBarTextStyle": "white",            // 导航栏标题颜色,仅支持 black/white
    "navigationBarTitleText": "微信接口功能演示",  // 导航栏标题文字内容
    "backgroundColor": "#ffffff",   // 窗口的背景色
    "backgroundTextStyle": "dark"   // 下拉背景字体、loading 图的样式,仅支持 dark/light
    "enablePullDownRefresh": false  // 是否开启下拉刷新
  },
  // 设置底部tabBar的表现(选填)
  "tabBar": {
    "backgroundColor": "#ffffff"         // tab 的背景色
    "color": "#eeeeee"                   // tab 上的文字默认颜色
    "selectedColor": "#349dda"           // tab 上的文字选中时的颜色
    "borderStyle": "black"               // tabbar上边框的颜色, 仅支持 black/white
    "list": [{                           // tab 的列表,2~5个tab
      "pagePath": "pages/index/index",   // 页面路径,必须在 pages 中先定义
      "text": "首页"                     // tab 上按钮文字
      "iconPath": "aa/a.png"             // 图片路径,icon 大小限制为40kb
      "selectedIconPath": "aa/b.png"     // 选中时的图片路径,icon 大小限制为40kb
    }, {
      "pagePath": "pages/logs/logs",
      "text": "日志"
    }]
    "position": "bottom"                 // 设置tabbar的位置:可选值 bottom、top
  },
  // 设置网络超时时间(选填),默认时间都为:60000毫秒
  "networkTimeout": {
    "request": 10000,
    "connectSocket": 10000,
    "uploadFile": 10000,
    "downloadFile": 10000
  },
  // 设置是否开启debug模式,即是否在控制台输出调试信息(选填)
  "debug": true
}

page_name.json文件(页面配置文件)

说明:每一个小程序页面也可以使用.json文件来对本页面的窗口表现进行配置。 页面的配置比app.json全局配置简单得多,只是设置 app.json 中的 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项。页面的.json只能设置 window 相关的配置项,以决定本页面的窗口表现,所以无需写 window 这个键,如:
{
  "navigationBarBackgroundColor": "#000000",    // 导航栏背景颜色
  "navigationBarTextStyle": "white",            // 导航栏标题颜色,仅支持 black/white
  "navigationBarTitleText": "微信接口功能演示",  // 导航栏标题文字内容
  "backgroundColor": "#eeeeee",       // 窗口的背景色 
  "backgroundTextStyle": "dark"       // 下拉背景字体、loading 图的样式,仅支持 dark/light
  "enablePullDownRefresh": false      // 是否开启下拉刷新
  "disableScroll": false              // 设置为 true 则页面整体不能上下滚动;只在 page.json 中有效,无法在 app.json 中设置该项
}

逻辑层(App Service)

  • 小程序开发框架的逻辑层是由JavaScript编写。
  • 逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。
    • 增加 AppPage 方法,进行程序和页面的注册。
    • 增加 getApp 和 getCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
    • 提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
    • 每个页面有独立的作用域,并提供模块化能力。
    • 由于框架并非运行在浏览器中,所以 JavaScript 在 web 中一些能力都无法使用,如 document,window 等。
    • 开发者写的所有代码最终将会打包成一份 JavaScript,并在小程序启动的时候运行,直到小程序销毁。类似 ServiceWorker,所以逻辑层也称之为 App Service。

1. 注册程序 —》 app.js文件

// app.js
// App(object) 函数用来注册一个小程序。接受一个 object 参数。
// object参数内可以包含多个函数(生命周期函数或自定义函数)。
App({
  // 1. 监听小程序初始化:当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
  onLaunch: function() { 
    // Do something initial when launch.
  },
  // 2. 监听小程序显示:当小程序启动,或从后台进入前台显示,会触发 onShow
  onShow: function() {
      // Do something when show.
  },
  // 3. 监听小程序隐藏:当小程序从前台进入后台,会触发 onHide
  onHide: function() {
      // Do something when hide.
  },
  // 4. 错误监听函数
  onError: function(msg) {
    console.log(msg)
  },
  // 自定义函数(用 this 可以访问)
  myFun: function(msg) {

  },
  globalData: 'I am global data'
})
// 在APP()函数内可以设置全局函数和全局数据。
// 在app.js文件内部是通过this获取当前小程序的实例,在该文件外部是通过getApp()函数获取。

补充:

// other.js
// 在APP()函数内部,直接用this就可以获取到小程序实例。
// 在APP()函数外部,我们提供了全局的 getApp() 函数,可以获取到小程序实例。
var appInstance = getApp()
console.log(appInstance.globalData) // I am global data

2. 注册页面 —》 page_name.js文件

  • 说明:Page() 函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。
// index.js
Page({
  data: {                             // 页面的初始数据
    text: 'init data',
    array: [{msg: '1'}, {msg: '2'}],
    object: {
      text: 'init data'
    }
  },
  onLoad: function(options) {         // 生命周期函数--监听页面加载
    // 一个页面只会调用一次。
    // 接收页面参数可以获取wx.navigateTo和wx.redirectTo及<navigator/>中的 query。
    // Do some initialize when page load.
  },
  onReady: function() {               // 生命周期函数--监听页面初次渲染完成
    // 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
    // 对界面的设置如wx.setNavigationBarTitle请在onReady之后设置。
    // Do something when page ready.
  },
  onShow: function() {                // 生命周期函数--监听页面显示
    // 每次打开页面都会调用一次。
    // Do something when page show.
  },
  onHide: function() {                // 生命周期函数--监听页面隐藏
    // 当navigateTo或底部tab切换时调用。
    // Do something when page hide.
  },
  onUnload: function() {              // 生命周期函数--监听页面卸载
    // 当redirectTo或navigateBack的时候调用。
    // Do something when page close.
  },
  onPullDownRefresh: function() {     // 页面相关事件处理函数--监听用户下拉动作
    // 监听用户下拉刷新事件。
    // 需要在config的window选项中开启enablePullDownRefresh。
    // 当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
    // Do something when pull down.
  },
  onReachBottom: function() {         // 页面相关事件处理函数--页面上拉触底事件的处理函数
    // Do something when page reach bottom.
  },
  onShareAppMessage: function () {    // 页面相关事件处理函数--用户点击右上角分享
   // 只有定义了此事件处理函数,右上角菜单才会显示“分享”按钮
   // 用户点击分享按钮的时候会调用
   // 此事件需要 return 一个 Object,用于自定义分享内容
    return {
      title: '自定义分享标题',   // 当前小程序名称
      desc: '自定义分享描述',
      path: '/page/user?id=123' // 分享路径,当前页面 path ,必须是以 / 开头的完整路径
    }
   // return custom share data when user share.
  },

  // Event handler.
  viewTap: function() {     // 事件处理函数
    console.log('view tap')
    // setData 函数用于将数据从逻辑层发送到视图层,同时改变对应的 this.data 的值。
    this.setData({
      text: 'Set some data for updating view.'
    })
  },
  customData: {
    hi: 'MINA'
  }
})

事件处理函数

  • 除了初始化数据和生命周期函数,Page 中还可以定义一些特殊的函数:事件处理函数。在渲染层可以在组件中加入事件绑定,当达到触发事件时,就会执行 Page 中定义的事件处理函数。
  • 示例代码:
<!--index.wxml  视图层 -->
<view bindtap="viewTap"> 刷新 </view>
// index.js  逻辑层
Page({
  viewTap: function() {
    console.log(' 刷新 视图被点击了')
  }
})

setData() 函数

setData() 函数用于将数据从逻辑层发送到视图层,同时改变对应的this.data的值。

注意:

  • 直接修改 this.data 无效,无法改变页面的状态,还会造成数据不一致。

  • 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。

  • 示例代码:

    <!--index.wxml-->
    <view>{{text}}</view>
    <button bindtap="changeText"> Change normal data </button>
    <view>{{array[0].text}}</view>
    <button bindtap="changeItemInArray"> Change Array data </button>
    <view>{{object.text}}</view>
    <button bindtap="changeItemInObject"> Change Object data </button>
    <view>{{newField.text}}</view>
    <button bindtap="addNewField"> Add new data </button>
    
    //index.js
    Page({
      data: {
        text: 'init data',
        array: [{text: 'init data'}],
        object: {
          text: 'init data'
        }
      },
      changeText: function() {
        // this.data.text = 'changed data'  // bad, it can not work
        this.setData({
          text: 'changed data'
        })
      },
      changeItemInArray: function() {
        // you can use this way to modify a danamic data path
        this.setData({
          'array[0].text':'changed data'
        })
      },
      changeItemInObject: function(){
        this.setData({
          'object.text': 'changed data'
        });
      },
      addNewField: function() {
        this.setData({
          'newField.text': 'new data'
        })
      }
    })
    

getCurrentPages()

  • getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
页面跳转 跳转方法
打开新页面 调用 API wx.navigateTo 或使用组件 <navigator open-type="navigate"/>
页面重定向 调用 API wx.redirectTo 或使用组件 <navigator open-type="redirect"/>
页面返回 调用 API wx.navigateBack 或用户按左上角返回按钮
Tab 切换 调用 API wx.switchTab 或使用组件<navigator open-type="switchTab"/> 或用户切换 Tab

3. 文件作用域

  • 在javaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
  • 通过全局函数 getApp()可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置。

4. 模块化

  • 我们可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports(推荐) 或者 exports 才能对外暴露接口。

  • 示例代码:

    // common.js
    function sayHello(name) {
      console.log(`Hello ${name} !`)
    }
    function sayGoodbye(name) {
      console.log(`Goodbye ${name} !`)
    }
    
    module.exports.sayHello = sayHello
    exports.sayGoodbye = sayGoodbye
    
    // page_name.js
    // 在需要使用这些模块的文件中,使用 require(path) 将公共代码引入
    var common = require('common.js')
    Page({
      helloMINA: function() {
        common.sayHello('MINA')
      },
      goodbyeMINA: function() {
        common.sayGoodbye('MINA')
      }
    })
    

    WXML常用的标签:

    <view>  类似于 <div>
    <text> 类似于 <font><span>
    <image> 类似于 <img>
    <navigator> 类似于 <a>
    

小程序的内容通常不能大于2MB!

css3为了区分伪类和伪元素,伪元素采用双冒号写法。

常见伪类— :hover, :link, :active, :target, :not(), :focus。
常见伪元素— ::first-letter, ::first-line, ::before, ::after, ::selection。

::before和::after下特有的content,用于在css渲染中向元素逻辑上的头部或尾部添加内容。

这些添加不会出现在DOM中,不会改变文档内容,不可复制,仅仅是在css渲染层加入。

所以不要用:before或:after展示有实际意义的内容,尽量使用它们显示修饰性内容,例如图标。

举例:网站有些联系电话,希望在它们前加一个icon☎,就可以使用:before伪元素,如下: