Skip to content

一、页面导航

1.简介

1.1 什么是页面导航?

image-20221002174911310

1.2 小程序中实现页面导航的两种方式

image-20221002174925671

2.声明式导航

2.1 导航到 tabBar 页面

image-20221002174955142

html
<navigator url="/pages/message/message" open-type="switchTab">导航到消息页面</navigator>

2.2 导航到非 tabBar 页面

image-20221002175023052

html
<navigator url="/pages/info/info" open-type="navigate">导航到info页面</navigator>
或者:<navigator url="/pages/info/info">导航到info页面</navigator>

2.3 后退导航

image-20221002175037589

html
<navigator open-type="navigateBack" delta='1' >后退</navigator>
或者:<navigator open-type="navigateBack">后退</navigator>

3.编程式导航

3.1 导航到 tabBar 页面

image-20221002175102574

image-20221002175113594

3.2 导航到非 tabBar 页面

image-20221002175128262

image-20221002175143699

3.3 后退导航

image-20221002175158476

image-20221002175209009

4.导航传参

4.1 声明式导航传参

跳转到非tabBar页面

image-20221002175256318

和a标签传参数值是一样的!

4.2 编程式导航传参

跳转到非tabBar页面

image-20221002175309550

和a标签传参数值是一样的!

4.3 在 onLoad函数 中接收导航参数

image-20221002175324149

二、页面事件

1.下拉刷新事件

1.1 什么是下拉刷新

下拉刷新是移动端的专有名词,指的是通过手指在屏幕上的下拉滑动操作,从而重新加载页面数据的行为。

1.2 启用下拉刷新

image-20221002175531102

1.3 配置下拉刷新窗口的样式

image-20221002175551989

1.4 监听页面的下拉刷新事件

image-20221002175611972

image-20221002175618402

都是写在Page对象里面的

1.5 停止下拉刷新的效果

image-20221002175634575

js
/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
onPullDownRefresh: function () {
    // console.log('触发了message页面的下拉刷新')
    this.setData({
        count: 0
    })
    wx.stopPullDownRefresh()
},

2.上拉触底事件

2.1 什么是上拉触底

上拉触底是移动端的专有名词,通过手指在屏幕上的上拉滑动操作,从而加载更多数据的行为

2.2 监听页面的上拉触底事件

image-20221002175712830

2.3 配置上拉触底距离

image-20221002175724946

3.上拉触底案例

3.1 案例效果展示

image-20221002175814030

3.2 案例的实现步骤

image-20221002175829514

3.3 具体实现

步骤1 - 定义获取随机颜色的方法

image-20221002175846750

步骤2 - 在页面加载时获取初始数据

image-20221002175857831

步骤3 - 渲染 UI 结构并美化页面效果

image-20221002175908232

步骤4 - 上拉触底时获取随机颜色

image-20221002175916872

步骤5 - 添加 loading 提示效果:showLoading函数

image-20221002175928520

步骤6 - 对上拉触底进行节流处理

原因:有可能我们在很短时间内触发很多次触底事件,那这样会不断地请求,并且只会返回最后一次的数据

解决:我们应当进行节流处理,也就是正在进行网络请求时拒绝再次请求

image-20221002175940853
js
// pages/contact/contact.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    colorList: [],
    isloding: false //节流标志变量
  },

  getColors() {
    this.setData({
      isloding: true //正在发起网络请求
    })
    // 需要展示 loading 效果
    wx.showLoading({
      title: '数据加载中...'
    })
    wx.request({
      url: 'https://www.escook.cn/api/color',
      method: 'get',
      success: ({ data: res }) => {
        this.setData({
          colorList: [...this.data.colorList, ...res.data]
        })
      },
      complete: () => {
        wx.hideLoading()
        this.setData({
          isloding: false
        })
      }
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.getColors()
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    if (this.data.isloding) return //如果正在进行网络请求,就直接结束

    this.getColors()
  }
    
})

4.扩展

自定义编译模式:

解释:就是每次编译(重新编译)之后进入的页面,方便我们针对某一个页面进行开发

默认情况下,每次编译都会进入首页

image-20221002180014357

三、生命周期

1.什么是生命周期

image-20221002180100926

2.生命周期的分类

image-20221002180122161

3.什么是生命周期函数

image-20221002180139944

4.生命周期函数的分类

image-20221002180153847

5.应用的生命周期函数

image-20221002180207042

输入App,然后点击那个函数,会自动出现以下内容的生命周期函数:

小程序进入后台:意思就是小程序被放到手机的后台运行了,也就是把页面切走了!

js
//app.js
App({

  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {
    // console.log('onLaunch')
  },

  /**
   * 当小程序启动,或从后台进入前台显示,会触发 onShow
   */
  onShow: function (options) {
    // console.log('onShow')
  },

  /**
   * 当小程序从前台进入后台,会触发 onHide
   */
  onHide: function () {
    // console.log('onHide')
  },

  /**
   * 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
   */
  onError: function (msg) {
    // console.log('onError')
  }
})

模拟切后台:再次点击就会切到前台

image-20221003002025879

6.页面的生命周期函数

image-20221002180222975

输入Page,然后点击那个函数,会自动出现以下内容的生命周期函数:

image-20221003002816670
js
// pages/home/home.js
Page({
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  }
})

用的多的:

  • onLoad:初始化页面的数据、转存页面接收到的参数options

  • onReady:修改页面里面的内容,有一些相关的方法,比如修改页面标题

四、WXS 脚本

1.概述

1.1 什么是 wxs

WXS(WeiXin Script)是小程序独有的一套脚本语言,WXS 结合 WXML,可以构建出页面的结构。

1.2 wxs 的应用场景

wxml 中无法调用在页面的 .js 中定义的函数(只是能用事件绑定而已),但是 wxml 中可以调用 wxs 中定义的函数

因此,小程序中 wxs 的典型应用场景就是“过滤器”

(vue3已经删除过滤器)

1.3 wxs 和 JavaScript 的关系

image-20221002180322646

2.基础语法

2.1 内嵌 wxs 脚本

image-20221002180347558

2.2 定义外联的 wxs 脚本

/utils/tools.wxs

js
function toLower(str) {
  return str.toLowerCase()
}

module.exports = {
  toLower: toLower
}

image-20221002180402152

2.3 使用外联的 wxs 脚本

html
<wxs src="../../utils/tools.wxs" module="tools"></wxs>

image-20221002180415356

3.WXS 的特点

3.1 与 JavaScript 不同

为了降低 wxs(WeiXin Script)的学习成本, wxs 语言在设计时借大量鉴了 JavaScript 的语法。

但是本质上,wxs 和 JavaScript 是完全不同的两种语言!

3.2 不能作为组件的事件回调

里面不可以调用js文件的函数,但是可以调用wxs文件的函数

但是wxs文件的函数不能作为事件函数

utils文件夹里面的wxs文件是给wxml调用的,js文件是给js调用的!

js与wxs彼此都不能进行调用

image-20221002180455595

3.3 隔离性

image-20221002180508332

3.4 性能好

image-20221002180524014

五、案例 - 本地生活(列表页面)

1. 演示页面效果以及主要功能

image-20221002180552246

2.列表页面的 API 接口

image-20221002180609876

3.判断是否还有下一页数据

image-20221002180621481

4.具体实现

home.xwml

html
<!--pages/home/home.wxml-->
<!-- 轮播图区域 -->
<swiper indicator-dots circular>
  <swiper-item wx:for="{{swiperList}}" wx:key="id">
    <image src="{{item.image}}"></image>
  </swiper-item>
</swiper>

<!-- 九宫格区域 -->
<view class="grid-list">
  <navigator class="grid-item" wx:for="{{gridList}}" wx:key="id" url="/pages/shoplist/shoplist?id={{item.id}}&title={{item.name}}">
    <image src="{{item.icon}}"></image>
    <text>{{item.name}}</text>
  </navigator>
</view>

<!-- 图片区域 -->
<view class="img-box">
  <image src="/images/link-01.png" mode="widthFix"></image>
  <image src="/images/link-02.png" mode="widthFix"></image>
</view>

home.js

js
// pages/home/home.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 存放轮播图数据的列表
    swiperList: [],
    // 存放九宫格数据的列表
    gridList: []
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.getSwiperList()
    this.getGridList()
  },

  // 获取轮播图数据的方法
  getSwiperList() {
    wx.request({
      url: 'https://www.escook.cn/slides',
      method: 'GET',
      success: (res) => {
        this.setData({
          swiperList: res.data
        })
      }
    })
  },

  // 获取九宫格数据的方法
  getGridList() {
    wx.request({
      url: 'https://www.escook.cn/categories',
      method: 'GET',
      success: (res) => {
        this.setData({
          gridList: res.data
        })
      }
    })
  }
})

shoplist.wxml

html
<!--pages/shoplist/shoplist.wxml-->

<view class="shop-item" wx:for="{{shopList}}" wx:key="id">
  <view class="thumb">
    <image src="{{item.images[0]}}"></image>
  </view>
  <view class="info">
    <text class="shop-title">{{item.name}}</text>
    <text>电话:{{tools.splitPhone(item.phone)}}</text>
    <text>地址:{{item.address}}</text>
    <text>营业时间:{{item.businessHours}}</text>
  </view>
</view>

<wxs src="../../utils/tools.wxs" module="tools"></wxs>

shoplist.js

js
// pages/shoplist/shoplist.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    query: {}, //传入的参数:要查询的条件(要显示什么板块的内容)
    shopList: [],
    page: 1,
    pageSize: 10,
    total: 0,
    isloading: false
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      query: options //存储传入的参数
    })
    this.getShopList()
  },

  // 以分页的形式获取商铺列表数据的方法
  getShopList(cb) {
    this.setData({
      isloading: true
    })
    // 展示 loading 效果
    wx.showLoading({
      title: '数据加载中...'
    })

    wx.request({
      //取值:直接this.data.属性即可,因为this代表Page对象
      url: `https://www.escook.cn/categories/${this.data.query.id}/shops`,
      method: 'GET',
      data: { //发送到服务器的数据
        _page: this.data.page, //第几页
        _limit: this.data.pageSize //显示的条数:即pageSize
      },
      success: (res) => {
        this.setData({
          shopList: [...this.data.shopList, ...res.data], //拼接数据
          total: res.header['X-Total-Count'] - 0 //返回的数据里面有一个header对象,里面的X-Total-Count属性就是数据的实际总数,-0是为了把字符串转换为数字
        })
      },
      complete: () => {
        wx.hideLoading() // 隐藏 loading 效果
        this.setData({ isloading: false })
        // wx.stopPullDownRefresh() //注:不应当直接写在这里,而是应该在需要的时候传进来,因为不是所有的获取数据的时候都需要停止下拉刷新
        // 下面就是调用这个函数:wx.stopPullDownRefresh(),停止下拉刷新的效果
        cb && cb() //短路运算:有没有传入cb,如果传了就进行调用
      }
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    wx.setNavigationBarTitle({
      title: this.data.query.title //动态显示标题
    })
  },

  /**
   * 页面相关事件处理函数--监听用户下拉刷新动作
   */
  onPullDownRefresh: function () {
    // 需要重置数据
    this.setData({
      page: 1,
      shopList: [],
      total: 0
      //pageSize不用重置,因为是固定的
    })
    // 重新发起数据请求
    this.getShopList(() => {
      wx.stopPullDownRefresh() //传入回调函数作为参数:停止下拉刷新的效果
    })
  },

  /**
   * 页面上拉触底事件处理函数--监听用户上拉触底动作
   */
  onReachBottom: function () {
    //当没有数据时就不应该发起额外的请求!
    if (this.data.page * this.data.pageSize >= this.data.total) { // 证明没有下一页的数据了
      return wx.showToast({ //显示消息提示框的api
        title: '数据加载完毕!', //必须配置
        icon: 'none' //默认是success图标,如果不希望展示就写为none
      })
    }
    // 判断是否正在加载其他数据
    if (this.data.isloading) return
    // 如果可以进行加载,那么页码值 +1
    this.setData({
      page: this.data.page + 1
    })

    // 获取下一页数据
    this.getShopList()
  }
    
})

shoplist.wxss

css
/* pages/shoplist/shoplist.wxss */
.shop-item {
  display: flex;
  padding: 15rpx;
  border: 1rpx solid #efefef;
  border-radius: 8rpx;
  margin: 15rpx;
  box-shadow: 1rpx 1rpx 15rpx #ddd;
}

.thumb image {
  width: 250rpx;
  height: 250rpx;
  display: block;
  margin-right: 15rpx;
}

.info {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  font-size: 24rpx;
}

.shop-title {
  font-weight: bold;
}

tools.wxs

过滤器处理手机号:改为xxx-xxxx-xxxx的格式

js
function splitPhone(str) {
  if(str.length !== 11) return str

  var arr = str.split('') //按空字符分隔,即把手机号分成11个元素,放入一个数组

  arr.splice(3, 0, '-') //在索引为3的位置,不删除元素(删除0个),插入一个-
  arr.splice(8, 0, '-')

  return arr.join('') //将数组元素合并,变成一个字符串
}

module.exports = {
  splitPhone: splitPhone
}

总结:

image-20221002180631407