一、自定义组件
类似 vue 或者 react 中的自定义组件, 小程序允许我们使用自定义组件的方式来构建页面
一.1 创建自定义组件
创建 :
类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成
1.在 app.json 中新建页面
2.在 和 pages 同级目录下 创建 components 文件夹
3.在 commponents 里面 创建 Tabs 文件夹
4.创建 Tabs 文件解构,点击 文件夹 Tabs,然后右键,点击新建 Commponent,会弹出一个输入框,输入 Tabs 点击回车,就会自动生成 Tabs.js、Tabs.json、Tabs.wxml、Tabs.wxss 文件
在 Tabs.json 中的代码 :
{
"component": true, // 表示当前的组件是一个组件
"usingComponents": {} // 在里面可以继续引入其它的组件
}
在 Tabs.js 中的代码
// components/Tabs/Tabs.js
// 组件是 Component,而不是 pages 了
Component({
/**
* 组件的属性列表
*/
// 接收父向子传递的数据
properties: {
},
/**
* 组件的初始数据
*/
// 自己的数据
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
一.2 声明引入自定义组件
声明 :
打开我们新建的页面,点击 xxx.json,会看到里面有一段代码,我们想要声明组件,就需要在这里面配置 标签名字 和 组件相对路径,注意最后文件的后缀名可以不用添加
{
"usingComponents": {
"Tabs":"../../commponents/Tabs/Tabs"
}
}
一.3 页面使用自定义组件
打开新建页面的 xxx.wxml, 直接把刚才在 xxx,json 中配置过的 标签名字,当做标签写上,就可以在小程序中看到引入的 Tabs 组件
<!--pages/work14/work14.wxml-->
<Tabs></Tabs>
一.4 编辑组件, tabs 样式优化
在 tabs.wxml 中编辑 :
<!--commponents/Tabs/Tabs.wxml
<Tabs></Tabs> -->
<view class="tabs">
<view class="tabs_title">
<!-- 不能用写死的数据,应该在 组件 tabs.js 的 data 中存数据,然后遍历数据到 页面的wxml 文件上 -->
<!-- <view class="title_item active">首页</view>
<view class="title_item">原创</view>
<view class="title_item">分类</view>
<view class="title_item">关于</view> -->
<view
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive?'active':''}}"
>
{{item.name}}
</view>
</view>
<view class="tabs_content">内容</view>
</view>
<Tabs></Tabs>
在 tabs.wxss 中编辑 :
/* commponents/Tabs/Tabs.wxss */
.tabs {}
.tabs_title {
display: flex;
padding: 10rpx 0;
}
.title_item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.active {
color: red;
border-bottom: 5rpx solid currentColor;
}
.tabs_content{}
在 tabs.js 中编辑 :
// components/Tabs/Tabs.js
// 组件是 Component,而不是 pages 了
Component({
/**
* 组件的属性列表
*/
// 接收父向子传递的数据
properties: {
},
/**
* 组件的初始数据
*/
// 自己的数据
data: {
tabs:[
{
id:0,
name:"首页",
isActive:true
},
{
id:1,
name:"原创",
isActive:false
},
{
id:2,
name:"分类",
isActive:false
},
{
id:3,
name:"关于",
isActive:false
}
]
},
/**
* 组件的方法列表
*/
methods: {
}
})
成功图示,现在是个死的样式,不能点击 :
一.5 标题激活选中
在 tab.wxml 标签中添加方法和下标索引
<view
wx:for="{{tabs}}"
wx:key="id"
class="title_item {{item.isActive?'active':''}}"
bindtap="handleItemTap"
data-index="{{index}}"
>
在 tabs.js 中 data 同级下的 methods 里面定义
/**
* 组件的方法列表
一. 页面.js 文件中 存放事件回调函数的时候,存放在 data 同层级下!!!
二. 组件.js 文件中 存放事件回调函数的时候,必须要存在 methods中!!!
*/
methods: {
handleItemTap(e){
/*
一. 绑定点击事件 需要在 methods 中绑定
二. 获取被点击的索引
三. 获取原数组
四. 对数组循环
1. 给每一个循环性 选中属性 改为 false
2. 给 当前的索引的 项 添加激活选中效果就可以了!!!
*/
// 2 获取索引
// console.log(e)
const {index} = e.currentTarget.dataset;
// 3 获取 data 中的数组
// 解构 对复杂类型进行解构的时候,复制了一份 变量的引用而已
// 最严谨的做法,重新拷贝一份数组,在对这个数组的备份进行处理
// let tabs = JSON.parse(JSON.stringify(this.data.tabs))
// 不要直接修改 this.data.数据
let {tabs} = this.data;
// 4.循环数组
// [].forEach 遍历数组 遍历数组的时候 修改了 v ,也会导致原数组被修改
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
})
}
}
保存,看效果,可以随便点击
![]() | ![]() |
一.6 父向子传递数据
将 Tabs.js 中 data 里面的数据剪贴,复制到 页面.js 中的 data 数据里面
在 Tabs.js 文件的 properties 中接收约束
properties: {
// 要接受的数据名称
// type 要接受的数据的类型
// value 默认值
tabs:{
type:Array,
value:[]
}
},
在 页面.wxml 中 使用,最后保存的效果和之前一样
<!--
一. 父组件(页面) 向子组件 传递数据 通过 标签属性的方式来传递
1. 在子组件上进行接收
2. 把这个数据当成是 data 中的数据直接用即可
-->
<Tabs tabs="{{tabs}}"></Tabs>
流程图 :
一.7 子向父传递数据
我们用上面的写法运行,打开 调试器的 AppData,我们本身给 首页的 isActive 设置的是 true,当后来点了别处之后,虽然底部颜色消失了,但是 可以清除的看到 AppData 里面的 isActive 还是 true,为了解决这个问题,我们就用到了 子传父
在 Tabs.js 的 methods 中定义的方法里面编译
<!-- 五. 点击事件触发的时候
触发父组件中的自定义事件 同时传递数据给 父组件
this.triggerEvent("父组件自定义事件的名称",要传递的参数 )
-->
// 触发父组件中的自定义事件 同时传递数据给 父组件
this.triggerEvent("itemChange",{index});
在页面.wxml 标签中自定义方法名
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange"></Tabs>
在 页面.js data 同级下 新添方法,编写
// 自定义事件 用来接收子组件传递的数据的
handleItemChange(e){
// console.log(e)
// 接收传递过来的参数
const {index} = e.detail;
// console.log(index)
let {tabs} = this.data;
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
})
}
点击保存,看调试器的 AppData,可以看到当我们点击变化时 isActive 的中值发生变化
一.8 自定义组件 slot
在 Tabs.wxml 中修改 view 标签 内容这一块
<view class="tabs_content">
<!--
slot 标签 其实就是一个占位符 插槽
等到 父组件调用 子组件的时候 再传递 标签过来,最终这些被传递的标签
就会替换 slot 插槽的位置
-->
<slot></slot>
</view>
在 页面.wxml Tabs 组件中添加 block 占位符
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
<block wx:if="{{tabs[0].isActive}}">0</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
<block wx:else>3</block>
</Tabs>
点击保存,查看小程序,发现点那个就显示里面的内容
一.9 定义段与实例方法
Component 构造器可用于定义组件,调用Component 构造器时可以指定组件的属性、数据、方法 等。
定义段 | 类型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表,j参见下文 |
data | Object | 否 | 组件的内部数据,和 properties 一同用于组件的模板渲染 |
observers | Object | 否 | 组件数据字段监听器,用于监听 properties 和 data 的变化 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用 |
created | Function | 否 | 组件生命周期函数,在组件实例刚刚被创建时执行,注意此时不能调用 setData |
attached | Function | 否 | 组件生命周期函数,在组件实例进入页面节点树时执行 |
ready | Function | 否 | 组件生命周期函数,在组件布局完成后执行 |
moved | Function | 否 | 组件生命周期函数,在组件实例被移动到节点树另一个位置时执行 |
detached | Function | 否 | 组件生命周期函数,在组件实例被从页面节点树移出时执行 |
二、小程序生命周期
分为应⽤生命周期和页面生命周期
关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节
二.1 应用生命周期
表格 :
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
onLaunch | function | 否 | 监听小程序初始化 | |
onShow | function | 否 | 监听小程序启动或切前台 | |
onHide | function | 否 | 监听小程序切后台 | |
onError | function | 否 | 错误监听函数 | |
onPageNotFound | function | 否 | 页面不存在监听函数 |
测试及注意点 :
在 app.js 中编译
// app.js
App({
// 一. 应用第一次启动的就会触发的事件
onLaunch(){
// 在应用第一启动的时候,获取用户的个人信息
console.log("onLaunch")
// 这里的 aabbcc 是为了测试 onError 报错 和 事件源的,如果没有报错信息,就不能打印 onError,所以在这里让小程序故意报错
// aabbcc
// 这里的代码是写一个假的地址,然后测试 onPageNotFound 找不到页面的,不然不会报错,查看不方便
// js 的方式来跳转 不能触发 onPageNotFound
// wx.navigateTo({
// url:'/11/22/33'
// })
},
// 二. 应用 被用户看到
onShow(){
// 对应用的数据或者页面效果 重置
console.log("onShow")
},
// 三. 应用 被隐藏了
onHide(){
// 暂停或清除定时器
console.log("onHide")
},
// 四. 应用的代码发生了报错的时候,就会触发
onError(err){
// 在应用发生代码错误的时候,收集用户的错误信息,通过异步请求,将错误的信息发送后台去
console.log("onError")
console.log(err)
},
// 五. 页面找不到就会触发
// 应用第一次启动的时候,如果找不到第一个入口页面,才会触发
onPageNotFound(){
// 如果页面不存在了,通过 js 的方式来重新跳转页面,重新跳到第二个页面
// 不能跳到 tabbar 页面,导航组件类似
// 找到微信开发者工具上方正中间的位置,会看到 "普通编译",点击找到 "添加编译模式",模式名称自定义,
// 启动页面写一个不存在的,为了测试,然后确定,就可以测试下面这个找不到跳转到指定页面了
wx.navigateTo({
url:'/pages/work8/work8'
})
console.log("onPageNotFound")
}
})
二.2 页面生命周期
表格 :
属性 | 类型 | 说明 |
---|---|---|
data | object | 页面的初始数据 |
onLoad | function | 生命周期回调—监听页面加载 |
onShow | function | 生命周期回调—监听页面显示 |
onReady | function | 生命周期回调—监听页面初次渲染完成 |
onHide | function | 生命周期回调—监听页面隐藏 |
onUnload | function | 生命周期回调—监听页面卸载 |
onPullDownRefresh | function | 监听用户下拉动作 |
onReachBottom | function | 页面上拉触底事件的处理函数 |
onShareAppMessage | function | 用户点击右上角转发 |
onPageScroll | function | 页面滚动触发事件的处理函数 |
onResize | function | 页面尺寸改变时触发 |
onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 |
测试及注意点 :
app.json 中添加一个 tabbar,后面测试点击 tabbar 的
{
"pagePath": "pages/work15/work15",
"text": "我的",
"iconPath": "icon/_search.png",
"selectedIconPath": "icon/search.png"
}
页面.js
// pages/work15/work15.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// console.log("onLoad")
// onLoad 发送异步请求来初始化页面数据
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
// console.log("onShow")
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
// console.log("onReady")
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
// console.log("onHide")
},
/**
* 生命周期函数--监听页面卸载 也是可以通过点击超链接来演示
*/
onUnload: function () {
// console.log("onUnload")
},
/**
* 页面相关事件处理函数--监听用户下拉动作
* 我们之前写过这个下拉刷新的配置,所以这里直接输出
*/
onPullDownRefresh: function () {
// console.log("onPullDownRefresh")
// 页面的数据 或者效果 重新 刷新
},
/**
* 页面上拉触底事件的处理函数
* 需要让页面 出现上下滚动才行
*/
onReachBottom: function () {
// console.log("onReachBottom")
// 上拉加载下一页数据
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
// console.log("onShareAppMessage")
// 点击小程序的右上角 "···" 转发,就会在调试台触发
},
// 后面这三个生命周期函数是我们自己手动添加的
// 页面滚动就会触发
onPageScroll:function(){
// console.log("onPageScroll")
},
// 页面的尺寸发生改变的时候,触发
// 小程序 发生了 横屏竖屏 切换的时候就会触发
// 在 页面.json 中添加配置 { "pageOrientation":"auto" }
// 点击小程序页面上边有一个 "旋转按钮",点击就可以在调试台看到输出了
// 但是我的在开发工具里面不能输出,在手机上预览就可以实现了
onResize:function(){
// console.log("onResize")
},
// 1. 点击 tabbar 就会触发,必须是当前页面
// 2. 点击的是自己的 tab item 才会出发
onTabItemTap:function(){
// console.log("onTabItemTap")
}
})
页面.wxml
<!--pages/work15/work15.wxml-->
<!-- 为了测试 onHide 才写的这个,当我们点击跳转时, "onHide" 在调试台就显示出来了 -->
<navigator url="/pages/work14/work14" open-type="navigate">
work14
</navigator>
<!-- 为了测试 onUnload 才写的这个,当我们点击跳转时, "onUnload" 在调试台就显示出来了 关闭当前页面也就意味着卸载了页面-->
<navigator url="/pages/work14/work14" open-type="redirect">
work14 redirect
</navigator>
<!-- 这里为了测试屏幕上拉,通过标签来顶出来 可以使用快捷方式 view{$}*25 会直接输出 25 个标签 -->
<view>1</view>
<view>2</view>
<view>3</view>
<view>4</view>
<view>5</view>
<view>6</view>
<view>7</view>
<view>8</view>
<view>9</view>
<view>10</view>
<view>11</view>
<view>12</view>
<view>13</view>
<view>14</view>
<view>15</view>
<view>16</view>
<view>17</view>
<view>18</view>
<view>19</view>
<view>20</view>
<view>21</view>
<view>22</view>
<view>23</view>
<view>24</view>
<view>25</view>
二.3 页面生命周期图解
三、补充
生命周期就是一些事件,只不过它触发的时机不是我们来定义的,而是应用或者程序自己来定义的
四、总结
如果你能看到这里,那么屏幕前的你毅力也是很强大.小程序的基本使用我们就结束了.在这四天中,每天都有不一样的收获和体验.也希望我的博客内容对你们有所帮助,也是对我最大的支持了!