小程序学习笔记

一、全局框架

小程序的主体由三个文件组成:app.jsapp.jsonapp.wxss
小程序学习笔记_第1张图片
小程序主体.png
一个小程序的页面由四个文件组成:.js.json.wxss.wxml
小程序学习笔记_第2张图片
小程序的某个页面.png
  1. app.json 是当前小程序的全局配置,定义了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等,JSON 文件中无法使用注释,加注释会报错。

  2. app.js中会产生一个App实例,用于监听小程序的生命周期、错误监听、页面不存在监听,整个小程序只有这一个App实例,全部页面共享,可以通过getApp()方法获取此全局唯一的App实例。(可以在此实例上保存共用的数据,以便各个界面共用)

// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData)
  1. app.wxss,用来描述WXML的组件样式,具有CSS的大部分特性。

  2. project.config.json是项目配置文件,可以定义小程序和云开发的目录位置,可以配置个性化选项等等。

二、小程序的渲染层和逻辑层

小程序的运行环境分成渲染层逻辑层,其中 WXML 模板WXSS 样式工作在渲染层JS 脚本工作在逻辑层

小程序的渲染层和逻辑层分别由2个线程管理:

  • 渲染层的界面使用了WebView 进行渲染,一个小程序存在多个界面,所以渲染层存在多个WebView线程。

  • 逻辑层采用JsCore线程运行JS脚本。

  • 这两个线程的通信会经由微信客户端做中转,逻辑层发送网络请求也经由微信客户端转发,小程序的通信模型下图所示。


    小程序学习笔记_第3张图片
    小程序通信模型

三、 程序与页面

微信打开小程序流程:

  • 首先微信在打开小程序之前,会把小程序的代码包下载到本地。

  • 然后通过 app.json 的 pages 字段就可以知道你当前小程序的所有页面路径,pages字段的第一个就是小程序的首页。

  • 微信吧首页的代码装载进来,通过底层机制,渲染出来首页。

小程序启动流程:

  • 小程序启动之后,在 app.js 定义的 App 实例的 onLaunch 回调会被执行。(整个小程序只有这一个实例,全部页面共享。)

  • 微信会先根据首页的.json文件生成一个界面。(.json文件定义了导航栏的颜色和文字等信息)

  • 然后装载首页的.wxss.wxml文件。

  • 最后装载首页的.js文件,.js文件有一个Page实例,小程序会根据Page实例中的data数据和首页的.wxml文件,一起渲染出最终的结构,这就是你看到的小程序首页的样子。(渲染完成后,Page实例会受到一个onLoad回调)

四、小程序运行机制

五、小程序更新机制

六、事件系统

七、自定义组件

自定义组件
  1. 已自定义一个上拉加载组件为例,下图是一个自定义的上拉加载组件:


    小程序学习笔记_第4张图片
    上拉加载组件.png
  2. 组件由四个文件组成:json、wxml、wxss、js,要写自定义组件,需要在json文件中进行自定义组件声明

{
  "component": true
}
  1. 在自定义组件的 js 文件中,需要使用 Component 来注册组件,并提供组件的属性定义、内部数据和自定义方法。
// components/load-more/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
      hasMore: {
        type: Boolean,
        value: false
      },
      // 加载中的显示文本
      loadingText: {
        type: String,
        value: '加载中...'
      },
      // 加载失败的显示文本
      failText: {
        type: String,
        value: '加载失败, 请点击重试!'
      },
      // 没有更多后的显示文本, 默认没有则隐藏加载更多控件
      finishText: {
        type: String,
        value: ''
      },
      // 列表渲染延时, 默认为 500 ms, 我在开发工具中测试列表渲染速度时快时慢, 可根据实际使用中界面复杂度自行调整
      // ps 如果能监听setData() 渲染结束的话则可以不需要延时 
      listRenderingDelay: {
        type: Number,
        value: 500
      }
  },

  /**
   * 组件的初始数据
   */
  data: {
    showThis: false,
    text: '',
    showIcon: false,
    isLoading: false
  },

  /**
   * 组件的方法列表
   */
  methods: {

    //加载更多的入口方法, 直接在page中使用时请在onReachBottom() 方法中调用这个方法, 并实现loadMoreListener方法去获取数据
    loadMore: function() {
      if(!this.properties.hasMore){
        console.log('load more finish')
        return
      }
      if(this.data.isLoading) {
        console.log('loading ...')
        return
      }
      this.setData({
        isLoading: true
      })
      this.triggerEvent('loadMoreListener')
    },
    //加载完成, 传入hasMore 
    loadMoreComplete: function(data) {
        var hasMore = data.curPage < data.pageCount && data.pageCount != 1
        var text = '', showThis = false, showIcon = false

        if (hasMore) {
          showIcon = true
          showThis = true
          text = this.properties.loadingText
        } else if (this.properties.finishText.length>0) {
          text = this.properties.finishText
          showThis = true
        }
        this.setData({
          hasMore: hasMore,
          text: text,
          showIcon: showIcon,
          showThis: showThis
        })
        //界面渲染延迟, 避免列表还未渲染完成就再次触发 loadMore 方法
        setTimeout(function(){
          this.setData({
            isLoading: false
          })
        }.bind(this), this.properties.listRenderingDelay)
    },
    // 加载失败
    loadMoreFail: function() {
      this.setData({
        showIcon: false,
        text: this.properties.failText
      })

      //界面渲染延迟, 避免列表还未渲染完成就再次触发 loadMore 方法
      setTimeout(function(){
        this.setData({
          isLoading: false
        })
      }.bind(this), this.properties.listRenderingDelay)
    },
    //点击 loadmore 控件时触发, 只有加载失败时才会进入页面回调方法
    clickLoadMore: function() {
      if(this.data.text != this.properties.failText) return
      this.setData({
        showIcon: true,
        text: this.properties.loadingText,
        isLoading: true
      })
      this.triggerEvent('clickLoadMore')
    }
  }
})

  1. 剩下的就跟下普通的页面一样了,在wxml中编写组件模板,在wxss中编写样式。

注意:在组件wxss中不能使用ID选择器、属性选择器和标签名选择器。

使用自定义组件
  1. 将组件文件夹复制到自己的小程序中

  2. 在需要用到此组件的页面A的json文件中进行声明,提供此组件的标签名和文件路径:

{
  "usingComponents": {
    "load-more":"../../components/load-more/index"
  }
}
  1. 把此组件放到页面A的wxml文件的合适的位置

  1. 在页面A的js文件中,初始化此组件
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
   //loadMoreView是在Page之外的定义的变量(var loadMoreView)
   //拿到loadMoreView后就可以调用此组件里的方法
    loadMoreView = this.selectComponent("#loadMoreView")
  },
  1. 在页面A的js文件中,在触底事件中调用组件的loadMore方法
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    if (this.data.isLoading == false) {
      this.setData({
        currentPage: this.data.currentPage + 1
      })
      loadMoreView.loadMore()
    }
  },
  1. 在页面A的js文件中,实现两个回调:
//触底事件时,调用了loadMore函数,loadMore函数会调用loadMoreListener函数
loadMoreListener: function (e) {
    this.requestListData(this.data.currentPage)
},
//当加载失败时,会出现加载更多视图,
//点击加载更多视图,会调用此函数
clickLoadMore: function (e) {
    this.requestListData(this.data.currentPage)
},
  1. 每个自定义组件的使用方法都不相同,可以先看作者提供的使用方法和源码,根据自己的实际情况使用或者微调。

八、插件

九、 需要注意的地方

1. wx:key,wx:key值是否唯一,会控制组件是否重新创建

  • 当wx:key=""是唯一的值时,数据改变触发渲染层重新渲染时,会校正key唯一的组件,保持他们的状态,提高渲染效率,而不会重新创建。

  • 当wx:key没有设置或者不唯一时,数据改变触发渲染时,会重新创建组件,会丢失原先的状态。(如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

设置wx:key唯一,有两种方式:

  • wx:key可以是数组的item的某个属性,需要确保此属性是唯一的字符串或者数字,并且不能动态改变。

  • wx:key可以是保留关键字*this,代表在for循环中的item本身,这种表示需要item是一个唯一的字符串或者数字。

2. 下拉刷新

  • 通过.json中的enablePullDownRefresh为true来开启用户手动刷新

  • 通过API的wx.startPullDownRefresh()可以自动触发下拉刷新

  • 通过API的wx.stopPullDownRefresh()来停止下拉刷新

  • 通过app.jsonwindowbackgroundTextStyle来控制样式,dark和light两种可以选择。

  • 通过.js中的onPullDownRefresh()方法,来监控下拉刷新操作

**3. **

十、微信小程序开发者文档,遇到问题及时查询官方文档和官方Demo

  • 小程序开发者文档
  • 小程序官方Demo

你可能感兴趣的:(小程序学习笔记)