起源:一直觉得很有必要自己封装一个弹窗组件,一边实现各种不同产品的需求,但又要注重交互体验,加个缩放动画,一直都没写个好看的,终于,在前几天写了一个我自认为丝滑的,有动画的,弹窗的组件,哈哈哈哈哈哈哈哈哈哈哈哈哈哈
先说下动画
思路的话,我觉得,可能不一样的打就是加动画,这里我用的是css3的animation,遮罩层从rgba(0, 0, 0, 0)到rgba(0, 0, 0, 0.7),弹窗主体采用transform: translate(-50%, -50%) scale(0);到transform: translate(-50%, -50%) scale(1),要注意的是因为弹窗始终要居中,所以我用translate(-50%, -50%)配合了position:absolute;top:50%;left:50%,
关键在动画的消失
因为动画要缩回去,所以要动画的时间,如果世上外面传一个flag来控制的话,显然是不能实现中国需求的,所以我做的是在弹窗里面再写一个flag,当外面传一个flag为true时,里面dialogFlag也为true,显示的时候是外面的触发里面的flag,消失的时候是里面触发外面的即dialogFlag先设置为false,延迟0.3s再将外面的flag设置为false就好了(要是小伙伴有更好的办法解决可以私聊呀),这里需要用到微信的observers(监听事件),它可以监听到外面的flag并设置里面的flag
小程序组件的事件触发
triggerEvent(触发事件),它接收三个参数,triggerEvent(事件名称,参数,事件选项--控制冒泡,捕获)
到这里,差不多就讲完了,下面就是完整代码啦:
wxml:因为有些场景是要盖住地图,或者图片,所以这里我主体采用了cover-view
<!--Component/dialog/dialog.wxml-->
<cover-view wx:if="{{show}}" class="{{dialogFlag?'mask':'mask hideMask'}}" catchtap="close">
<cover-view class="dialog" style="width:{{dialogWidth}}">
<cover-view class="dialog_title" wx:if="{{title}}">{{title}}</cover-view>
<cover-view class="dialog_body" wx:if="{{content}}">{{content}}</cover-view>
<slot></slot>
<cover-view class="dialog_footer">
<cover-view class="dialog_btn" catchtap="close">取消</cover-view>
<cover-view class="dialog_btn dialog_primary" catchtap="confirm">确定</cover-view>
</cover-view>
</cover-view>
</cover-view>
<!-- <dialog title="提示" show="{{show}}" content="这是一个带有动画缩放效果的弹窗" bind:close="onClose"></dialog> -->
wxss:
/* Component/dialog/dialog.wxss */
.mask {
top: 0;
left: 0;
width: 100%;
height: 100%;
position: fixed;
animation: enterMask 0.3s;
background: rgba(0, 0, 0, 0.7);
display: block;
}
.dialog {
padding: 40rpx;
box-sizing: border-box;
background: #ffffff;
border-radius: 20rpx;
position: absolute;
left: 50%;
top: 50%;
animation: enterDialog 0.3s;
transform: translate(-50%, -50%);
}
.hideMask {
animation: leaveMask 0.3s;
display: block;
}
.hideMask .dialog {
transform: translate(-50%, -50%) scale(0);
display: block;
animation: leaveDialog 0.3s;
}
@keyframes enterMask {
from {
background: rgba(0, 0, 0, 0);
display: none;
}
to {
background: rgba(0, 0, 0, 0.7);
display: block;
}
}
@keyframes leaveMask {
from {
background: rgba(0, 0, 0, 0.7);
display: block;
}
to {
background: rgba(0, 0, 0, 0);
display: none;
}
}
@keyframes enterDialog {
from {
/* transform: ; */
transform: translate(-50%, -50%) scale(0);
}
to {
/* transform: ; */
transform: translate(-50%, -50%) scale(1);
}
}
@keyframes leaveDialog {
from {
/* transform: ; */
transform: translate(-50%, -50%) scale(1);
display: block;
}
to {
/* transform: ; */
transform: translate(-50%, -50%) scale(0);
display: none;
}
}
.dialog_title {
font-size: 32rpx;
font-weight: 500;
text-align: center;
color: #333333;
padding: 20rpx 0 40rpx;
}
.dialog_body {
font-size: 24rpx;
font-weight: 400;
color: #666666;
line-height: 33rpx;
margin: 0 auto;
width: 340rpx;
white-space: normal;
text-align: center;
}
.dialog_footer {
display: flex;
padding: 60rpx 50rpx 10rpx;
justify-content: space-between;
}
.dialog_btn {
width: 200rpx;
height: 70rpx;
background: #ffffff;
border: 2rpx solid #009aff;
border-radius: 35rpx;
font-size: 28rpx;
font-weight: 400;
text-align: center;
color: #009aff;
line-height: 70rpx;
}
.dialog_primary {
background: #009AFF;
color: #fff;
}
json:组件的常规配置
{
"component": true,
"usingComponents": {}
}
js:重点,哈哈哈
Component({
/**
* 组件的属性列表 props
*/
properties: {
// 标题
title: {
type: String,
value: ''
},
// 内容
content: {
type: String,
value: ''
},
// 显示-隐藏flag
show:{
type:Boolean,
value:false
},
// 是否显示底部按钮
footer:{
type:Boolean,
value:true
},
// 弹窗的宽度
dialogWidth:{
type: String,
value: '650rpx'
}
},
/**
* 组件的初始数据
*/
data: {
dialogFlag:false//收起、展开mask动画
},
/**
* 组件的方法列表
*/
methods: {
close(){
//
/*
triggerEvent 自定义组件触发事件,triggerEvent('myevent', myEventDetail, myEventOption)
myevent:事件的触发名称
myEventDetail:传递出去的参数
myEventOption:事件选项
{
bubbles Boolean 否 false 事件是否冒泡
composed Boolean 否 false 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
capturePhase Boolean 否 false 事件是否拥有捕获阶段
}
*/
this.setData({
dialogFlag:false
})
setTimeout(()=>{
this.triggerEvent('close')
},300)
},
confirm(){
setTimeout(()=>{
this.triggerEvent('confirm')
},300)
}
},
observers: {
// 监听props,设置dialogFlag
'show': function() {
// console.log(this.properties.show)
if (this.properties.show) {
this.setData({
dialogFlag:true
})
}
}
}
})
到这里就非常nice的结束了,要是有小伙伴有更好的解决方法,可以评论呀