加载中...

微信小程序学习(加深)


微信小程序学习(加深)

一、wx:if 与 hidden 的对比

wx:if 以动态创建和移除元素的方式,控制元素的展示与隐藏

hidden 以切换样式的方式(display: none/block;),控制元素的显示与隐藏

所以需要 频繁切换时,建议使用 hidden

如果条件复杂时,建议使用 wx:if 搭配 wx:elifwx:else 进行展示与隐藏的切换,

可以理解为vuev-ifv-show

二、wx:for

通过 wx:for 可以根据指定的数组,循环渲染重复的组件结构:

<view wx:for="{{list}}"> // list即需要循环的数组
  索引:{{index}}-当前项:{{item}}
</view>

当前循环项的索引用 index 表示;当前循环项用item表示

使用 wx:for-index 可以指定当前循环项的索引的变量名

使用 wx:for-item 可以指定当前项的变量名

<view wx:for="{{list}}" wx:for-index="idx" wx:for-item='itm'>
  索引:{{idx}}-当前项:{{itm}}
</view>

声明式导航

通过点击<navigator>组件实现页面跳转

如果需要导航到tabBar页面,我们需要指定好url地址,以及跳转的方式open-type 表示跳转的方式,必须为 switchTab,即:

<navigator url="/pages/home/home" open-type="switchTab">跳转tabBar</navigator>

如果导航到非 tabBar 页面,open-type 必须为 navigateopen-type="navigate" 属性可以省略:

<navigator url="/pages/info/info" open-type="navigate">跳转非 tabBar </navigator>

如果想后退上一页的话,open-type 的值必须是 navigateBack,表示要进行后退导航,还需要添加delta 其值必须是数字,表示要后退的层级,默认为1:

<navigator open-type="navigateBack" delta='1' >后退</navigator>

编程式导航

调用 wx.switchTab(Object object) 方法进行跳转

如果需要导航到 tabBar 页面,其示例代码:

// 在页面添加点击按钮绑定事件
<button bindtap="gotabBar">跳转tabBar页面</button>
// 当前页面的js文件
  gotabBar(){
    wx.switchTab({
      url: '/pages/home/home',
    })
  }

如果需要导航到 非tabBar 页面,其示例代码:

// 在页面添加点击按钮绑定事件
<button bindtap="gotabBar">跳转tabBar页面</button>
// 当前页面的js文件
  gotabBar(){
    wx.navigateTo({
      url: '/pages/info/info',
    })
  }

如果需要后退,可以调用 wx.navigateBack(Object object) 方法,可以返回上一页面或多级页面,主要接收参数delta,传入Number类型,默认为1:

// 在页面添加点击按钮绑定事件
<button bindtap="goBack">跳转tabBar页面</button>
// 当前页面的js文件
  gotabBar(){
    wx.navigateBack()
  }

三、生命周期

小程序的生命周期分为两类:

应用生命周期 : 特指小程序从启动 -> 运行 -> 销毁的过程

页面生命周期 : 特指小程序中,每个页面的加载 -> 渲染 -> 销毁的过程

页面的生命周期范围较小,应用程序的生命周期范围较大

了解了生命周期,在每个生命周期就会伴随着生命周期函数:

生命周期函数分为两类,分别是:

应用的生命周期函数 : 特指小程序从启动 -> 运行 -> 销毁期间依次调用的那些函数

页面的生命周期函数 : 特指小程序中,每个页面从加载 -> 渲染 -> 销毁期间依次调用的那些函数

应用的生命周期函数

小程序的应用生命周期函数需要在 app.js 中进行声明:

// app.js
// 主要的函数,分别是:初始化完成的时候,小程序由后台进入,小程序进入后台
App({
  onLaunch: function () {},
  onShow: function () { },
  onHide: function () { }
});

页面的生命周期函数

小程序的页面生命周期函数需要在页面的 .js 文件中进行声明:

Page({
  /**
   * 页面的初始数据
   */
  data: {},
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {},
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {},
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {},
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {},
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {},
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {},
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {},
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {}
})

四、WXS 脚本

WXS(WeiXin Script)是小程序独有的一套脚本语言,结合 WXML,可以构建出页面的结构,可以理解为一种写在外面在引入使用的js代码,wxml 中无法调用在页面的 .js 中定义的函数,所以一般是作为”过滤器”来使用的。

使用方法:

在项目新建一个util的文件夹,用于汇总文件,新建一个index.wxs的文件,在里面编写一些函数导出:

function toLower(str) {
  return str.toLowerCase()
}
module.exports = {
  toLower: toLower
}

在需要使用这个函数的wxml的文件里面再最后面添加<wxs></wxs>标签:

// 页面使用函数
<view>{{m2.toLower(count2)}}</view>
// module 用来指定模块的名称 src 用来指定要引入的脚本的路径,且必须是相对路径
<wxs module="m2" src="../../util/index.wxs"></wxs>

如果想直接写在wxml文件,可以直接在下方书写即可:

<view>{{m1.toUpper(count)}}</view>

<wxs module="m1">
  module.exports.toUpper = function (str) {
    return str.toUpperCase()
  }
</wxs>

五、数据监听器

数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。它的作用类似于 vue 中的 watch 侦听器。在小程序组件中,数据监听器的基本语法格式如下:

Component({
  observers:{
    '监听数据1,监听数据2':function(新数据1,新数据2){
      // 这里书写处理内容
    }
  }
})

如果某个对象中需要被监听的属性太多,为了方便,可以使用通配符 ** 来监听对象中所有属性的变化:

Component({
  observers:{
    'data.**':function(obj){
      this.setData({
          newData:`${obj.a},${obj.b}`
      })
    }
  }
})

六、组件

组件的生命周期函数

在小程序组件中,最重要的生命周期函数有 3 个,分别是 createdattacheddetached,主要为:

  1. 组件实例刚被创建好的时候,created 生命周期函数会被触发

  2. 在组件完全初始化完毕、进入页面节点树后, attached 生命周期函数会被触发

  3. 在组件离开页面节点树后, detached 生命周期函数会被触发

其他的周期函数:

  1. ready :在组件在视图层布局完成后执行
  2. moved : 在组件实例被移动到节点树另一个位置时执行
  3. error : 每当组件方法抛出错误时执行,会获得一个err的参数

lifetimes 节点

在小程序组件中,生命周期函数可以直接定义在 Component 构造器的第一级参数中,可以在lifetimes字段 内进行声明(这是推荐的方式,其优先级最高)

Component({
  // 推荐写法
  lifetimes: {
    attached() { },
    detached() { }
  },
  // 旧式写法
  attached() { },
  detached() { }
})

组件所在页面的生命周期

组件所在页面的生命周期函数有如下 3 个,分别是:

  1. show : 组件所在的页面被展示时执行
  2. hide : 组件所在的页面被隐藏时执行
  3. resize : 组件所在的页面尺寸变化时执行,接收size参数

pageLifetimes 节点

组件所在页面的生命周期函数,需要定义在 pageLifetimes 节点中,示例代码如下:

Component({
  pageLifetimes: {
    show: function () { }, // 页面被显示
    hide: function () { }, // 页面被隐藏
    resize: function (size) { }, // 页面尺寸发生变化
  }
})

七、插槽

了解vue对于插槽肯定不陌生,对于小程序,侧重于启用多个插槽,在小程序的自定义组件中,需要使用多 插槽时,可以在组件的 .js 文件中,通过如下方式进行启用。

Component({
  options: {
    multipleSlots: true // 启用多个slot
  }
})

在组件的 .wxml 中使用多个 标签,以不同的 name 来区分不同的插槽:

<view>
  <slot name='slotOne'></slot>
  <view>------</view>
  <slot name='slotTwo'></slot>
</view>

使用的时候需要注明slot属性:

<!-- 使用 -->
<my-info>
  <view slot='slotOne'>这是slotOne</view>
  <view slot='slotTwo'>这是slotTwo</view>
</my-info>

八、父子组件之间的通信

  1. 属性绑定用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件:
// 父组件定义数据
  data: {
    num: 0
  }
// 向组件传值
<my-info num='{{num}}'></my-info>

// 子组件接收
  properties: {
    num: Number
  }
// 子组件使用
<text>num:{{num}}</text>
  1. 事件绑定用于实现子向父传值,可以传递任何类型的数据:
// 子组件的wxml
<button type="primary" bindtap="addNum">+1</button>
// 子组件的js绑定事件
  methods: {
    addNum() {
      // 修改自身的num
      this.setData({
        num: this.properties.num + 1
      })
      this.triggerEvent('add', { value: this.properties.num })
    }
  }
// 父组件的wxml
<my-info bindadd="changeNum"></my-info>
// 父组件的js
  changeNum(e) {
    this.setData({
      num: e.detail.value // value是传入的值
    })
  }
  1. 获取组件实例:可在父组件里调用 this.selectComponent("id或class选择器") ,获取子组件的实例对象,从而直接访问子组 件的任意数据和方法。调用时需要传入一个选择器:
// 父组件的wxml
<my-info class="info"></my-info>
<button bindtap="getInfo">获取组件实例</button>
// 父组件的js
  getInfo() {
    const myInfo = this.selectComponent('.info')
    myInfo.setData({ num: myInfo.properties.num + 1 }) // 调用组件的方法
    myInfo.addNum() // 调用组件的方法
  }

九、behaviors

behaviors 是小程序中,用于实现组件间代码共享的特性,类似于 Vue.js 中的 mixins

在项目新建文件夹behaviors,用于汇总,在该文件夹下创建index.js文件,调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象,供所有的组件使用:

module.exports = Behavior({
  properties: {},
  data: { name: 'zs' },
  methods: {}
})

需要使用到该文件的内容可以引入即可:

const myBehavior = require('../behaviors/index')
Component({
  behaviors: [myBehavior],
  ...
})

十、npm 包

在小程序也是可以使用一些npm包来加速项目的搭建

Vant Weapp

Vant Weapp 是有赞前端团队开源的一套小程序 UI 组件库,助力开发者快速搭建小程序应用

官网地址:<Vant Weapp)>

使用步骤:

打开终端

输入:

// 先初始化包,这里需要安装node
npm init -y 
// 安装Vant Weapp,如果安装不了需要管理员身份运行,或者看清楚安装的路径是否是项目的路径
npm i @vant/weapp@1.3.3 -S --production

我们还需要构建npm:

构建npm

如果出现报错:

报错

我们需要找到project.config.json文件,修改一些内容:

{
  ...
  "setting": {
    ...
    "packNpmManually": true,
    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./miniprogram/"
      }
    ]
  }
}

构建好了项目会出现miniprogram_npm文件夹

安装构建完 Vant 组件库之后,将 app.json 中的 "style": "v2" 去除,在 app.jsonusingComponents 节点中引入需要的组件:

  "usingComponents": {
    "van-button": "@vant/weapp/button/index"
  }

使用:在需要用到按钮的wxml文件测试一下:

<van-button type='primary'>按钮</van-button>

页面呈现了绿色的按钮即代表引入成功了

如果想定制全局主题样式,可以在 app.wxss 中,写入 CSS 变量,即可对全局生效:

page{
  --button-primary-background-color:red
}

这样我们再去看,按钮就会变成红的,想自己定义一些样式,可以去<vant-weapp/var.less at dev · youzan/vant-weapp (github.com)>了解更多样式的修改

十一、API Promise化

API Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步 API,升级改造为基于 Promise 的异步 API,从而提高代码的可读性、维护性,避免回调地狱的问题。

我们需要安装相应的包:

npm i miniprogram-api-promise@1.0.4 --save

安转好之后再次构建npm,在app.js顶部添加代码:

import { promisifyAll } from 'miniprogram-api-promise'
const wxp = wx.p = {}
promisifyAll(wx, wxp)

使用:

// wxml结构
<van-button type='primary' bindtap="getInfo">按钮</van-button>
//js结构
  async getInfo() {
    const res = await wx.p.request({
      method: 'GET请求方式',
      uri: '请求地址',
      data: { 请求数据 }
    })
    console.log(res)
  }

十二、全局数据共享

全局数据共享是为了解决组件之间数据共享的问题,可以理解为vuevuex全局数据共享,

在小程序中,可使用mobx-miniprogram配合 mobx-miniprogram-bindings 实现全局数据共享

安装 MobX 相关的包:

npm i mobx-miniprogram@4.13.2 --save
npm i mobx-miniprogram-bindings@1.2.1 --save

再次构建npm

我们需要在项目创建文件夹store,在该文件夹下创建store.js文件,创建 MobX Store 实例:

import { observable, action } from 'mobx-miniprogram'

export const store = observable({
  // 定义数据
  num1: 1,
  num2: 2,

  // 计算,类似于getter
  get sum() {
    return this.num1 + this.num2
  },
  // action方法
  changeNum1: action(function (value) {
    this.num1 += value
  })
})

将 Store 中的成员绑定到页面中

// 在我们需要使用store的js文件引入即可
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'
Page({
  ...
  onLoad: function () {
    this.storeBindings = createStoreBindings(this, {
      store,
      fields: ['num1', 'num2', 'sum'],
      actions: ['changeNum1']
    })
  },
  onUnload: function () {
    this.storeBindings.destoryStoreBindings()
  }
})

页面的展示:

// wxml页面
<view>{{num1}}+{{num2}}={{sum}}</view>
<van-button type='primary' bindtap="addNum1" data-value="{{1}}">num1+1</van-button>
//js页面绑定函数
  addNum1(e) {
    this.changeNum1(e.target.dataset.value)
  }

当我们点击按钮的时候就会触发addNum1函数,该函数会去触发store.js的changeNum1,将num1的数值进行加一,从而引起sum的值的变化。

将 Store 中的成员绑定到组件中

在组件中的绑定和页面有一点点区别:

import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from '../store/store'
Component({
  behaviors: [storeBindingsBehavior],
  storeBindings: {
    store,
    fields: {
      num1: () => store.num1, // 绑定的第一种方法
      num2: (store) => store.num2, // 绑定的第二种方法
      sum: 'sum'
    },
    actions: {
      changeNum1: 'changeNum1'
    }
  }
})

使用方法和页面的使用方法一致:

// wxml页面
<view>{{num1}}+{{num2}}={{sum}}</view>
<van-button type='primary' bindtap="addNum1" data-value="{{1}}">num1+1</van-button>
//js页面绑定函数
  addNum1(e) {
    this.changeNum1(e.target.dataset.value)
  }

十三、分包

分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载

配置方法:

app.json的文件中,pages选项是我们主包的保存路径,所有的tabBar只能写在这里进行主要加载,其他的部分可以写在subpackages选项下进行分包加载,小程序会按 subpackages 的配置进行分包,subpackages 之外的目录将被打包到主包中。

例如:

  "subPackages": [
    {
      "root": "packageA", // 第一个分包的目录名称
      "pages": [
        "pages/cart/cart", // 包的存放路径
        "pages/myShop/myShop"
      ]
    },
    {
      "root": "packageB",
      "pages": [
        "pages/cart2/cart2",
        "pages/myShop2/myShop2"
      ]
    }
  ]

如果需要设置成独立分包,即不依赖主包即可运行,这样可以很大程度上提升分包页面的启动速度,普通分包必须依赖于主包才能运行 ,而独立分包可以在不下载主包的情况下,独立运行

我们只需要在普通分包添加independent即可,以packageB为例:

    {
      "root": "packageB",
      "pages": [
        "pages/cart2/cart2",
        "pages/myShop2/myShop2"
      ],
      "independent": true
    }

分包预下载

在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包 页面时的启动速度。

在项目的app.json文件添加代码:

// 该属性与pages平级  
"preloadRule": {
    // 当我们进入到pages/home/home路径下就开始预下载packageA这个包
    "pages/home/home":{ // 触发分包预下载的路径
      "network": "all", // 默认为WiFi
      "packages": ["packageA"] // 预下载的包,可以通过root或者name来指定预下载的包
    }
  }

十四、自定义 tabBar

小程序官网自定义tabBar的地址:<自定义 tabBar | 微信开放文档 (qq.com)>

在该地址的添加 tabBar 代码文件可以引入我们的vant组件库:<Tabbar 标签栏 - Vant Weapp )>

使用步骤:

  1. app.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置也补充完整。
  2. 新建custom-tab-bar文件夹,在该文件夹创建index.js、index.json、index.wxml、index.wxss
  3. 复制vant组件库的自定义图标

定义custom-tab-bar下的index.wxml文件夹:

<van-tabbar active-color='#13A7A0' active="{{ active }}" bind:change="onChange">
  <van-tabbar-item info='{{item.info?item.info:""}}' wx:for="{{list}}" wx:key="index">
    <image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
    <image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
    {{item.text}}
  </van-tabbar-item>
</van-tabbar>

定义custom-tab-bar下的index.js文件夹:

import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from '../store/store'
Component({
  options: {
    styleIsolation: 'shared'
  },
  behaviors: [storeBindingsBehavior],
  storeBindings: {
    store,
    fields: {
      active: 'active'
    },
    actions: {
      updateActive: 'updateActive'
    }
  },
  data: {
    "list": [
      {
        "pagePath": "/pages/home/home", // 跳转路径
        "text": "首页",
        "iconPath": "/images/...", // 未选中的图标
        "selectedIconPath": "/images/..." // 选中的图标
      },
      {
        "pagePath": "/pages/cart/cart",
        "text": "购物车",
        "iconPath": "/images/...",
        "selectedIconPath": "/images/...",
        "info": 2
      },
      {
        "pagePath": "/pages/my/my",
        "text": "我们",
        "iconPath": "/images/...",
        "selectedIconPath": "/images/..."
      }
    ]
  },
  methods: {
    onChange(event) {
      this.updateActive(event.detail)
      wx.switchTab({
        url: this.data.list[event.detail].pagePath,
      })
    },
  }
})

index.wxss文件修改一定的样式:

.van-tabbar-item{
  --tabbar-item-margin-bottom:0;
}

store文件代码:

import { observable, action } from 'mobx-miniprogram'
export const store = observable({
  active:0,
  get sum() {},
  updateActive: action(function (index) {
    this.active = index
  })
})

文章作者:
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 !