介绍
开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。
创建
1.在根目录下创建components文件夹
2.新建一个component
使用
在自定义组件的 js 文件中,需要使用 Component() 来注册组件,并提供组件的属性定义、内部数据和自定义方法。组件的属性值和内部数据将被用于组件 wxml 的渲染,其中,属性值是可由组件外部传入的。例如:
Component({
properties: {
innerText: {
type: String,
value: 'default value',
}
},
data: {
someData: {}
},
methods: {
customMethod: function(){}
}
})
使用组件需要在需要用到的页面的json文件中添加组件的路径,如
json文件配置完成后,就要在wxml文件中使用,使用方法类似于vue组件。如:
应用
组件模板样式
组件默认只有一个插槽,如果你需要多个插槽的话,就要在该js文件中配置,在options对象中添加multipleSlots:true
多个插槽用name值区分
在页面中使用则是用slot=”插槽name值“来使用
组件的样式默认是为样式隔离的,这就是说你在组件定义好的样式,是可以通过类的方式进行修改的,当然样式选项不止样式隔离一种。如:
Component({
options: {
styleIsolation: 'isolated'
}
})
isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
外部类的定义使用
定义外部类之前需要在js文件中配置externalClasses:[“itemclass”],属性,在wxml文件中定义元素的类
组件的生命周期
1.组件实例刚刚被创建好时, created 生命周期被触发。
2.在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。
3.在组件离开页面节点树后, detached 生命周期被触发。
Component({
lifetimes: {
created: function() {
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
})
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义。
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
简易组件的代码示例
自定义顶部栏
nav.js
// components/nav/nav.js
Component({
/**
* 组件的属性列表
*/
properties: {
"title":{
type:"string",
value:""
},
"color":{
type:"string",
value:"#fff"
}
},
/**
* 组件的初始数据
*/
data: {
statusBarHeight:20,
barHeight:44,
pagesLen:0,
},
lifetimes:{
attached(){
var info = wx.getSystemInfoSync();
console.log(info);
this.setData({statusBarHeight:info.statusBarHeight})
const res = wx.getMenuButtonBoundingClientRect()
this.setData({titleWidth:res.left});
var barHeight = res.height+(res.top-info.statusBarHeight)*2;
this.setData({barHeight});
var pages = getCurrentPages();
this.setData({pagesLen:pages.length})
}
},
/**
* 组件的方法列表
*/
methods: {
goBack(){
wx.navigateBack()
},
goHome(){
wx.navigateBack({
delta: this.data.pagesLen,
})
}
}
})
nav.wxml
<!--components/nav/nav.wxml-->
<view class="nav" style="padding-top: {{statusBarHeight}}px; height: {{barHeight}}px;">
<view class="bar" style="width: {{titleWidth}}px; height: {{barHeight}}px; color: {{color}};">
<view class="btn">
<view class="back" wx:if="{{pagesLen>1}}" bindtap="goBack" ><image src="./images/back.svg" mode="aspectFill"></image></view>
<view class="home" bindtap="goHome"><image src="./images/home.svg" mode="aspectFit"></image></view>
</view>
{{title}} {{pagesLen}}
</view>
</view>
自定义我的页面
item.js
// components/item/item.js
Component({
options:{
multipleSlots:true
},
externalClasses:["itemclass"],
/**
* 组件的属性列表
*/
properties: {
// 标题
title:{
type:String,
value:""
},
// 显示右侧插槽
showrslot:{
type:Boolean,
value:false,
},
// 图标
icon:{
type:String,
value:""
},
tip:{
type:String,
value:"",
},
badge:{
type:[Boolean,Number],
value:false
},
url:{
type:String,
value:""
},
openType:{
type:String,
value:"navigate"
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
itemclick(e){
console.log(e);
//发送一个事件
this.triggerEvent("itemclick",e.detail)
}
}
})
item.wxml
<navigator class="item itemclass" url="{{url}}" open-type="{{openType}}" bindtap="itemclick">
<view class="icon" wx:if="{{icon}}">
<image src="{{icon}}" mode="aspectFill"></image>
</view>
<view class="content">
<view class="title">
<view class="title" wx:if="{{title}}">{{title}}</view>
<slot name="title" wx:else ></slot>
</view>
<view class="right" wx:if="{{!showrslot}}">
<view class="tip">{{tip}}</view>
<view class="badge" wx:if="{{badge}}">
<view wx:if="{{badge===true}}" class="dot">
</view>
<view wx:else class="redbadeg">
{{badge}}
</view>
</view>
<view class="arrow"></view>
</view>
<slot name="right" wx:else></slot>
</view>
</navigator>
item.wxss
/* components/item/item.wxss */
.item{
line-height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.icon{
margin-left: 30rpx;
margin-right: 30rpx;
height: 100%;
display: flex;
align-items: center;
}
.icon image{
width: 60rpx;
height: 60rpx;
}
.content{
padding: 0 30rpx;
border-bottom: 1rpx solid #ccc;
display: flex;
flex:1;
}
.title{
flex:1;
color:#333;
font-size: 32rpx;
}
.right{
display: flex;
align-items: center;
}
.right .arrow{
height: 30rpx;
width: 30rpx;
border-top:3rpx solid #999;
border-right: 3rpx solid #999;
transform: rotate(45deg);
}
.tip{
color:#999;
font-size: 24rpx;
}
.dot{
height: 14rpx;
width: 14rpx;
background-color: #f00;
border-radius: 12rpx;
margin-left: 15rpx;
}
.redbadeg{
font-size: 18rpx;
color:#fff;
border-radius: 18rpx;
background-color: #f00;
max-height: 30rpx;
width: 30rpx;
line-height: 30rpx;
text-align: center;
margin-left: 15rpx;
}