小程序 --- 事件、数据处理、声明周期、常用 API

1. 事件

小程序中不能通过 on 来绑定事件,需要使用 bind 方法来绑定事件,并且没有click事件,需要使用 tap 事件来代替

1. 事件绑定

**方式一: **

<view bind:tap="fnName"></view>

**方式二: **

<view bindtap="fnName"></view>

2. 函数处理

page/cate/cate.js

Page({
  // 所有的函数都需要写在 Page方法 中
  tapName(event){
    console.log(event);
  }
})

3. 事件类型

1. 点击(tap)

2. 输入(input)

4. 事件对象

1. 获取用户输入的值

Page({
  tapName(event){
    // 获取输入框的值
    console.log(event.detail.value);
  }
})

5. 阻止事件冒泡

将绑定事件的方式由 bind 改为 catch

<button type="warn" catchtap="tapName">绑定事件</button>

6. 事件传参

1. data-* 传参

通过 data-* 的方式来定义需要传递的数据

<!-- 多个参数,使用多个 data-* -->
<view data-id="1" data-name="tom" bindtap="handle">点击</view>

获取自定义数据

Page({
  handle(event){
    // currentTarget: 事件绑定者,也就是指: 哪个组件绑定了当前事件处理函数
    console.log("事件绑定者: ",event.currentTarget.dataset.id);
    // target: 事件触发者,也就是指: 哪个组件触发了当前事件处理函数
    // 如果事件被冒泡过,则会有所不同
    console.log("事件触发者: ",event.target.dataset.id);
  }
})

**注意: **

  1. 如果自定义属性使用的是全小写字母写法(data-parentid),event取值时同样用全小写字母取值(parentid)
  2. 如果自定义属性是多个单词组成的,则单词与单词之间使用 中划线(-) 进行连接(data-parent-id),event取值时,需要使用小驼峰取值(parentId)
  3. 如果自定义属性是使用小驼峰写法(data-parentId),event取值时,需要使用全小写字母(parentid)

2. mark 标记传参

mark 是一种自定义属性,可以在组件上添加,用于识别具体触发事件的 target 节点,同时 mark 还可以用于承载一些自定义数据

<button type="primary" bindtap="markHandle" mark:id="2" mark:name="jany">mark 传参</button>

获取自定义数据

Page({
  markHandle(event){
    // 如果通过事件冒泡触发的事件,则会获取到所有节点绑定的自定义数据
    console.log(event.mark.id);
  }
})

2. 数据

1. 数据绑定

1. 单向数据绑定

数据能影响页面,页面不会影响数据,小程序页面中使用的数据,需要在 js 文件中的 Page() 方法中,使用 data属性来定义,在 wxml 页面中使用 Mustache 语法 -- 爽大括号{{ }} 来取值

数据声明

pages/index/index.js

Page({
  // 小程序页面中使用的数据,都在这里定义
  data:{
    id: 1,
    name:"小明",
    school:{
      name: "新华中学"
    },
    isChecked: true
  }
})

数据使用

pages/index/index.wxml

{{name}}
{{school.name}}

<!-- 如果需要动态绑定一个变量,属性值也需要使用双大括号 -->
<view id="{{ id }}"></view>

<!-- 通过 isChecked 来控制 checkbox 是否被选中,需要加大括号 -->
<view>
  <checkbox checked="{{ isChecked }}" /> 抽烟
</view>


<!-- 算数运算 -->
<view>{{ id + 1 }}</view>

<!-- 三元运算 -->
<view>{{ id === 1 ? "等于" : "不等于" }}</view>

<!-- 逻辑判断 -->
<view>{{ id > 1 }}</view>

<!-- 只能写表达式,不能写语句,也不能调用 js 的方法 -->

2. 双向数据绑定

在 WXML 中,普通属性的绑定是单向的,当输入框中的值发生改变时,并不会影响 data 中的 address 的值

pages/index/index.html

<view>
  <label for="address">地址: </label>
  <input type="text" id="address" value="{{ address }}"/>
</view>

page/index/index.js

Page({
  data: {
    address: "北京市"
  },
  
})

如果想要实现双向数据绑定,只需要在属性前加上model: 即可使这个属性变为双向数据绑定

<view>
  <label for="address">地址: </label>
  <!-- value 属性前添加 model: 来实现双向数据绑定 -->
  <input type="text" id="address" model:value="{{ address }}"/>
</view>

2. 基础数据类型操作

小程序中修改数据不推荐通过赋值来进行修改,通过赋值的方式修改数据无法改变页面的数据

而是要通过 setData() 方法来修改,更新数据,并驱动视图页面的数据更新

1. 赋值方式

Page({
  data: {
    num: 1
  },
  changeNum(){
    // 赋值方式修改数据,真实数据已经更新了,但是页面数据依然未被重新加载
    this.data.num += 1
    console.log(this.data.num);  
  }
})

2. setData() 方法

Page({
  data: {
    num: 1
  },
  changeNum(){
    this.setData({
      // setData() 方法接收一个对象,key为需要修改数据的变量名,值为需要数据做的操作
      num: this.data.num + 1
    })
  }
})

3. 对象操作

1. 新增属性

Page({
  data: {
    userInfo:{}
  },
  changeObj(){
    // 使用 setData() 方法给对象添加属性
    this.setData({
      // 字符串形式的 数据路径: obj.b.c
      'userInfo.id': 1,
      'userInfo.name': 'Tom'
    })
  }
})

2. 修改属性

Page({
  data: {
    userInfo:{
      id: 1,
      name: 'Tom'
    }
  },
  changeObj(){
    // 使用 setData() 方法修改对象的属性
    this.setData({
      // 字符串形式的 数据路径: obj.b.c
      'userInfo.id': 2,
      'userInfo.name': 'Jany'
    })
  }
})

3. 快速修改多个属性

1. 使用展开运算符

Page({
  data: {
    userInfo:{
      id: 1,
      name: 'Tom'
    }
  },
  changeObj(){
    // 1. 使用展开运算符,复制原对象中的所以属性,后面定义的属性会自动覆盖原对象中的同名属性
    const userInfo = {
      ...this.data.userInfo,
      id:2,
      name: 'Jany'
    }

    // 2. 调用 setData() 方法,修改对象属性
    this.setData({
      userInfo: userInfo
    })
  }
})

2. 使用 Oject.assgin() 方法

Page({
  data: {
    userInfo:{
      id: 1,
      name: 'Tom'
    }
  },
  changeObj(){  
    // 1. 调用 Object.assgin() 方法,合并两个对象,将需要修改的属性,覆盖原对象中的同名属性
    const newObj = Object.assign(this.data.userInfo,{
      id:2,
      name: 'Jany'
    })

    // 2. 调用 setData() 方法,将新对象更新原对象
    this.setData({
      userInfo: newObj
    })
  }
})

4. 删除属性

删除单个属性

Page({
  data: {
    userInfo:{
      id: 1,
      name: 'Tom'
    }
  },
  changeObj(){ 
    // 1. 删除对象中的 name属性
    delete this.data.userInfo.name

    // 2. 更新对象
    this.setData({
      userInfo: this.data.userInfo
    })
  }
})

删除多个属性

Page({
  data: {
    userInfo:{
      id: 1,
      name: 'Tom',
      age:18
    }
  },
  changeObj(){ 
    // 1. 使用对象结构的方式,将想保留的属性解构到 ...res 中
    const {id,name,...res} = this.data.userInfo

    // 2. 更新对象
    this.setData({
      userInfo: res
    })
  }
})

5. 循环

1. 基本使用

pages/index/index.wxml

<!-- 固定的两个变量名,item和index, 循环对象时,index 是对象的 key,item 是对象的值,wx:key="" 不需要加 双大括号-->
<view wx:for="{{ people }}" wx:key="index">
  <text>{{ item }} -- {{ index }}</text>
</view>

pages/index/index.js

Page({
  data: {
    people: {
      id: 1,
      name: "小明",
      age: 18,
    }
  }
})

**2. 如果需要对默认的变量名和索引进行修改,可以使用 wx:for-item 和 wx:for-index **

<!-- 将对象的属性变量名改为key,值变量名改为value -->
<view wx:for="{{ people }}" wx:key="index" wx:for-item="value" wx:for-index="key">
  <text>{{ key }} --- {{ value }}</text>  >
</view>

3. 将 wx:for 用在 <block/> 标签上,以渲染一个包含多节点的结构块. <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染生成标签, 只接受控制属性, <block/>标签在 wxml 中可以用于组织代码结构,支持列表渲染、条件渲染等

<block wx:for="{{ people }}" wx:key="id" wx:for-item="obj" wx:for-index="i">
  <view>名字: {{ obj.name }}</view>
  <view>年龄: {{ obj.age }}</view>
</block>

4. 数组操作

1. 新增元素

push() 方法新增,能更新数据,无法更新页面中的显示

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // push() 方法可以更新数据,但是不会更新页面中的显示
    this.data.list.push(4)
  }
})

1. 使用 数组的 push() 方法,并调用 setData() 方法,更新数据

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // 1. 调用 push() 方法,将新元素新增到数组中
    this.data.list.push(4)
      
    // 2. 调用 setData(),更新数据
    this.setData({
      list: this.data.list
    })
  }
})

2. 使用 数组的 concat() 方法,并调用 setData() 方法更新数据

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // 1. 调用 push() 方法,将新元素合并到数组中
    const newList = this.data.list.concat(4)
      
    // 2. 调用 setData(),更新数据
    this.setData({
      list: newList
    })
  }
})

3. 使用 ...展开运算符,将元素添加到新数组,并调用 setData() 方法更新数据*

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // 1. 使用 ...展开运算符,将数据连同新的元素添加到新的数组中
    const newList = [...this.data.list,4]
      
    // 2. 调用 setData(),更新数据
    this.setData({
      list: newList
    })
  }
})

2. 修改元素

数据路径方式

Page({
  data: {
    list: [1,2,3],
    objList: [{
        name: "Tom"
    },{}]
  },
  changeArr(){
    this.setData({
      // 使用数据路径的方式修改数组中索引为1的元素
      'list[1]': 4
        
      // 使用数据路径的方式修改数组对象中索引为1的元素
      'list[0].name': 'Jany'
    })
  }
})

3. 删除元素

1. 调用数组的 splice() 方法,删除元素,再调用 setData() 方法 更新数据

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // 删除索引为0的元素,删除1个
    this.data.list.splice(0,1)

    // 调用 setData() 方法,更新数据
    this.setData({
      list: this.data.list
    })
  }
})

2. 调用数组的 filter() 方法,筛选出符合条件的元素,再调用 setData() 方法 更新数据

Page({
  data: {
    list: [1,2,3]
  },
  changeArr(){
    // 1. 调用 filter() 方法筛选出符合条件的元素
    const newList = this.data.list.filter(item => item !== 2)

    // 2. 调用 setData() 方法,更新数据
    this.setData({
      list: newList
    })
  }
})

4. 循环

1. 普通数组

pages/index/index.wxml

<!-- 循环数组时, index 是 索引, item 是元素值 -->
<view wx:for="{{ list }}" wx:key="index">{{ item }}</view>

pages/index/index.js

Page({
  data: {
    list: [1,2,3]
  }
})

2. 数组对象

pages/index/index.wxml

<!-- 如果是使用对象中的某个属性作为key, 必须加双大括号来取值 -->
<view wx:for="{{ peopleList }}" wx:key="{{ item.id }}">
  <text>{{ item.name }}</text>
  <text>{{ item.age }}</text>
</view>

pages/index/index.js

Page({
  data: {
    peopleList: [
      {
        id: 1,
        name: "小明",
        age: 18
      },
      {
        id: 2,
        name: "小红",
        age: 19
      },
      {
        id: 3,
        name: "小白",
        age: 16
      },
  ]
  },
})

**3. 如果需要对默认的变量名和索引进行修改,可以使用 wx:for-item 和 wx:for-index **

<!-- 将数组中的元素变量名改为 obj, 索引变量名改为 i  -->
<view wx:for="{{ objList }}" wx:key="id" wx:for-item="obj" wx:for-index="i">
  <text>{{ obj.name }}</text>
  <text>{{ obj.age }}</text>
  <text> --- {{ i }}</text>
</view>

3. 将 wx:for 用在 <block/> 标签上,以渲染一个包含多节点的结构块. <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染, 只接受控制属性, <block/>标签在 wxml 中可以用于组织代码结构,支持列表渲染、条件渲染等

<block wx:for="{{ objList }}" wx:key="id" wx:for-item="obj" wx:for-index="i">
  <view>名字: {{ obj.name }}</view>
  <view>年龄: {{ obj.age }}</view>
</block>

3. 条件渲染

1. 逻辑语句

通过 新增和移除标签结构 来实现的

1. wx:if 、wx:elif、wx:else

page/index/index.wxml

<view wx:if="{{ num === 1 }}">num 等于 {{ num }}</view>
<view wx:elif="{{ num === 2 }}">num 等于 {{ num }}</view>
<view wx:else>num大于2, 目前num等于 {{ num }}</view>

<button type="warn" bind:tap="updateNum">更新 num</button>

pages/index/index.js

Page({
  data:{
    num: 1
  },
  updateNum(){
    this.setData({
      num: this.data.num + 1
    })
  }
})

2. hidden 属性

通过 css的 display:none 来实现的,页面中依然存在着标签结构

pages/index/index.wxml

<view hidden="{{ !isHidden }}">如果isHidden是true,则隐藏,否则展示</view>

<button type="warn" bind:tap="updateHidden">更新 isHidden</button>

pages/index/index.js

Page({
  data:{
    isHidden: true
  },
  updateHidden(){
    this.setData({
      isHidden: !this.data.isHidden
    })
  }
})

4. 运行机制

1. 图解

2. 启动

小程序的启动分为两种情况, 一种是冷启动、一种是热启动

**冷启动: **如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动

**热启动: ** 如果用户已经打开过某小程序, 然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态

3. 挂起

小程序进入[后台状态] 一段时间(5秒)后,微信停止小程序 JS 线程运行,小程序进入[挂起状态]

当开发者使用了后台播放音乐、后台地理位置等能力时,小程序可以在后台持续运行,不会进入到[挂起状态]

4. 销毁

如果用户很久没有使用小程序(30分钟),或者系统资源紧张,小程序会被销毁,即完全终止运行

5. 更新机制

在访问小程序时,微信会将小程序代码包缓存在本地。

开发者发布了新的小程序版本以后, 微信客户端会检查本地缓存的小程序有没有新版本,并进行小程序代码包的更新。

**更新机制: **

  1. 启动时同步更新: 微信运行时,会定期检查最近使用的小程序是否有更新。如果有更新,下次小程序启动时会同步进行更新,更新到最新版本后再打开小程序。如果用户长时间未使用小程序时,会强制同步检查版本更新
  2. 启动时异步更新: 在启动前没有发现更新,小程序每次 冷启动 时,都会异步检查是否有更新版本。如果发现有现版本,将会异步下载新版本的代码包,将新版本的小程序在下一次冷启动进行使用,当前访问使用的依然是本地的旧版本代码

在启动时异步更新的情况下, 如果开发者希望立刻进行版本更新,可以使用 wx.getUpdateManager API 进行处理,在有新版本时提示用户重启小程序更新新版本

app.js

App({
  // 冷启动时,必然会调用这个钩子函数
  onLaunch(){
    // 当小程序冷启动时, 会自动向微信后台请求新版本的信息,如果有新版本,会立即进行下载
    //  wx.getUpdateManager() 监听下载的状态,
    const updateManager = wx.getUpdateManager()
    // 当新版本下载完成后,会触发 onUpdateReady() 方法中定义的回调函数
    updateManager.onUpdateReady(function(){
      // 提示用户是否需要重启应用,进行更新新版本
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好,是否重启应用?',
        success(res){
          if (res.confirm){
            // 强制当前小程序使用新版本,并重启当前小程序
            updateManager.applyUpdate()
          }
        }
      })
    })
  }
})

测试编译,版本强制更新

6. 生命周期

**应用生命周期: **应用程序进程,从创建到消亡的整个过程,也就是小程序 启动 => 运行 => 销毁 的整个过程

**小程序生命周期: ** 小程序从启动到销毁的整个过程,其中包括 页面生命周期、组件生命周期

一个小程序完成整的生命周期由 应用生命周期、页面生命周期、组件生命周期 三部分组成

1. 应用生命周期

应用生命周期函数需要再 app.js 文件的 App() 方法中进行定义

1. onLaunch()

小程序冷启动初始化完成时触发,启动的整个过程只会执行一次,如果是热启动(即由后台状态切换为前台状态时,不会触发这个钩子函数)

2. onShow()

小程序冷启动或从后台状态进入前台状态(热启动)显示页面时触发

3. onHide()

小程序从前台状态进入后台状态时触发

2. 页面生命周期

页面生命周期函数需要在 页面.js 文件的 Page() 方法中进行定义

1. onLoad()

监听页面加载时触发,每个页面只会触发一次

2. onShow()

监听页面在前台展示时触发

3. onReady()

监听页面初次渲染完成时触发,每个页面只会触发一次

4. onUnload()

如使用navigator 组件跳转页面,且open-type="redirct"即关闭当前页面(销毁当前页面)时触发

5. onHide()

如使用navigator 组件跳转页面,且open-type="navigate"即保留当前页面(隐藏当前页面)时触发

3. 组件的生命周期

组件的生命周期函数需要在 lifetimes 字段中进行声明, created(重要)、attached(重要)、ready、moved、detached(重要)

1. created()

组件实例创建完毕后触发, 一般用于给组件添加一些自定义属性,此时不能调用 setData()

Component({
  lifetimes: {
    created () {
        this.test = "测试"   // 添加自定义属性
    }
  }
})

2. attached()

模板解析完成,并挂载到页面时触发, 一般用于给组件写一些页面交互,可以调用 setData()

3. detached()

组件被销毁时触发

4. 细节

  1. tabBar 页面之间相互切换,页面不会被销毁
  2. 点击左上角,返回上一个页面,会销毁当前页面

5. 总结

1. 小程序冷启动, 钩子函数的执行顺序

2. 保留当前页面, 进入下一个页面, 钩子函数的执行顺序、销毁当前页面, 进入下一个页面, 钩子函数的执行顺序

3. 小程序热启动, 钩子函数的执行顺序

7. 常用 API

1. 分类

**异步API: ** 通常接收一个 object 类型的参数,如: wx.request({})

**同步API: ** 通常以 Sync 结尾,如: wx.setStorageSync()

**事件监听API: ** 通常以 on 开头,如: wx.onAppHide()

异步 API 支持 callback & Promise 两种调用方式:

  1. 当接口参数 Object 对象中不包含 success、fail、complete 时将默认返回 Promise
  2. 不分接口如 request、uploadFile 本身就有返回值,因此不支持 Promise 风格的调用方式,它们的 promisify 需要开发者自行封装

2. 发送网络请求

1. 域名配置

wx.request 请求的域名必须在微信公众平台进行配置, 如果使用 wx.request 请求未配置的域名,在控制台会有响应的报错

需要开发者平台配置服务器域名

2. 跳过域名校验

3. 代码实现

pages/index/index.wxml

<block wx:for="{{ list }}" wx:key="id">
  <view>
    <text>{{ item.title }}</text>
    <image src="{{ item.imageUrl }}" mode=""/>
  </view>
</block>

<button type="warn" bind:tap="getData">发送请求</button>

pages/index/index.js

Page({
  data:{
    list: []
  },
  getData(){
    wx.request({
      // 接口地址
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      // 请求方法
      method: "GET",
      // 请求参数
      data:{},
      // 请求头
      header:{},
      // API 执行成功后的回调
      success: (res) =>{
        if (res.statusCode === 200){
          this.setData({
            list: res.data.data
          })
        }
      },
      // API 执行失败后的回调
      fail:(err) =>{
        console.log(err);
      },
      // 不管 API 执行是否成功,都会执行
      complete: () =>{

      }
    })
  }
})

3. 提示框

1. loading

通常配置发送网络请求来使用,用于增加用户体验

**wx.showLoading(): ** 显示 loading 提示框

**wx.hideLoading(): ** 关闭 loading 提示框

Page({
  data:{
    list: []
  },
  getData(){
    // 1. 当点击按钮时,就显示 loading框
    wx.showLoading({
      // loading框显示的文字内容
      title: '数据加载中...',
      // 是否显示透明蒙层, 防止触摸穿透
      // 即如果设置为true, 则在 loading框 显示的时候,其背后的页面任何地方都不可以再被点击到
      mask: true
    })
    wx.request({
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      method: "GET",
      success: (res) =>{
        if (res.statusCode === 200){
          this.setData({
            list: res.data.data
          })
          
        }
      },
      fail:(err) =>{
        console.log(err);
      },
      complete: () =>{
        // 2. 无论请求是否成功,都关闭 loading框
        wx.hideLoading()
      }
    })
  }
})

2. 模态对话框、消息提示框

**wx.showModal(): ** 显示模态对话框, 如询问用户是否退出登录等

**wx.showToast(): ** 显示消息提示框,提示用户退出登录成功等

1. 回调函数风格调用

Page({
  logOut(){
    wx.showModal({
      title: '提示',   // 提示的标题
      content: '是否退出登录',   // 提示的内容
      complete: (res) => {
        // 用户点击取消后执行的逻辑
        if (res.cancel) {
          // 调用消息提示框,告诉用户成功退出登录 
          wx.showToast({     
            title: '成功退出登录!',
          })
        }
        // 用户点击确定后执行的逻辑
        if (res.confirm) {
          // 调用消息提示框,告诉用户成功退出登录 
          wx.showToast({
            title: '退出登录成功',
          })
        }
    })
  }
})

2. Promise 风格调用

Page({
  async logOut(){
    const { cancel, confirm } = await wx.showModal({
      title: '提示',   // 提示的标题
      content: '是否退出登录',   // 提示的内容
    })
    // 1. 用户点击确定后执行的逻辑
    if (confirm) {
      // 调用消息提示框,告诉用户成功退出登录 
      wx.showToast({     
        title: '成功退出登录!',
      })
    } else { // 2. 用户点击取消后执行的逻辑
      wx.showToast({
        title: '取消删除',
        icon: `error`,    // 更换消息提示框的图标
        duration: 2000   // 设置 2s 后消息提示框消失
      })
    }
  }
})

4. 本地存储

在小程序中使用 API 将数据存储在用户的设备上, 以便小程序运行时和下次启动时快速的读取这些数据

如果存储对象类型的数据, 可以直接进行存储和读取, 无需使用 JSON.stringify()、JSON.parse() 进行转换

1. 同步存储

**wx.setStoragesync(): ** 新增

// 第一个参数: 本地存储中指定的key
// 第二个参数: 需要存储的数据
wx.setStorageSync("num", 1)

// 如果存储的是对象类型数据, 不需要使用 JSON.stringify() 转换成 JSON 字符串
wx.setStorageSync("obj", {name: "tome", age: 16})

**wx.getStorageSync(): ** 获取

const num = wx.getStorageSync("num")

// 如果存储的是对象类型数据, 不需要使用 JSON.parse() 转换成对象
const obj = wx.getStorageSync("obj")

**wx.removeStorageSync(): ** 删除

wx.removeStorageSync("num")

**wx.clearStorageSync(): ** 清空

wx.clearStorageSync()

2. 异步存储

**wx.setStorage(): ** 新增

// 第一个参数: 本地存储中指定的key
// 第二个参数: 需要存储的数据
wx.setStorage("num", 1)

// 如果存储的是对象类型数据, 不需要使用 JSON.stringify() 转换成 JSON 字符串
wx.setStorage("obj", {name: "tome", age: 16})

**wx.getStorage(): ** 获取

async getStorage(){
    const num = await wx.setStorage("num")
    console.log(num)
}

// 如果存储的是对象类型数据, 不需要使用 JSON.parse() 转换成对象
async getStorage(){
    const num = await wx.setStorage("obj")
    console.log(obj)
}

**wx.removeStorage(): ** 删除

wx.removeStorage("num")

**wx.clearStorage(): ** 清空

wx.clearStorage()

5. 页面跳转

**声明式导航: ** navigator 组件

**编程式导航: ** 小程序提供的 API

1. wx.navigateTo()

保留当前页面, 并跳转至应用内的 非 tabBar 页面

wx.navigateTo({
	url: '/pages/list/list',
})

传递参数

wx.navigateTo({
	url: '/pages/list/list?name=Tom&age=23',   // 直接使用 ? 携带参数,多个参数之间使用 & 连接
})

跳转后的页面中的 onLoad(options) 方法中接收参数

pages/list/list.js

Page({
    onLoad(options){
        console.log(options.name)
    }
})

2. wx.redirectTo()

关闭当前页面, 并跳转至应用内的 非 tabBar 页面

wx.redirectTo({
    url: '/pages/list/list',
})

传递参数

wx.redirectTo({
	url: '/pages/list/list?name=Tom&age=23',   // 直接使用 ? 携带参数,多个参数之间使用 & 连接
})

跳转后的页面中的 onLoad(options) 方法中接收参数

pages/list/list.js

Page({
    onLoad(options){
        console.log(options.name)
    }
})

3. wx.switchTab()

跳转至 tabBar 页面, 路径后不允许携带参数

wx.switchTab({
    url: '/pages/mine/mine',
})

4. wx.reLaunch()

关闭所有页面, 并跳转到应用内的某个页面

wx.reLaunch({
    url: '/pages/list/list',
})

传递参数

wx.reLaunch({
	url: '/pages/list/list?name=Tom&age=23',   // 直接使用 ? 携带参数,多个参数之间使用 & 连接
})

跳转后的页面中的 onLoad(options) 方法中接收参数

pages/list/list.js

Page({
    onLoad(options){
        console.log(options.name)
    }
})

5. wx.navigateBack()

关闭当前页面, 并返回上一级页面或多级页面

// 默认返回上一级页面
wx.navigateBack()

// 返回指定层级页面
wx.navigateBack({
    delta:2
})

6. 上拉加载

1. 配置

在 pages/index/index.json 文件中配置 触发上拉加载的 距离页面底部距离

{
  "onReachBottomDistance": 100   // 默认是 50rpx
}

2. 事件监听

在 pages/index/index.js 文件中创建 onReachBottom() 函数 用来监听页面底部的距离是否达到配置值

Page({
  data:{
    numList: [1,2,3]
  },
  // 当页面距离底部的距离达到 json 文件中的距离时触发 onReachBottom() 函数
  onReachBottom(){
    // 1. 展示 loading提示框
    wx.showLoading({
      title: '数据加载中...',
    })
      
    // 2. 模拟网络延迟
    setTimeout(() => {
      const lastNum = this.data.numList[this.data.numList.length -1]
      const newArr = [lastNum + 1,lastNum + 2,lastNum + 3]
      this.setData({
        numList: [...this.data.numList,...newArr]
      })
      wx.hideLoading()
    },1500)
  }
})

7. 下拉刷新

1. 配置

在 pages/index/index.json 文件中配置 允许下拉

{
    "backgroundTextStyle": "light",   // loading的样式效果 light/dark
    "backgroundColor": "#777",   // 窗口背景色
    "enablePullDownRefresh": true  // 开启下拉刷新功能
}

2. 事件监听

在 pages/index/index.js 文件中创建 onPullDownRefresh() 函数 用来监听页面下拉刷新

Page({
  data:{
    numList: [1,2,3]
  },
  // 用户下拉刷新后触发 onPullDownRefresh() 函数
  onPullDownRefresh(){
    this.setData({
      numList: [100,200,300]
    })
    // 在下拉刷新后, loading 效果有可能会有不会收回的bug, 这里手动调用方法,收回loading 即可
    if (this.data.numList.length === 3){
      wx.stopPullDownRefresh()   // 收回 loading提示框
    }
  }
})

8. scroll-view 组件实现上拉和下拉效果

1. 上拉加载

pages/index/index.wxml

<scroll-view 
  lower-threshold="100"     // 触底距离, 用户上拉时距离底部100px时,触发上拉加载事件
  bindscrolltolower="getMore" // 监听用户上拉的自定义事件处理函数
  enable-back-to-top="true"   // 点击手机的状态栏,快速回到顶部
  class="scroll-y" 
  scroll-y>
  <view wx:for="{{ numList }}" wx:key="index">{{ item }}</view>
</scroll-view>

pages/index/index.scss

.scroll-y {
  height: 100vh;
  background-color: #efefef;
  view {
    height: 600rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    // 所有基数的儿子标签
    &:nth-child(odd){  
      background-color: lightgreen;
    }
    // 所有偶数的儿子标签
    &:nth-child(even){
      background-color: lightskyblue;
    }
  }
  
}

pages/index.index.js

Page({
  data:{
    numList: [1,2,3]
  },
  // 上拉加载更多的自定义事件处理函数
  getMore(){
    // 1. 展示 loading框
    wx.showLoading({
      title: '数据加载中...',
    })
	
    // 2. 模拟网络请求
    setTimeout(()=>{
      const lastNum = this.data.numList[this.data.numList.length -1]
      const newArr = [lastNum + 1, lastNum + 2, lastNum + 3]
      this.setData({
        numList: [...this.data.numList, ...newArr]
      })
      wx.hideLoading()
    },1500)
    
  }
})

2. 下拉刷新

pages/index/index.wxml

<scroll-view 
             
  refresher-enabled   // 开启下拉刷新
  refresher-background="#fff"  // loading 的背景颜色
  refresher-default-style="black"   // laoding 的默认样式,white/black/none
  refresher-triggered="{{ isTriggered }}"  // 是否继续展示下拉loading框,设置为false
  bindrefresherrefresh="refreshHandler"  // 下拉刷新的自定义事件处理函数

  class="scroll-y" 
  scroll-y>
  <view wx:for="{{ numList }}" wx:key="index">{{ item }}</view>
</scroll-view>

pages/index/index.scss

.scroll-y {
  height: 100vh;
  background-color: #efefef;
  view {
    height: 600rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    // 所有基数的儿子标签
    &:nth-child(odd){  
      background-color: lightgreen;
    }
    // 所有偶数的儿子标签
    &:nth-child(even){
      background-color: lightskyblue;
    }
  }
  
}

pages/index.index.js

Page({
  data:{
    numList: [1,2,3],
    isTriggered: false
  },
  // 上拉加载更多的自定义事件处理函数
  getMore(){
    // 1. 展示 loading框
    wx.showLoading({
      title: '数据加载中...',
    })
	
    // 2. 模拟网络请求
    setTimeout(()=>{
      const lastNum = this.data.numList[this.data.numList.length -1]
      const newArr = [lastNum + 1, lastNum + 2, lastNum + 3]
      this.setData({
        numList: [...this.data.numList, ...newArr],
        isTriggered: false  // 数据更新后, 继续将 isTriggered 设置为false,来隐藏下拉 loading 框
      })
      wx.hideLoading()
    },1500)
    
  }
})
posted @ 2024-06-14 17:00  河图s  阅读(189)  评论(0)    收藏  举报