由于項目開發(fā)需求,坑爹的小程序沒有自定義dialog(類似餓了么組件那種)。于是百度了下思路,開發(fā)了一個。
title 標(biāo)題 cancelText 取消文本 (默認(rèn)文本為取消) confirmText 確認(rèn)文本(默認(rèn)文本為確定) animated 是否動畫 (默認(rèn)為是) modalSize 模態(tài)框大小(默認(rèn)md) animationOption 動畫事件(默認(rèn)300s)
接下來分享下實現(xiàn)步驟吧...主要的概念就是想把自定義的部分通過插槽來接收。
1、創(chuàng)建好components組件且命好名字。 小tips:在微信開發(fā)工具內(nèi)創(chuàng)建方便點它會自動幫你把相關(guān)文件配好。
創(chuàng)建組件且命名
2、寫好相關(guān)布局及樣式。
dialog.wxss
/** 模態(tài) **/
.modal{
position: fixed;
top: 0rpx;
left: 0rpx;
right: 0rpx;
bottom: 0rpx;
width: 100%;
height: 100%;
z-index: 100;
}
.modal-mask{
position: absolute;
width: 100%;
height: 100%;
z-index: 97;
background-color: rgba(0,0,0,0.30);
}
.modal-layer-sm{
width: 60%;
transform : translate3d(-50%,-50%,0);
left : 50%;
}
.modal-layer-md{
width: 80%;
transform : translate3d(-50%,-50%,0);
left : 50%;
}
.modal-layer-full{
width: 100%;
left: 0;
}
.modal-layer{
position: absolute;
background: transparent;
top: 50%;
display: flex;
flex-direction: column;
z-index: 98;
box-shadow: 0 4rpx 14rpx rgba(0,0,0,.4);
}
.modal-header{
background: #fff;
color: #333;
padding: 20rpx;
font-size: 30rpx;
text-align: center;
border-top-left-radius: 10rpx;
border-top-right-radius: 10rpx;
}
.modal-body{
flex: 1;
padding: 0 40px 40rpx;
background: #ffffff;
}
.modal-footer{
background: #ffffff;
flex-direction: row;
display: flex;
align-items: center;
width: 100%;
border-top : 1rpx solid #eee;
border-bottom-left-radius: 10rpx;
border-bottom-right-radius: 10rpx;
}
.modal-close{
color: #fff;
font-size: 48rpx;
position: absolute;
right: 40rpx;
top: 0;
z-index: 98;
}
.btn{
flex: 1;
text-align: center;
font-size: 30rpx;
color:#666;
padding: 19rpx 5rpx;
}
.btn:first-child{
border-right: 1px solid #eee;
}
.btn-primary{
color: #009887;
}
dialog.wxml
<view animation="{{animationData}}" hidden="{{!isShow}}" class='modal'>
<view data-type="mask" catchtap='hideModal' class='modal-mask' ></view>
<view class='modal-layer modal-layer-radius {{modalSize == "sm" ? " modal-layer-sm" : " modal-layer-md" }} ' >
<!-- 頭部 -->
<view class='modal-header'>
<text>{{title}}</text>
</view>
<!-- 內(nèi)容區(qū)域 -->
<view class='modal-body'>
<slot></slot>
</view>
<view class='modal-footer'>
<text catchtap='_cancelModal' class='btn btn-default'>{{cancelText}}</text>
<text catchtap='_confirmModal' class='btn btn-primary'>{{confirmText}}</text>
</view>
</view>
</view>
dialog.js
// common/component/modal.js
Component({
/**
* 組件的屬性列表
*/
properties: {
title : {
type : String,
value : '這里是默認(rèn)標(biāo)題'
},
cancelText : {
type: String,
value: '取消'
},
confirmText : {
type: String,
value: '確定'
},
backdrop: {
type: Boolean,
value: true
},
animated : {
type: Boolean,
value: true
},
//模態(tài)框大小(sm md)
modalSize : {
type: String,
value: "md"
},
//動畫時間(默認(rèn)300)
animationOption : {
type : Object,
value : {
duration : 300
}
},
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
isShow:false,
animation : ''
},
ready: function () {
this.animation = wx.createAnimation({
duration: this.data.animationOption.duration,
timingFunction: "linear",
delay: 0
});
},
/**
* 組件的方法列表
*/
methods: {
//modal隱藏
hideModal : function(e){
if(e){
let type = e.currentTarget.dataset.type;
if (type == 'mask' && !this.data.backdrop) {
return;
}
}
if (this.data.isShow) this._toggleModal();
},
//modal顯示
showModal: function(){
if (!this.data.isShow) {
this._toggleModal();
}
},
//切換modal的顯示還是隱藏
_toggleModal:function(){
if(!this.data.animated){
this.setData({
isShow: !this.data.isShow
})
}
else{
let isShow = !this.data.isShow;
this._executeAnimation(isShow);
}
},
//根據(jù)需求執(zhí)行動畫
_executeAnimation: function (isShow) {
let animation = this.animation;
if (isShow) {
animation.opacity(0).step();
this.setData({
animationData: animation.export(),
isShow: true
})
setTimeout(function () {
animation.opacity(1).step()
this.setData({
animationData: animation.export()
})
}.bind(this), 50)
}
else {
animation.opacity(0).step()
this.setData({
animationData: animation.export()
})
setTimeout(function () {
this.setData({
isShow: isShow
})
}.bind(this), this.data.animationOption.duration)
}
},
//取消事件 向外部page 發(fā)送事件通知
_cancelModal : function(){
this.hideModal();
this.triggerEvent("cancelEvent");
},
//確認(rèn)事件
_confirmModal : function(){
this.triggerEvent("confirmEvent");
}
}
})
核心都在這叻~注釋都有哦。
分析下怎么做到自定義彈層吧。

slot圖
通過slot圖所示,從圖中可以知道通過slot插槽來接受modal-body里頭自定義的代碼。因為這里只需要一個插槽,所以插槽的名字可以省略,會自動配上。如果是需要多個slot的話,記得為插槽加上name="xxx"屬性命名哦,對應(yīng)的視圖塊通過 slot="xxx"接受對應(yīng)的插槽數(shù)據(jù)。
js部分
需用在頁面渲染的時候獲取組件
onReady: function () {
this.Modal = this.selectComponent("#modal");
},
取消按鈕以及確定按鈕的回調(diào)事件
_cancelEvent : function(){
console.log("點擊取消!");
}
_confirmEventFirst : function(){
console.log("點擊確定了!");
this.Modal.hideModal();
}
控制modal顯示和隱藏
this.Modal.showModal();//顯示 this.Modal.hideModal(); //隱藏
好了展示下效果唄~

效果圖.png
對了。標(biāo)題這塊以及按鈕塊都可以根據(jù)自己的需求再做調(diào)整哦。
樣式也可以調(diào)整。
路過的小伙伴給下star哦~