<view hidden="{{!isShow}}" class='modal' catchtouchmove="preventTouchMove">
<view data-type="mask" catchtap='_cancelModal' class='modal-mask'></view>
<view animation="{{animationData}}" class='modal-layer modal-layer-{{layout}}'>
<!-- 头部 -->
<view class='modal-header' wx:if="{{header}}">
<text>{{title}}</text>
</view>
<!-- 内容区域 -->
<view class='modal-body'>
<slot></slot>
</view>
<view class='modal-footer' wx:if="{{footer}}">
<button class='btn btn-cancel' catchtap='_cancelModal' wx:if="{{isCancelShow}}">{{cancelText}}</button>
<button class='btn btn-confirm' catchtap='_confirmModal'>{{confirmText}}</button>
</view>
</view>
</view>
// components/modal/index.js
Component({
/**
* 组件的属性列表
*/
properties: {
layout: {
type: String,
value: 'top'
},
header: {
type: Boolean,
value: true
},
footer: {
type: Boolean,
value: true
},
title: {
type: String,
value: ''
},
isCancelShow: {
type: Boolean,
value: true
},
cancelText: {
type: String,
value: '取消'
},
confirmText: {
type: String,
value: '确定'
},
backdrop: {
type: Boolean,
value: true
},
animated: {
type: Boolean,
value: true
},
//模态框大小(sm md)
modalSize: {
type: String,
value: "md"
},
//动画时间(默认300)
animationOption: {
type: Object,
value: {
duration: 300
}
},
},
options: {
styleIsolation: 'apply-shared'
},
/**
* 组件的初始数据
*/
data: {
isShow: false,
animation: ''
},
ready: function() {
this.animation = wx.createAnimation({
duration: this.data.animationOption.duration,
timingFunction: "linear",
delay: 0
});
},
pageLifetimes: {
show: function() {
},
hide: function() {
// 页面被隐藏
this.hideModal()
},
resize: function(size) {
// 页面尺寸变化
}
},
/**
* 组件的方法列表
*/
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);
}
},
//根据需求执行动画
_executeAnimation: function(isShow) {
let animation = this.animation;
if (isShow) {
switch (this.data.layout) {
case 'top' :
animation.translateY(-200).step();
break;
case 'center':
animation.translateY('-50%').step();
break;
case 'bottom':
animation.translateY(200).step();
break;
}
this.setData({
animationData: animation.export(),
isShow: true
})
setTimeout(function() {
switch (this.data.layout) {
case 'top':
animation.translateY(0).step();
break;
case 'center':
animation.translateY(0).step();
break;
case 'bottom':
animation.translateY(0).step();
break;
}
this.setData({
animationData: animation.export()
})
}.bind(this), 50)
} else {
switch (this.data.layout) {
case 'top':
animation.translateY(-200).step();
break;
case 'center':
animation.translateY('-50%').step();
break;
case 'bottom':
animation.translateY(200).step();
break;
}
this.setData({
animationData: animation.export()
})
setTimeout(function() {
this.setData({
isShow: isShow
})
}.bind(this), this.data.animationOption.duration)
}
},
//取消事件 向外部page 发送事件通知
_cancelModal: function() {
this.hideModal();
this.triggerEvent("cancel");
},
//确认事件
_confirmModal: function() {
this.triggerEvent("confirm");
},
preventTouchMove() {}
}
})
/* components/modal/index.wxss */
.modal {
position: fixed;
/* top: 45px; */
top: 0;
left: 0rpx;
right: 0rpx;
bottom: 0rpx;
width: 100%;
height: 100%;
z-index: 1000;
}
.modal-mask {
position: absolute;
width: 100%;
height: 100%;
z-index: 997;
background-color: rgba(0, 0, 0, 0.30);
}
.modal-layer {
position: absolute;
background: transparent;
display: flex;
flex-direction: column;
z-index: 998;
}
.modal-layer-top {
top: 90rpx;
width: 100%;
height: 564rpx;
}
.modal-layer-center {
top: 25%;
width: 80%;
left: 10%;
}
.modal-layer-bottom {
bottom: 0;
width: 100%;
height: 564rpx;
}
.modal-header {
background: #fff;
text-align: center;
font-size: 14px;
font-weight: 400;
color: rgba(64, 64, 64, 1);
line-height: 40rpx;
min-height: 112rpx;
display: flex;
align-items: center;
justify-content: center;
}
.modal-body {
flex: 1;
background: #ffffff;
padding: 0 56rpx;
}
.modal-footer {
background: #ffffff;
flex-direction: row;
display: flex;
align-items: center;
width: 100%;
border-top: 1rpx solid #eee;
min-height: 120rpx;
}
.modal-close {
color: #fff;
font-size: 48rpx;
position: absolute;
right: 40rpx;
top: 0;
z-index: 98;
}
.btn {
flex: 1;
text-align: center;
border-radius: 40rpx;
font-size: 15px;
font-weight: 400;
margin-left: 40rpx;
}
.btn-cancel {
color: rgba(102, 102, 102, 1);
border: 1px solid rgba(153, 153, 153, 1);
}
.btn-confirm {
background-color: #1FC8CF;
color: #fff;
}
.btn:last-child {
margin-right: 40rpx;
}
button {
background: inherit;
border: none;
margin: 0;
}
button:after {
border-radius: 0rpx;
border: none;
}
github