由于原生模态窗口只提供显示消息,无法进行数据交互,故自定义了一个模态窗口组件,可以看看下面代码示例与讲解:
<template>
<view :id="[popupId?'wmjpopupWrapper'+popupId:'']" class="wmj-popup-wrapper" :class="popupClass" :style="[popupStyles]">
<view class="wmj-popup-content" :class="popupContentClass" :style="[{height:height,width:width}]">
<slot></slot>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text">{{title}}</text>
</view>
<view class="uni-dialog-content">
<view class="line">
<view class='lineLeft'>{{labelTxt_1}}:</view>
<view class="lineRight">
<text class="uni-dialog-title-text">{{objTxt}}</text>
<text class="uni-dialog-title-text" v-if="false">{{objID}}</text>
</view>
</view>
<view class="line">
<view class='lineLeft'>{{labelTxt_2}}:</view>
<view class="lineRight">
<picker mode="date" :value="date" :start="startDate" :end="endDate" @change="bindDateChange">
<view class="uni-input">{{date}}</view>
</picker>
</view>
</view>
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="close">
<text class="uni-dialog-button-text">取消</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">确定</text>
</view>
</view>
</view>
</view>
<view v-if="maskShow" class="wmj-popup-mask" :class="popupMaskClass" @tap="close(maskClick)"></view>
</view>
</template>
<script>
export default {
name: "wmj-popup-wrapper",
props: {
objID: {
type: String,
default: ''
},
title: {
type: String,
default: '提示'
},
objTxt: {
type: String,
default: 'wmj'
},
labelTxt_1: {
type: String,
default: 'wmj'
},
labelTxt_2: {
type: String,
default: 'wmj'
},
type: {
type: String,
default: "center" // left right top bottom center
},
transition: {
type: String,
default: "none" //none slider fade
},
active: {
type: Boolean,
default: false
},
height: {
type: [String],
default: "100%"
},
width: {
type: [String],
default: "100%"
},
top: {
type: [String],
default: "0"
},
bottom: {
type: [String],
default: "0"
},
left: {
type: [String],
default: "0"
},
right: {
type: [String],
default: "0"
},
popupId: {
type: [String, Number],
default: 0
},
maskShow: {
type: Boolean,
default: true
},
maskClick: {
type: Boolean,
default: true
},
closeCallback: {
type: Function,
},
oKCallback: {
type: Function,
},
},
data() {
const currentDate = this.getDate({
format: true
})
return {
newActive: this.active,
newTransition: true,
date: this.objID==''? currentDate : this.objID,
};
},
computed: {
startDate() {
return this.getDate('start');
},
endDate() {
return this.getDate('end');
},
popupClass: function() {
let _class = "";
if (this.newActive) {
_class += "wmj-popup-active";
}
let arrType = ["left", "right", "top", "bottom", "center"];
if (arrType.indexOf(this.type) !== -1 && this.type !== 'center') {
_class += " wmj-popup-" + this.type;
}
return _class;
},
popupStyles: function() {
const patt = /(%|in|cm|mm|em|pt|pc|px|vw|vh)$/i;
const testTop = patt.test(this.top);
const testBottom = patt.test(this.bottom);
const testLeft = patt.test(this.left);
const testRight = patt.test(this.right);
let width = 'calc(100%';
width += testLeft ? ' - ' + this.left : '';
width += testRight ? ' - ' + this.right : '';
width += ')';
let height = 'calc(100%';
height += testTop ? ' - ' + this.top : '';
height += testBottom ? ' - ' + this.bottom : '';
height += ')';
let _style = {};
if (testLeft || testRight) {
_style.width = width
};
if (testTop || testBottom) {
_style.height = height
};
if (testTop) {
_style.top = this.top
};
if (testBottom) {
_style.bottom = this.bottom
};
if (testLeft) {
_style.left = this.left
};
if (testRight) {
_style.right = this.right
};
return _style;
},
popupContentClass: function() {
let _class = "";
let arrTransition = ["none", "slider", "fade"];
if (!!this.newTransition && arrTransition.indexOf(this.transition) !== -1 && this.transition !== 'none') {
_class += "wmj-popup-transition-" + this.transition;
}
return _class;
},
popupMaskClass: function() {
let _class = "";
if (!!this.newTransition) {
_class += "wmj-popup-mask-fade";
}
return _class;
}
},
methods: {
bindDateChange: function(e) {
this.date = e.target.value
},
getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
show: function() {
this.newActive = true;
let _this = this;
setTimeout(function() {
_this.newTransition = false;
}, 50)
},
close: function(v) {
let close = v == false ? false : true;
if (close) {
this.newTransition = true;
let _this = this;
setTimeout(function() {
_this.newActive = false;
if (typeof(_this.closeCallback) == "function") {
_this.closeCallback();
}
}, 300)
}
},
onOk: function() {
console.log(this.objID);
if (this.objID != "" || this.objID != undefined) {
var endDate = new Date(this.objID);
var _Date = new Date(this.date);
if (_Date <= endDate) {
uni.showToast({
icon: "none",
title: "续权日期不可小于到期时间",
duration: 1500
})
return;
}
}
this.$emit("oKCallback", this.date);
this.newActive = false;
}
}
}
</script>
<style lang="scss" scoped>
wmj-popup-wrapper {
position: absolute;
width: 300px;
border-radius: 5px;
background-color: #f9f9f9;
}
.wmj-popup-wrapper {
position: fixed;
// z-index: 998;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
display: none;
overflow: hidden;
&.wmj-popup-active {
display: flex;
}
&.wmj-popup-left {
justify-content: flex-start;
.wmj-popup-transition-slider {
transform: translate3d(-100%, 0, 0);
}
}
&.wmj-popup-right {
justify-content: flex-end;
.wmj-popup-transition-slider {
transform: translate3d(100%, 0, 0);
}
}
&.wmj-popup-top {
align-items: flex-start;
.wmj-popup-transition-slider {
transform: translate3d(0, -100%, 0);
}
}
&.wmj-popup-bottom {
align-items: flex-end;
.wmj-popup-transition-slider {
transform: translate3d(0, 100%, 0);
}
}
.wmj-popup-content {
border-radius: 10px;
background-color: #fff;
z-index: 2;
height: 100%;
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
align-content: flex-start;
transform: translate3d(0, 0, 0) scale(1);
opacity: 1;
overflow: hidden;
transition: transform .3s ease-in-out, opacity .3s ease-in-out;
&.wmj-popup-transition-fade {
transform: translate3d(0, 0, 0) scale(0.3);
opacity: 0;
}
}
.wmj-popup-mask {
position: absolute;
z-index: 1;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
width: 100%;
background-color: rgba(#000, 0.5);
transition: background .3s ease-in-out;
&.wmj-popup-mask-fade {
background-color: rgba(#000, 0);
}
}
.uni-popup-dialog {
width: 100%;
height: 100%;
border-radius: 5px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
color: black;
margin-top: 25rpx;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
height: 50%;
//flex-direction: row;
justify-content: center;
align-items: center;
//padding: 15px 15px 15px 15px;
.line {
margin-top: 15rpx;
height: 50rpx;
width: 92%;
//flex-direction: row;
border-bottom: 1px solid #f5f5f5;
font-size: 14px;
margin-left: 15rpx;
display: flex;
.lineRight {
flex: 1;
height: 100%;
width: 70%;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
color: #585858;
}
.lineLeft {
display: flex;
width: 30%;
margin-left: 30rpx;
align-items: center;
height: 100%;
color: #959595;
}
}
}
.uni-dialog-content-text {
font-size: 14px;
color: #585858;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
margin-top: 0rpx;
border-top-color: #e1e1e1;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
height: 30rpx;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-border-left {
border-left-color: #afafaf;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
margin-top: 50rpx;
font-size: 15px;
text-align: center;
}
.uni-button-color {
color: $uni-color-primary;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
}
.uni-popup__success {
color: $uni-color-success;
}
.uni-popup__warn {
color: $uni-color-warning;
}
.uni-popup__error {
color: $uni-color-error;
}
.uni-popup__info {
color: #909399;
}
.uni-popup-dialog__close {
display: block;
cursor: pointer;
position: absolute;
top: 9px;
right: 17px;
}
.uni-popup-dialog__close-icon {
display: inline-block;
width: 13px;
height: 1px;
background: #909399;
transform: rotate(45deg);
}
.uni-popup-dialog__close-icon::after {
content: '';
display: block;
width: 13px;
height: 1px;
background: #909399;
transform: rotate(-90deg);
}
}
</style>
模态窗口组件与JS及CSS示例
上述示例代码定义了文本信息框及日期框,然后通过属性提供给父窗体调用,另外自定义了【取消和确定】按钮,在JS代码里面定义了回调函数供父窗体调用,同时一些基础外观属性一并定义了,方便扩展!
下面看看父窗体调用示例及效果展示:
<wmjPopupWrapper ref="wmjPopupWrapper" :type="type" :transition="transition" :title="popupTitle" :objTxt="objTxt"
:labelTxt_1="labelTxt_1" :labelTxt_2="labelTxt_2" :objID="objID" :active="active" :height="height" :width="width"
:popupId="popupId" :maskShow="maskShow" :maskClick="maskClick" :closeCallback="closeCallback" @oKCallback="oKCallback">
</wmjPopupWrapper>
父窗体调用自定义模态窗口
import wmjPopupWrapper from "@/components/wmj-popup-wrapper/wmj-popup-wrapper.vue"
export default {
components: {
wmjPopupWrapper
},
data() {
return {
type: "center", // left right top bottom center 中间弹出
transition: "none", //none slider fade
active: false, //是否激活
height: "25%", //自定义高度
width: "80%",
popupId: 1, // ID作为唯一区别,亦可作为参数传参到后台
popupTitle: "XXXXXXX", //标题
objTxt: "wmj", //对象文本
labelTxt_1: "序列号",
labelTxt_2: "续权日期",
objID: "",
maskShow: true,
maskClick: true
}
使用具体示例
以上代码开箱即用,希望可以集思广益做好扩展!
(目前窗口显示内容需要提前定义好,如遇到使用其他标签,可能需要重绘界面,个人建议是绘制所有你所需的标签,通过V-IF或CSS和属性定义提供给父窗口决定展示)
差点忘了回调函数:
methods: {
QuickApproval(e) {
this.$refs.wmjPopupWrapper.show();
},
closeCallback: function(v) {
console.log("关闭后回调" + v);
},
oKCallback: function(v) {
uni.request({
url: //你的api,
method: 'POST',
data: {
"date": v,
//其他参数
},
success: (res) => {
console.log(res.data)
}
});