微信小程序自定义组件介绍
自定义组件发开文档
类似vue
或者react
中的自定义组件, 小程序允许我们使用自定义组件的方式来构建页面.
自定义组件的使用
1. 创建组件(js,json,wxml,wxss)
2. 在父组件 json
文件中 注册组件
"usingComponents": {
"cell":"/components/cell/cell",
}
}
3. 使用组件
<cell ></cell>
组件的样式
1. 隔离样式(默认页面与组件的样式是相互隔离的)
//在子组件cell.js 允许样式隔离
options:{
// 样式隔离:apply-shared 父影响子,shared父子相互影响,
//isolated相互隔离
styleIsolation:"isolated",
},
2. 外部类
- 01 在子组件
cell.js
定义外部类
externalClasses:["cell-class"],
- 02 在子组件
cell.wxml
使用外部类
<view class="cell cell-class" > 我是组件里的cell</view>
- 03 在父组件页面
com.wxml
使用外部类
<cell cell-class="mycell"></cell>
- 04 在父组件页面
com.wxss
设置外部类的样式
.mycell{
line-height: 120rpx !important;
color: #f70;
}
完整图片代码
自定义组件插槽
1.默认插槽(text)
- 01 在父组件–页面
com.wxml
中定义默认插槽
<cell>
<text>鸡蛋50倍</text>
</cell>
- 02 在子组件–
cell.wxml
中接收插槽内容(slot)
<view class="cell cell-class" >
我是组件里的cell-
<slot></slot>
</view>
图片完整代码
2.命名插槽
- 01 在父组件–页面
com.wxml
中定义命名插槽
<cell>
<text slot="prv">😋</text>
<text slot="next">🎉</text>
</cell>
- 02 在子组件–
cell.js
中 设置允许多个插槽
options:{
//允许多个插槽
multipleSlots:true,
},
- 03 在子组件–
cell.wxml
中接收命名插槽内容
<view class="cell cell-class" >
<slot name="prv"></slot>
<slot name="next"></slot>
</view>
组件传参
1. 父传子
- 01在父组件-
com.wxml
定义组件的属性(title/num)
<cell title="中美两国和平相处" num="{{2}}"></cell>
- 02 在子组件
cell.js
接收父组件的属性并定义
properties: {
title:{
type:String,
value:""
},
num:{
// 定义类型
type:Number,
// 定义默认值
value:1
}
},
- 03 在子组件
cell.wxml
使用父组件传过来的参
<view class="cell">
<text>{{title}}</text>
<text>{{num}}</text>
</view>
2. 子传父
- 01 在子组件
cell.js
定义data
自己的数据
data: {
count:1
},
- 02 在子组件
cell.js
生命周期attached
挂载更新count
lifetimes:{
attached(){
console.log(this.data)
// count的值为父组件传递的num值
this.setData({count:this.data.num})
}
},
- 03 在子组件
cell.js
定义组件方法
methods: {
tapHd(){
this.setData({count:this.data.count+1})
}
}
- 04 在子组件页面
cell.wxml
绑定单击事件并使用在子组件定义的数据data
<view class="cell" bindtap="tapHd">
<text>{{title}}</text>
<text>{{count}}</text>
</view>
自定义组件js文件中Components
里面的参数
1. 生命周期 lifetime
attach
组件的挂载
2. data
数据
3. methods
方法
4. properties
属性(只读)
5. externalClasses
外部类
6. options
选项
multipleSlots
多个插槽
//允许多个插槽
multipleSlots:true
styleIsolation
(默认样式隔离)
styleIsolation:"isolated", 样式隔离
// 样式隔离:apply-shared 父影响子,shared父子相互影响,
// isolated相互隔离
接下来是两个自定义组件
item
nav
案例分享
item
组件效果图
- 父组件
com.wxml
代码
//wxml代码
<item title="支付" icon="/images/icon01.png"></item>
<item title="相册" icon="/images/icon02.png"></item>
<item title="支付" ></item>
<item title="消息" icon="/images/icon02.png" badge="{{true}}" tip="3条未读"></item>
<item title="消息" icon="/images/icon02.png" badge="{{12}}" tip="12条未读"></item>
<item title="消息" icon="/images/icon02.png" showrslot="{{true}}">
<switch checked="true" slot="right"></switch>
</item>
<item>
<view slot="title">插槽title</view>
</item>
<item title="新闻" icon="/images/icon02.png" url="/pages/yidian/yidian" open-type="switchTab">
</item>
<item title="首页" icon="/images/icon02.png" url="/pages/home/home" >
</item>
<item title="消息" icon="/images/icon02.png" showrslot="{{true}}" itemclass="myitem">
<switch checked="true" slot="right"></switch>
</item>
- 父组件
com.js
代码
// pages/com/com.js
Page({
/**
* 页面的初始数据
*/
data: {
},
cellHd(e){
console.log(e);
wx.showToast({
title: '你点击了'+e.detail,
})
},
- 父组件
com.wxss
代码
/* pages/com/com.wxss */
.title{
line-height: 88rpx;
background-color: #f0f0f0;
padding: 0 15rpx;
}
.cell{
color:red;
}
.mycell{
line-height: 120rpx !important;
color:#F70;
}
.myitem{
line-height: 200rpx !important;
background-color: #F0f0f0;
}
- 父组件
com.json
代码
{
"usingComponents": {
"cell":"/components/cell/cell",
"item":"/components/item/item"
}
}
- 子组件
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>
<!--
icon 图标
conent 内容
title 标题
right 右侧
tip 提示
badge 红点
arrow 箭头
-->
- 子组件
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;
}
- 子组件
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.json
{
"component": true,
"usingComponents": {}
}
nav
自定义导航栏组件
nav
效果图
- 父组件
navpa.wxml
<nav title="你好渐变标题" color="#fff"></nav>
<image src="https://p.qqan.com/up/2022-10/202210111338422888.jpg"></image>
- 父组件
navpa.json
{
"usingComponents": {
"nav":"/components/nav/nav"
},
"navigationStyle":"custom"
}
- 子组件
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>
- 子组件
nav.wxss
/* components/nav/nav.wxss */
.nav{
background-image: linear-gradient(90deg, rgb(96, 197, 236), rgb(37, 125, 197));
position: sticky;
}
.nav .bar{
box-sizing: border-box;
padding: 0 7px;
display: flex;
align-items: center;
}
.btn{display: flex; align-items: center;}
.btn>view{
height: 40px;
width: 40px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.btn image{
height: 22px;
width: 22px;
align-items: center;
}
.btn .back { border-right: 1rpx solid rgba(255,255,255,.5); height: 22px;}
- 子组件
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()
console.log(res);
// 标题栏可以使用的宽度(排除右侧胶囊的位置)
this.setData({titleWidth:res.left});
// 标题栏高度
var barHeight = res.height+(res.top-info.statusBarHeight)*2;
this.setData({barHeight});
// 获取当前页
var pages = getCurrentPages();
console.log(pages);
//更新页面的长度
this.setData({pagesLen:pages.length})
}
},
/**
* 组件的方法列表
*/
methods: {
goBack(){
wx.navigateBack()
},
goHome(){
wx.navigateBack({
// 返回历史的长度为总页面数
delta: this.data.pagesLen,
})
}
}
})
- 子组件
nav.json
{
"component": true,
"usingComponents": {}
}
end…
下期见。。。