气泡弹窗组件是产品设计中常用的控件之一,以下是对uniapp气泡弹窗组件可视化的详细解析:

一、组件定义

气泡弹窗组件(diy-popover )指的是当触发某项操作时,在页面上方或特定位置展示的弹出层容器,容器内可展示文本、按钮、列表、标签、表单项等内容。组件库代码实现如下.

<template>
	<view v-if="visibleSync" :style="[customStyle, {
		zIndex: uZindex - 1
	}]" class="diy-popover" :class="mask?'mask':''" hover-stop-propagation>
		<u-mask v-if="mask" :blur="blur" :duration="duration" :custom-style="maskCustomStyle" :maskClickAble="maskCloseAble"
			:z-index="uZindex - 2" :show="showDrawer && mask" @click="maskClick"></u-mask>
		<!-- 移除	@tap.stop.prevent -->
		<view class="popover" :class="[
				mask?'':'nomask',
				safeAreaInsetBottom ? 'safe-area-inset-bottom' : '',
				showDrawer ? 'diy-popover-visible' : ''
			]" @touchmove.stop.prevent
			:style="getPositionStyle()" @click="closeByPopover">
			<text :class="['popover-'+diymode,'popover-'+dynPlace]" :style="{width:'0px',height:'0px'}"></text>
			<slot></slot>
			<view class="clearfix"></view>
		</view>
	</view>
</template>

<script>
	/**
	 * popover 汽泡组件
	 * @description 汽泡组件,用于汽泡组件、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义
	 * @property {String} mode 弹出方向(默认left)
	 * @property {Boolean} mask 是否显示遮罩(默认true)
	 * @property {Stringr | Number} length mode=top 
	 * @property {Boolean} zoom 是否开启缩放动画,只在mode为center时有效(默认true)
	 * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
	 * @property {Boolean} mask-close-able 点击遮罩是否可以关闭弹出层(默认true)
	 * @property {Numberr | String} z-index 弹出内容的z-index值(默认1075)
	 * @event {Function} open 弹出层打开
	 * @event {Function} close 弹出层收起
	 */

	export default {
		name: 'diy-popover',
		emits: ["update:modelValue", "input", "open", "close"],
		props: {
			value: {
				type: Boolean,
				default: false
			},
			modelValue: {
				type: Boolean,
				default: false
			},
			/**
			 * 弹出方向,left|right|top|bottom
			 */
			mode: {
				type: String,
				default: 'top-center'
			},
			initType:{
				type: String,
				default: ''
			},
			/**
			 * 是否显示遮罩
			 */
			mask: {
				type: Boolean,
				default: true
			},
			// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
			safeAreaInsetBottom: {
				type: Boolean,
				default: false
			},
			// 是否可以通过点击遮罩进行关闭
			maskCloseAble: {
				type: Boolean,
				default: true
			},
			// 是否可以通过点击内容区进行关闭
			contentCloseAble:{
			  type: Boolean,
			  default: false,
			},
			// 显示显示弹窗的圆角,单位rpx
			borderRadius: {
				type: [Number, String],
				default: 0
			},
			zIndex: {
				type: [Number, String],
				default: ''
			},
			// 背景颜色
			bgcolor: {
				type: String,
				default: '#fff'
			},
			// 点击元素左边坐标
			triggerLeft: {
				type: [String, Number],
				default: 0
			},
			// 点击元素上方坐标
			triggerTop: {
				type: [String, Number],
				default: 0
			},
			// 点击元素高度
			triggerHeight: {
				type: [String, Number],
				default: 12
			},
			// 点击元素宽度
			triggerWidth: {
				type: [String, Number],
				default: 24
			},
			width: {
				type: String,
				default: '200px'
			},
			// 遮罩的样式,一般用于修改遮罩的透明度
			maskCustomStyle: {
				type: Object,
				default () {
					return {
						backgroundColor: 'none'
					}
				}
			},
			// 遮罩打开或收起的动画过渡时间,单位ms
			duration: {
				type: [String, Number],
				default: 250
			},
			// 遮罩的模糊度
			blur: {
				type: [String, Number],
				default: 0
			},

		},
		data() {
			return {
				statusBarHeight:0,
				diymode:this.mode,
				popoverTransform: 'scale(1)',
				popoverTop: '0px',
				popoverLeft: '0px',
				diybgcolor: this.bgcolor ? this.bgcolor : '#fff',
				visibleSync: false,
				showDrawer: false,
				timer: null,
				dynPlace: '',
				closeFromInner: false, // value的值改变,是发生在内部还是外部
			};
		},
		computed: {
			valueCom() {
				// #ifndef VUE3
				return this.value;
				// #endif

				// #ifdef VUE3
				return this.modelValue;
				// #endif
			},
			// 计算整理后的z-index值
			uZindex() {
				return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
			}
		},
		watch: {
			valueCom(val) {
				if (val) {
					this.open();
					this.popoverPosition()
				} else if (!this.closeFromInner) {
					this.close();
				}
				this.closeFromInner = false;
			},
		},
		mounted() {
			if(this.mode.indexOf("-")>0){
				this.diymode = this.mode.substring(0,this.mode.indexOf("-"))
			}else{
				this.diymode = this.mode
			}
			// 组件渲染完成时,检查value是否为true,如果是,弹出popup
			if(this.valueCom){
				this.open()
				this.popoverPosition()
			}
		},
		methods: {
			getPositionStyle(){
				let style = {width:this.width,background:this.diybgcolor,'--arrow-color':this.diybgcolor};
				if(this.initType!=''){
					if(this.initType.indexOf("left") >= 0){
					  style['left'] =  this.triggerLeft+'px'
					}
					if(this.initType.indexOf("right") >= 0){
					  style['right'] = this.triggerLeft+'px'
					}
			
					if(this.initType.indexOf("top") >= 0){
						// #ifdef H5
						style['top'] = (this.statusBarHeight + this.triggerTop) +'px'
						// #endif
						// #ifndef H5
						style['top'] = this.triggerTop +'px'
						// #endif
					}
					if(this.initType.indexOf("bottom") >= 0){
					  style['bottom'] = this.triggerTop+'px'
					}
				}else{
					style['top'] = this.popoverTop
					style['left'] = this.popoverLeft
				}
				return style
			},
			getTopOrBottomPlacement(wrapperwidth) {
				let width = uni.getSystemInfoSync().windowWidth
				//X坐标大于屏幕一半大小且大于屏幕的大小时
				if (this.triggerLeft + this.triggerWidth / 2 + wrapperwidth / 2 - width > 0) {
					return 'right'
				} else if (this.triggerLeft + this.triggerWidth / 2 - wrapperwidth / 2 > 0) {
					return 'center'
				} else {
					return 'left'
				}
			},
			getLeftOrRightPlacement(wrapperHeight) {
				let height = uni.getSystemInfoSync().windowHeight
				if (this.triggerTop + this.triggerHeight / 2 + wrapperHeight / 2 - height > 0) {
					return 'right'
				} else if (this.triggerTop + this.triggerHeight / 2 - wrapperHeight / 2 > 0) {
					return 'center'
				} else {
					return 'left'
				}
			},
			async popoverPosition() {
				let statusBar = await this.getStatusBar()
				statusBar = statusBar||0
				this.statusBarHeight = statusBar||0
				if(this.initType!=''){
					this.dynPlace = this.mode.indexOf("-")>0?this.mode:(this.mode+"-center")
				}else{
					let popoverDom = uni.createSelectorQuery().in(this).select(".popover")
					popoverDom.fields({
						size: true,
					}, (data) => {
						let width = data.width
						let height = data.height
						let y = this.triggerTop + statusBar
						let x = this.triggerLeft
						this.dynPlace = this.mode
						
						if (this.mode == 'top' || this.mode == 'bottom') {
							this.dynPlace = this.mode + "-" + this.getTopOrBottomPlacement(width)
						} else if (this.mode == 'left' || this.mode == 'right') {
							this.dynPlace = this.mode + "-" + this.getLeftOrRightPlacement(height)
						}else {
							this.dynPlace = this.mode
						}
						
						let popoverTop = 0
						let popoverLeft = 0
						switch (this.dynPlace) {
							case 'top-left':
								y = y + this.triggerHeight + 9
								popoverTop = `${y}px`
								x = x - 10
								x = x < 0 ? 2 : x
								popoverLeft = `${x}px`
								this.popoverLeft = popoverLeft
								this.popoverTop = popoverTop
								break;
							case 'top-center':
								y = y + this.triggerHeight
								popoverTop = `${y+9}px`
								x = x + this.triggerWidth / 2 - width / 2
								x = x < 0 ? 2 : x
								popoverLeft = `${x}px`
								this.popoverLeft = popoverLeft
								this.popoverTop = popoverTop
								break;
							case 'top-right':
								y = y + this.triggerHeight
								this.popoverTop = `${y+9}px`
								x = x + this.triggerWidth - width
								this.popoverLeft = `${x}px`
								break;
							case 'top-left':
								this.popoverTop = `${y-12-height}px`
								x = x - 10
								x = x < 0 ? 2 : x
								this.popoverLeft = `${x}px`
								break;
							case 'bottom-center':
								this.popoverTop = `${y-12-height}px`
								x = x + this.triggerWidth / 2 - width / 2
								x = x < 0 ? 2 : x
								popoverLeft = `${x}px`
								this.popoverLeft = popoverLeft
								break;
							case 'bottom-right':
								this.popoverTop = `${y-12-height}px`
								x = x + this.triggerWidth - width
								this.popoverLeft = `${x}px`
								break;
							case 'left-top':
								this.popoverTop = `${y}px`
								this.popoverLeft = `${x -width -15}px`
								break;
							case 'left-center':
								y = y - height / 2 + this.triggerHeight / 2
								this.popoverTop = `${y}px`
								this.popoverLeft = `${x -width -15}px`
								break;
							case 'left-bottom':
								y = y - height + this.triggerHeight + 5
								this.popoverTop = `${y}px`
								this.popoverLeft = `${x - width -15}px`
								break;
							case 'right-top':
								this.popoverTop = `${y}px`
								x = x + this.triggerWidth + 15
								this.popoverLeft = `${x}px`
								break;
							case 'right-center':
								y = y - height / 2 + this.triggerHeight / 2
								this.popoverTop = `${y}px`
								x = x + this.triggerWidth + 15
								this.popoverLeft = `${x}px`
								break;
							case 'right-bottom':
								y = y - height + this.triggerHeight + 5
								this.popoverTop = `${y}px`
								x = x + this.triggerWidth + 15
								this.popoverLeft = `${x}px`
								break;
						}
					}).exec();
				}
				
			},
			getStatusBar() {
				let promise = new Promise((resolve, reject) => {
					uni.getSystemInfo({
						success: function(e) {
							let customBar
							// #ifdef H5
							customBar = e.statusBarHeight + e.windowTop;
							// #endif
							resolve(customBar)
						}
					})
				})
				return promise
			},
			// 判断传入的值,是否带有单位,如果没有,就默认用rpx单位
			getUnitValue(val) {
				if (/(%|px|rpx|auto)$/.test(val)) return val;
				else return val + 'rpx'
			},
			//是否可以通过点击遮罩进行关闭
			closeByPopover(){
				if(this.contentCloseAble){
					this.close();
				}
			},
			// 遮罩被点击
			maskClick() {				
				this.close();
			},
			close() {
				// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close
				// 造成@close事件触发两次
				this.closeFromInner = true;
				this.change('showDrawer', 'visibleSync', false);
			},
			open() {
				this.change('visibleSync', 'showDrawer', true);
			},
			// 此处的原理是,关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件
			// 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用
			change(param1, param2, status) {
				// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
				if (this.popup == true) {
					this.$emit('input', status);
				}
				this.$emit("update:modelValue", status);
				this[param1] = status;
				if (status) {
					// #ifdef H5 || MP
					this.timer = setTimeout(() => {
						this[param2] = status;
						this.$emit(status ? 'open' : 'close');
					}, 50);
					// #endif
					// #ifndef H5 || MP
					this.$nextTick(() => {
						this[param2] = status;
						this.$emit(status ? 'open' : 'close');
					})
					// #endif
				} else {
					this.timer = setTimeout(() => {
						this[param2] = status;
						this.$emit(status ? 'open' : 'close');
					}, this.duration);
				}
			}
		}
	};
</script>

<style scoped lang="scss">
	@import "../../libs/css/style.components.scss";

	.diy-popover {
		/* #ifndef APP-NVUE */
		display: block;
		/* #endif */
		
		&.mask{
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			overflow: hidden;
			bottom: 0;
		}
	}

	.popover {
		position: absolute;
		&.nomask{
			position: fixed;
		}
		padding: 20rpx;
		z-index: 99999999;
		border-radius: 10rpx;
		display: flex;
		transition: opacity .15s, transform .15s;
		box-shadow: 0upx 0upx 30upx rgba(0, 0, 0, 0.2);

		.popover-top:after {
			content: "";
			position: absolute;
			border-width: 0 20rpx 20rpx;
			border-style: solid;
			border-color: transparent transparent var(--arrow-color);
		}

		.popover-top-left:after {
			top: -18rpx;
			left: 10rpx;
		}

		.popover-top-center:after {
			top: -18rpx;
			right: 50%;
			transform: translateX(50%);
		}

		.popover-top-right:after {
			top: -18rpx;
			right: 10rpx;
		}


		.popover-bottom:after {
			content: "";
			position: absolute;
			border-width: 20rpx 20rpx 0;
			border-style: solid;
			border-color: var(--arrow-color) transparent transparent;
		}

		.popover-bottom-left:after {
			bottom: -18rpx;
			left: 10rpx;
		}

		.popover-bottom-center:after {
			bottom: -18rpx;
			right: 50%;
			transform: translateX(50%);
		}

		.popover-bottom-right:after {
			bottom: -18rpx;
			right: 10rpx;
		}

		.popover-left:after {
			content: "";
			position: absolute;
			border-width: 20rpx 0 20rpx 20rpx;
			border-style: solid;
			border-color: transparent transparent transparent var(--arrow-color);
		}

		.popover-left-top:after {
			top: 10rpx;
			right: -18rpx;
		}

		.popover-left-center:after {
			top: 50%;
			right: -18rpx;
			transform: translateY(-50%);
		}

		.popover-left-bottom:after {
			bottom: 10rpx;
			right: -18rpx;
		}

		.popover-right:after {
			content: "";
			position: absolute;
			border-width: 20rpx 20rpx 20rpx 0;
			border-style: solid;
		 border-color: transparent var(--arrow-color) transparent transparent;
		}

		.popover-right-top:after {
			top: 10rpx;
			left: -18rpx;
		}

		.popover-right-center:after {
			top: 50%;
			left: -18rpx;
			transform: translateY(-50%);
		}

		.popover-right-bottom:after {
			bottom: 10rpx;
			left: -18rpx;
		}

	}


	.diy-popover-visible {
		transform: translate3D(0px, 0px, 0px) !important;
	}
</style>

二、分类

根据弹出位置和设计手法的不同,气泡弹窗组件可以分为多种类型,例如模态弹窗和非模态弹窗。模态弹窗采用模态设计手法,将用户之前看到的内容与当前看到的内容进行区分,并需要用户通过明确的操作才能退出该模式。非模态弹窗则相对自由,不会打断用户的正常操作。

三、功能

气泡弹窗组件的主要功能包括:

  1. 告知用户信息:通过弹窗展示重要信息,提醒用户注意。
  2. 提醒用户操作:引导用户进行下一步操作,提高用户参与度。
  3. 加强用户互动:通过弹窗与用户进行交互,收集用户反馈或意见。

四、设计要点

在设计气泡弹窗组件时,需要注意以下几点:

  1. 明确弹窗目的:确保弹窗的内容清晰、简洁,能够准确传达信息或引导用户操作。
  2. 控制弹窗大小:避免弹窗过大,影响用户体验。同时,也要确保弹窗内容足够显眼,能够引起用户注意。
  3. 合理设置关闭按钮:给予用户关闭弹窗的权利,避免强制用户阅读或操作。关闭按钮的位置应便于用户点击,减少操作成本。
  4. 优化交互体验:确保弹窗的触发方式、显示方式以及消失方式都符合用户的使用习惯,提高用户体验。

五、在线设计

把弹窗组件拖进设计器。然后支持其他 组件往组件容器里拖进去,比如我们直接拖进宫格组件进去。

设置气泡弹窗组件属性。

由于气泡弹窗组件在默认运行时,不显示,需要点击来显示此组件,拖动任意一个按钮组件进设计器。

设置按钮点击事件

保存源码至本地查看组件效果。

六、生成的源码

<template>
	<view class="container container329152">
		<button @tap="navigateTo" data-type="openPopover" data-id="btn-popover" id="btn-popover" class="diygw-col-24 btn-clz diygw-btn-default">按钮</button>
		<diy-popover v-model="popoverData.show" width="200px" bgcolor="#fff" mode="top" :triggerLeft="popoverData.left" :triggerTop="popoverData.top" :triggerWidth="popoverData.width" :triggerHeight="popoverData.height">
			<view class="flex flex-content diygw-col-24">
				<view class="flex diygw-col-24">
					<view class="diygw-grid col-3">
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/global/grid1.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单一 </view>
							</view>
						</view>
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/global/grid2.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单二 </view>
							</view>
						</view>
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/global/grid3.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单三 </view>
							</view>
						</view>
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/global/grid4.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单四 </view>
							</view>
						</view>
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/grid5.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单五 </view>
							</view>
						</view>
						<view class="diygw-grid-item">
							<view class="diygw-grid-inner">
								<view class="diygw-grid-icon diygw-avatar">
									<image mode="aspectFit" class="diygw-avatar-img" src="/static/grid6.png"></image>
								</view>
								<view class="diygw-grid-title"> 菜单六 </view>
							</view>
						</view>
					</view>
				</view>
			</view>
		</diy-popover>
		<view class="clearfix"></view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				//用户全局信息
				userInfo: {},
				//页面传参
				globalOption: {},
				//自定义全局变量
				globalData: {},
				listNum: 1,
				list: {
					code: 200,
					msg: '获取数据成功',
					data: [
						{
							title: '标题1',
							remark: '描述1',
							id: 1,
							attr: {
								title: '标题1'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题2',
							remark: '描述2',
							id: 2,
							attr: {
								title: '标题2'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题3',
							remark: '描述3',
							id: 3,
							attr: {
								title: '标题3'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题4',
							remark: '描述4',
							id: 4,
							attr: {
								title: '标题4'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题5',
							remark: '描述5',
							id: 5,
							attr: {
								title: '标题5'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题6',
							remark: '描述6',
							id: 6,
							attr: {
								title: '标题6'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题7',
							remark: '描述7',
							id: 7,
							attr: {
								title: '标题7'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题8',
							remark: '描述8',
							id: 8,
							attr: {
								title: '标题8'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题9',
							remark: '描述9',
							id: 9,
							attr: {
								title: '标题9'
							},
							img: 'https://php.diygw.com/logo.png'
						},
						{
							title: '标题10',
							remark: '描述10',
							id: 10,
							attr: {
								title: '标题10'
							},
							img: 'https://php.diygw.com/logo.png'
						}
					]
				},
				popoverData: {
					left: 0,
					top: 10,
					height: 0,
					width: 0,
					show: false
				}
			};
		},
		onPageScroll(e) {
			const scrollTop = e.scrollTop;
			this.headerBackgroundStyle = this.headerBackgroundStyle || { background: 'none' };
			if (scrollTop <= 80) {
				const opacity = scrollTop / 100;
				const color = `rgba(255, 255, 255, ${opacity})`;
				this.headerBackgroundStyle.background = color;
			} else {
				this.headerBackgroundStyle.background = '#ffffff';
			}
		},
		onShow() {
			this.setCurrentPage(this);
		},
		onLoad(option) {
			this.setCurrentPage(this);
			if (option) {
				this.setData({
					globalOption: this.getOption(option)
				});
			}

			this.init();
		},
		methods: {
			async init() {
				await this.listApi();
			},
			// 列表数据 API请求方法
			async listApi(param) {
				let thiz = this;
				param = param || {};

				//如果请求要重置页面,请配置点击附加参数refresh=1  增加判断如输入框回调param不是对象
				if (param.refresh || typeof param != 'object') {
					this.listNum = 1;
				}

				//请求地址及请求数据,可以在加载前执行上面增加自己的代码逻辑
				let http_url = 'https://php.diygw.com/article.php';
				let http_data = {
					pageNum: this.listNum,
					pageSize: 10,
					sctdown: param.sctdown || this.sctdown
				};
				let http_header = {};

				let list = await this.$http.post(http_url, http_data, http_header, 'json');

				let datarows = list.rows;
				if (http_data.pageNum == 1) {
					this.list = list;
				} else if (datarows) {
					let rows = this.list.rows.concat(datarows);
					list.rows = rows;
					this.list = list;
				}
				if (datarows && datarows.length > 0) {
					this.listNum = this.listNum + 1;
				}
				this.globalData.isshow = true;
				console.log(http_data.sctdown);
			},
			openPopover(evt) {
				let view = uni.createSelectorQuery().in(this);
				view.select('#' + evt.id).boundingClientRect();
				view.exec((data) => {
					if (data && data.length > 0 && data[0]) {
						this.popoverData.left = data[0].left;
						this.popoverData.top = data[0].top;
						this.popoverData.height = data[0].height;
						this.popoverData.width = data[0].width;
						this.popoverData.show = true;
					}
				});
			},
			closePopover(evt) {
				this.popoverData.show = false;
			}
		},
		onPullDownRefresh() {
			// 列表数据 API请求方法
			this.listNum = 1;
			this.listApi();

			uni.stopPullDownRefresh();
		},
		onReachBottom() {
			// 列表数据 API请求方法
			this.listApi();
		}
	};
</script>

<style lang="scss" scoped>
	.btn-clz {
		padding-top: 20rpx;
		border-bottom-left-radius: 12rpx;
		color: #fff;
		padding-left: 20rpx;
		padding-bottom: 20rpx;
		border-top-right-radius: 12rpx;
		margin-right: 10rpx;
		background-color: #07c160;
		margin-left: 10rpx;
		overflow: hidden;
		width: calc(100% - 10rpx - 10rpx) !important;
		border-top-left-radius: 12rpx;
		margin-top: 10rpx;
		border-bottom-right-radius: 12rpx;
		margin-bottom: 10rpx;
		text-align: center;
		padding-right: 20rpx;
	}
	.diygw-dialog-popover {
	}
	.container329152 {
	}
</style>

Logo

低代码爱好者的网上家园

更多推荐