uni-app 自定义模态窗口[支持自定义标签]

由于原生模态窗口只提供显示消息,无法进行数据交互,故自定义了一个模态窗口组件,可以看看下面代码示例与讲解:

<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)
						}
				});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值