赞
踩
再续一篇…
声明式导航 :在页面上声明一个<navigator>
导航组件,通过点击<navigator>
组件实现页面跳转
导航到 tabBar
页面:在使用 <navigator>
组件跳转到指定的 tabBar
页面时,需要指定 url
属性和 open-type
属性,其中: url
表示要跳转的页面的地址,必须以 /
开头 ;open-type
表示跳转的方式,必须为 switchTab
<navigator url="/pages/message/message" open-type="switchTab">导航到tab页面</navigator>
导航到非 tabBar
页面:open-type
必须为 navigate
(注意:在导航到非 tabBar
页面时,open-type="navigate"
属性可以省略)
<navigator url="/pages/info/info" open-type="navigate">导航到tab页面</navigator>
后退导航:open-type
的值必须是 navigateBack
,表示要进行后退导航 ;delta
的值必须是数字,表示要后退的层级**(注意:如果只是后退到上一页面,则可以省略 delta
属性,因为其默认值就是 1)**
<navigator open-type="navigateBack" delta="1">返回上一页</navigator>
编程式导航 :调用小程序的导航 API
,实现页面的跳转
导航到 tabBar
页面:调用 wx.switchTab(Object object)
方法,可以跳转到 tabBar
页面,其中 Object
参数对象的属性列表有:
url
:跳转 tabBar
页面的路径 (必填)success
:接口调用成功的回调函数fail
:接口调用失败的回调函数complete
:接口调用接收的回调函数(成功失败都会执行)<button bindtap="gotoMessage">
跳转至 tab 页面
</button>
gotoMessage() {
wx.switchTab({
url: '/page/message/message'
})
}
导航到非 tabBar
页面:调用 wx.navigateTo(Object object)
方法,可以跳转到非 tabBar
的页面。
<button bindtap="gotoInfo">
跳转至非 tab 页面
</button>
gotoInfo() {
wx.navigateTo({
url: '/page/info/info'
})
}
后退导航: 调用 wx.navigateBack(Object object)
方法,可以返回上一页面或多级页面。
<button bindtap="gotoBack">
后退
</button>
gotoBack() {
wx.navigateBack()
}
声明式导航传参:navigator
组件的 url
属性用来指定将要跳转到的页面的路径。同时,路径的后面还可以携带参数:
参数与路径之间使用 ? 分隔
参数键与参数值用 = 相连
不同参数用 & 分隔
<navigator url="/pages/info/info?name=zs&age=18">导航到tab页面</navigator>
编程式导航传参:
<button bindtap="gotoInfo">
跳转至非 tab 页面
</button>
gotoInfo() {
wx.navigateTo({
url: '/page/info/info?name=ls&age=20'
})
}
在 onLoad
中接收导航参数:通过声明式导航传参或编程式导航传参所携带的参数,可以直接在 onLoad
事件中直接获取到
data: {
// 存储 onLoad 接收到的参数
query: []
}
onLoad: function (options) {
console.log(options)
this.setData({
// 保存到 data 中的 query
query: options
})
}
wx.stopPullDownRefresh()
:当处理完下拉刷新后,下拉刷新的 loading
效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的 loading
效果应用生命周期(在 app.js
中进行声明):特指小程序从启动 -> 运行 -> 销毁的过程
App({
onLaunch() {
console.log('onLaunch监听小程的初始化,全局只触发一次')
},
onShow(){
console.log('onShow监听小程序的显示')
},
onHide(){
console.log('onHide监听小程序隐藏')
}
})
页面生命周期(在页面的 .js
文件中进行声明):特指小程序中,每个页面的加载 -> 渲染 -> 销毁的过程
Page({ // 页面的初始数据 data: { }, // 生命周期函数--监听页面加载 onLoad: function (options) { }) // 生命周期函数--监听页面初次渲染完成 onReady: function () { }, // 生命周期函数--监听页面显示 onShow: function () { }, // 生命周期函数--监听页面隐藏 onHide: function () { }, // 生命周期函数--监听页面卸载 onUnload: function () { }, })
组件的生命周期函数(组件的的生命周期可以在 lifetimes
字段内进行声明,其优先级最高)
Component({ // 在该字段下声明 lifetimes: { created: function() { // 在组件实例被创建时,会触发 // 此时还不能调用 setData // 通常只应该用于给组件的 this 添加一些自定义的属性字段 }, attached: function() { // 在组件实例进入页面节点树时执行 // 此时, this.data 已被初始化完毕 // 绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据) }, ready: function() { // 在组件在视图层布局完成后执行 }, moved: function() { // 在组件实例被移动到节点树另一个位置时执行 }, detached: function() { // 在组件实例被从页面节点树移除时执行 // 退出一个页面时,会触发,此时适合做一些清理性质的工作 }, error: function() { // 每当组件方法抛出错误时执行 }, }, }) // 组件所在页面的生命周期,需要定义在 pageLifetimes 节点中 Component({ pageLifetimes: { show: function() {}, // 页面被展示 hide: function() {}, // 页面被隐藏 resize: function(size) {} // 页面尺寸变化 } })
创建组件:
components -> test
文件夹components -> test
文件夹上,鼠标右键,点击“新建 Component
”.js,.json, .wxml 和 .wxss
引用组件
局部引用:在页面的 .json
配置文件中引用组件的方式,叫做“局部引用”
全局引用:在 app.json
全局配置文件中引用组件的方式,叫做“全局引用”
"usingComponents": {
// "自定义组件名": "路径"
"my-test": "/component/test/test"
}
// 在页面的 .wxml 文件中使用组件
<my-test></my-test>
组件与页面的区别
.json
文件中需要声明 "component": true
属性.js
文件中调用的是 Component()
函数methods
节点中组件样式隔离
class
选择器会有样式隔离效果,id
选择器、属性选择器、标签选择器不受样式隔离的影响修改组件的样式隔离选项
默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题。但有时,我们希望在外界能够控制组件内部的样式,此时,可以通过 styleIsolation
修改组件的样式隔离选项,用法如下:
// 方法1:在组件的 .js 文件中新增如下配置
Component({
options: {
styleIsolation: 'isolated'
}
})
// 方法2:在组件的 .json 文件中新增如下配置
{
"styleIsolation": "isolated"
}
styleIsolation
的可选值:
isolated
:启用样式隔离(默认)apply-shared
:页面样式会影响自定义组件,但自定义组件中的样式不会影响页面shared
:页面样式与组件样式会相互影响,也会影响其他设置了 apply-shared
或 shared
的自定义组件自定义组件中的 properties
属性:在小程序组件中,properties
是组件的对外属性,用来接收外界传递到组件中的数据
Component({
properties: {
// 方法1:完整定义属性的方式
max: {
type: Number, // 属性值的数据类型
value: 10 // 属性默认值
},
// 方法2:简化方法(不能指定默认值)
max: Number
}
})
// 页面中(如果页面有传递相应数值,则会覆盖组件中的默认值)
<my-test max="9"></my-test>
数据侦听器:用于监听和响应任何属性和数据字段的变化,从而执行特定的操作,类似于 VUE
中的 watch
侦听器
// 基本语法 Component({ observers: { '字段A,字段B': function(字段A的新值, 字段B的新值) { // do something } } }) // 例子(基本用法) Component({ data: { n1: 0, n2: 0, sum: 0 }, methods: { addN1() { this.setData({ n1: this.data.n1 + 1 }) }, addN2() { this.setData({ n2: this.data.n2 + 1 }) }, }, observers: { 'n1, n2': function(newN1, newN2) { this.setData({ sum: newN1 + newN2 }) } } }) // 监听对象属性的变化 observers: { 'list.n1, list.n2': function(newN1, newN2) { this.setData({ sum: newN1 + newN2 }) } } // 监听对象中所有属性的变化,可以使用通配符 ** 来监听对象中所有属性的变化 observers: { 'list.**': function(obj) { this.setData({ sum: obj.n1 + obj.n2 }) } }
纯数据字段:那些不用于界面渲染的 data 字段。(纯数据字段有助于提升页面更新的性能。)
使用规则:在 Component
构造器的 options
节点中,指定 pureDataPattern
为一个正则表达式,字段名符合这个正则 表达式的字段将成为纯数据字段,示例代码如下
Component({
options: {
// 指定所有 _ 开头的数据为纯数据字段
pureDataPattern: /^_/
},
data: {
a: true, // 普通数据字段
_b: true // 纯数据字段
}
})
插槽:以提供一个<slot>
节点(插槽),用于承载组件使用者提供的 wxml
结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOPuN80V-1666750576358)(C:\Users\zzx\AppData\Roaming\Typora\typora-user-images\image-20221022161231082.png)]
单个插槽
<!-- 组件的封装者 -->
<view>
<view>这是组件的内部节点</view>
<!-- 使用 slot 插槽占位 -->
<slot></slot>
</view>
<!-- 组件的使用者 -->
<test1>
<!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
<view>组件 slot 中的内容</view>
</test1>
多个插槽:需要使用多个插槽时,可以在组件的 .js
文件中,通过如下方式进行启用:
Component({
options: {
multipleSlots: true // 开启多个插槽
}
})
<!-- 组件的封装者 --> <view> <!-- name 为 before 的第一个 slot 插槽占位 --> <slot name="before"></slot> <view>这是组件的内部节点</view> <!-- name 为 after 的第二个 slot 插槽占位 --> <slot name="after"></slot> </view> <!-- 组件的使用者 --> <test1> <!-- 这部分内容将被放置在组件中 name 为 before 的 <slot> 的位置上 --> <view slot="before">组件 name 为 before 的 slot 中的内容</view> <!-- 这部分内容将被放置在组件中 name 为 after 的 <slot> 的位置上 --> <view slot="after">组件 name 为 after 的 slot 中的内容</view> </test1>
父子组件之间的通信
属性绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON
兼容的数据(只能传递普通类型的数据,无法将方法传递给子组件)
// 父组件中 data 节点
data: {
count: 0
}
// 父组件的 wxml 结构
// 引用子组件,向子组件传递 count 属性
<test1 count="{{count}}"></test1>
<view>父组件中,count值为:{{count}}</view>
// 子组件的 properties 节点
properties: {
// 接收父组件传递的 count
count: Number
}
// 子组件的 wxml 结构
<view>子组件中,count值为:{{count}}</view>
事件绑定:用于子组件向父组件传递数据,可以传递任意数据
在父组件的 .js
中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
// 在父组件中定义 syncCount 方法
// 这个方法会传递给子组件,供子组件进行调用
syncCount(e) {
console.log('syncCount')
}
在父组件的 wxml
中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件
<!-- 使用 bind:自定义事件名称 (推荐使用,结构清晰) -->
<test1 count="{{count}}" bind:sync="syncCount"></test1>
<!-- 或在 bind 后面直接写上自定义事件名称 -->
<test1 count="{{count}}" bindsync="syncCount"></test1>
在子组件的 js
中,通过调用 this.triggerEvent('自定义事件名称', { /* 参数对象 */ })
,将数据发送到父组件
// 子组件的 wxml 结构
<view>子组件中,count值为:{{count}}</view>
<button type="primary" bindtap="addCount">
+1
</button>
// 子组件的 js 代码
methods: {
addCount() {
this.setData({
count: this.properties.count + 1
})
// 子组件将更新后的 count 值传递给父组件
this.triggerEvent('sync', {value: this.properties.count})
}
}
在父组件的 js
中,通过 e.detail
获取到子组件传递过来的数据
syncCount(e) {
// console.log('syncCount')
this.setData({
count: e.detail.value
})
}
获取组件实例:父组件还可以通过 this.selectComponent("id或class选择器")
获取子组件实例对象,这样就可以直接访问子组件的任意数据和方法
<!-- 父组件中 wxml 结构 -->
<!-- 使用 bind:自定义事件名称 (推荐使用,结构清晰) -->
<test1 count="{{count}}" bind:sync="syncCount" class="customA"></test1>
<button bindtap="getChild">
获取子组件实例
</button>
// 父组件中 js 结构
getChild() {
const child = this.selectComponent('.customA')
child.setData({ count: child.porperties.count + 1 }) // 调用子组件的 setData 方法,使其的 count 自增加1
child.adCount() // 调用子组件的 addCount 方法
}
组件中的 behaviors
:用于实现组件间代码共享的特性,类似于 Vue.js
中的 “mixins”
。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
。
创建behavior
(在项目根目录创建behaviors
文件夹,再在文件夹中创建相应的js
文件):调用 Behavior(Object object)
方法即可创建一个共享的 behavior
实例对象,供所有的组件使用:
// 调用 Behavior() 方法,创建实例对象
// 使用 module.exports 将 behavior 实例对象共享出去
module.exports = Behavior({
// 属性节点
properties: {},
// 私有数据节点
data: { username: 'zs' },
// 事件处理函数和自定义方法节点
methods: {},
// 其他节点...
})
在组件中,使用 require()
方法导入需要的 behavior
,挂载后即可访问 behavior
中的数据或方法
// 1. 使用 require() 方法导入需要的 behavior 模块
const myBehavior = require("../../behaviors/my-behavior")
Component({
// 2. 将导入的 behavior 实例对象,挂载到 behaviors 数组节点中
behaviors: [myBehavior]
})
npm
包Vant Weapp
: 是有赞前端团队开源的一套小程序 UI
组件库,助力开发者快速搭建小程序应用。它所使用的是 MIT
开源许可协议,对商业使用比较友好
安装步骤:https://youzan.github.io/vant-weapp/#/quickstart#an-zhuang
如果项目初次使用 npm
,需执行 npm init -y
,安装包管理文件(package.json
)
通过 npm
安装(建议指定版本为@1.3.3
):npm i @vant/weapp@1.3.3 -S --production
修改app.json
:将 app.json
中的 "style": "v2"
去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。
构建 npm
包:打开微信开发者工具,点击 工具 -> 构建 npm
,并勾选 使用 npm
模块 选项,构建完成后,即可引入组件
使用 vant
组件(全局引入):在 app.json
的 usingComponents
节点中引入需要的组件,即可在 wxml
中直接使用组件。
// app.json
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
// 页面的 .wxml 结构
<van-button type="primary">按钮</van-button>
API Promise
化
默认情况下,小程序官方提供的异步 API
都是基于回调函数实现的,容易造成回调地狱的问题,代码的可读性、维护性差
API Promise
化,指的是通过额外的配置,将官方提供的、基于回调函数的异步 API
,升级改造为基于 Promise
的异步 API
,从而提高代码的可读性、维护性,避免回调地狱的问题。
安装步骤:
npm install --save miniprogram-api-promise@1.0.4
(建议安装1.0.4版本)
安装完成后,重新构建 npm
包(注意:如果项目中已存在 miniprogram_npm
目录,需先删除再构建)
在小程序入口文件中(app.js
),只需调用一次 promisefyAll()
方法,即可实现异步 API
的 Promise
化
import { promisefyAll } from 'miniprogram-api-promise'
const wxp = wx.p = {}
promisefyAll(wx, wxp)
调用 Promise
化之后的异步 API
// 页面结构
<van-button type="primary" bindtap="getInfo">按钮</van-button>
// 在页面的 .js 文件,定义对应的 getInfo 事件处理函数
async getInfo() {
const { data: res } = await wx.p.request({
method: 'GET',
url: 'https://www.escook.cn/api/get',
data: { name: 'zs', age: 20}
})
console.log(res)
}
全局数据共享(状态管理:是为了解决组件之间数据共享的问题(Vuex、Redux、MobX
)
在小程序中,可使用 mobx-miniprogram
配合 mobx-miniprogram-bindings
实现全局数据共享。其中:
mobx-miniprogram
用来创建 Store
实例对象
mobx-miniprogram-bindings
用来把 Store
中的共享数据或方法,绑定到组件或页面中使用
安装步骤:
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
MobX
相关的包安装完毕之后,删除 miniprogram_npm
目录后,重新构建 npm
创建 MobX
的 Store
实例
新建 Store
目录,再新建相应的 .js
文件
// 在这个 JS 文件中,专门来创建 Store 的实例对象 import { observable, action } from 'mobx-miniprogram' export const store = observable({ // 数据字段 numA: 1, numB: 2, // 计算属性 get sum() { return this.numA + this.numB }, // actions 方法,用来修改 store 中的数据 updateNum1: action(function (step) { this.numA += step }), updateNum2: action(function (step) { this.numB += step }) })
将Store 中的成员绑定到页面中
.js
文件中:// 页面的 .js 文件 import { createStoreBindings } from 'mobx-miniprogram-bindings' import { store } from '../../store/store' Page({ onLoda: function () { // 完成绑定工作 this.storeBindings = createStoreBindings(this, { store, fields: ['numA', 'numB', 'sum'], // 字段 actions: ['updateNum1'] // 方法 }) }, onUnload: function() { this.storeBindings.destroyStoreBindings() // 完成清除工作 } })
.wxml
中使用 Store
中的成员// 页面的 .wxml 结构
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler1" data-step="{{1}}">numA + 1</van-button>
<van-button type="danger" bindtap="btnHandler1" data-step="{{-1}}">numA - 1</van-button>
// 按钮事件处理函数
btnHander1(e) {
this.updateNum1(e.target.dataset.step)
}
将 Store
中的成员绑定到组件中
在组件的 .js
文件中:
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings' import { store } from '../../store/store' Component({ behaviors: [storeBindsBehavior], // 通过 storeBindingsBehavior 来实现自动绑定 storeBindings: { store, // 指定要绑定的 Store fields: { // 指定要绑定的字段数据 numA: () => store.numA, // 绑定字段的第 1 种方式 numB: (store) => store.numB, // 绑定字段的第 2 种方式 sum: 'sum' // 绑定字段的第 3 种方式 }, actions: { // 指定要绑定的方法 // 自定义方法名: ’store 中的方法‘ updateNum2: 'updateNum2' } } })
在组件的 .wxml
中使用 Store
中的成员:
// 组件的 .wxml 结构
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler2" data-step="{{1}}">numB + 1</van-button>
<van-button type="danger" bindtap="btnHandler2" data-step="{{-1}}">numB - 1</van-button>
// 组件的方法列表
methods: {
btnHander1(e) {
this.updateNum2(e.target.dataset.step)
}
}
概念:分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
优点:可以优化小程序首次启动的下载时间 ;对非 tabBar
页面进行按需加载;在多团队共同开发时可以更好的解耦协作。
分包后,小程序项目由 1 个主包 + 多个分包组成:
主包:一般只包含项目的启动页面或 TabBar
页面、以及所有分包都需要用到的一些公共资源】
分包:只包含和当前分包有关的页面和私有资源
配置方法
app.json
中相应代码,在 subpackages
节点进行配置独立分包:可以在不下载主包的情况下,独立运行(可以很大程度上提升分包页面的启动速度)
"subpackages": [
{
"root": "packageA",
"name": "pack1",
"pages": [
"pages/apple",
"pages/banana"
],
"independent": true // 通过此节点,声明当前 moduleB 分包为“独立分包”
}
]
分包预下载:在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度
在 app.json
中,与 pages
节点平级,使用 preloadRule
节点定义分包的预下载规则:
{
"preloadRule": {
"pages/contact/contact": { // 触发分包预下载的页面途径
"network": "all", // 可选值有“all”(不限网络进行预下载)和“wifi”(仅限wifi模式下)
// packages 表示进入页面后,预下载哪些分包,可通过 root 或 name 指定预下载哪些分包
"packages": ["pkgA"]
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。