export class NativePopup { constructor(globalOptions = {}) { this.sysInfo = uni.getSystemInfoSync() // 风格配色 const { bgColor = '#FFFFFF', titleColor = '#1F1F1F', contentColor = "#444746", themeColor = '#0b57d0' } = globalOptions this.globalStyle = { bgColor, titleColor, contentColor, themeColor } } handleClick = (e) => { const { clientX, clientY } = e // 获取计算好的布局数据 const { popupTop, popupHeight, popupWidth, btnAreaHeight, padding } = this.layoutData const { screenWidth } = this.sysInfo // 弹窗的左边距(因为是居中,计算左侧空白) const popupLeft = (screenWidth - popupWidth) / 2 // 按钮区域的顶部 Y 坐标 const btnAreaTop = popupTop + popupHeight - btnAreaHeight // 判断点击是否在按钮行的垂直范围内 if (clientY >= btnAreaTop && clientY <= (popupTop + popupHeight)) { // 定义按钮大概的宽度(用于触控区域,稍微放宽一点) const btnWidth = 80 const rightMargin = padding // 右边距 // 确认按钮区域 (最右侧) // 范围:(弹窗右边界 - 按钮宽 - 边距) ~ (弹窗右边界 - 边距) const confirmBtnRightX = popupLeft + popupWidth - rightMargin const confirmBtnLeftX = confirmBtnRightX - btnWidth if (clientX >= confirmBtnLeftX && clientX <= (confirmBtnRightX + 10)) { this.currentOptions.onConfirm && this.currentOptions.onConfirm() this.close() return } // 取消按钮区域 (确认按钮左边) // 范围:(确认按钮左边 - 按钮宽) ~ (确认按钮左边) const cancelBtnRightX = confirmBtnLeftX const cancelBtnLeftX = cancelBtnRightX - btnWidth if (clientX >= cancelBtnLeftX && clientX <= cancelBtnRightX) { this.currentOptions.onCancel && this.currentOptions.onCancel() this.close() return } } } createPopup = () => { const { screenWidth, screenHeight } = this.sysInfo const { bgColor, titleColor, contentColor, themeColor } = this.globalStyle const { title, content, confirmText, cancelText } = this.currentOptions // 布局计算 const popupWidth = Math.min(screenWidth - 48, 320) // 最大宽度320,两侧留空 const popupHeight = 180 // 固定高度 (如需自适应需复杂计算,这里取经验值) const padding = 24 // Material 3 标准内边距 // 垂直居中计算 const popupTop = (screenHeight - popupHeight) / 2 const popupLeft = (screenWidth - popupWidth) / 2 const btnAreaHeight = 50 // 底部按钮区域高度 // 保存布局数据供 handleClick 使用 this.layoutData = { popupTop, popupHeight, popupWidth, btnAreaHeight, padding } const popupView = new plus.nativeObj.View('popupView', { top: 0, left: 0, width: '100%', height: '100%', }) popupView.addEventListener("click", this.handleClick) // 1. 绘制全屏半透明蒙层 popupView.drawRect({ color: 'rgba(0, 0, 0, 0.4)', }, { top: 0, left: 0, width: '100%', height: '100%', }) // 2. 绘制卡片背景 popupView.drawRect({ color: bgColor, radius: '16px' }, { top: `${popupTop}px`, left: `${popupLeft}px`, width: `${popupWidth}px`, height: `${popupHeight}px`, }) // 3. 绘制标题 (更粗,字号 20px) popupView.drawText(title, { top: `${popupTop + padding}px`, left: `${popupLeft + padding}px`, width: `${popupWidth - padding * 2}px`, height: "30px", }, { size: "20px", weight: "bold", // 这里的bold在部分原生环境可能不明显,依靠字号区分 align: "left", color: titleColor, }) // 4. 绘制内容 (字号 15px,颜色略浅) popupView.drawText(content, { top: `${popupTop + padding + 35}px`, // 标题下方 left: `${popupLeft + padding}px`, width: `${popupWidth - padding * 2}px`, height: "60px", }, { size: "15px", align: "left", color: contentColor, whiteSpace: 'normal', lineSpacing: '20%', // 增加行间距提升阅读体验 }) // 5. 绘制按钮 (位于右下角) const btnFontSize = "15px" const btnWidth = "80px" // 绘制宽度 // 确认按钮 popupView.drawText(confirmText || '确认', { top: `${popupTop + popupHeight - 40}px`, // 底部留些空隙 left: `${popupLeft + popupWidth - padding - 80}px`, // 右对齐 width: btnWidth, height: '30px' }, { size: btnFontSize, color: themeColor, align: 'right', // 文字右对齐 weight: 'bold' }); // 取消按钮 popupView.drawText(cancelText || '取消', { top: `${popupTop + popupHeight - 40}px`, left: `${popupLeft + popupWidth - padding - 80 - 80 - 10}px`, // 确认按钮左侧,间隔10px width: btnWidth, height: '30px' }, { size: btnFontSize, color: themeColor, // 取消按钮可以是灰色 align: 'right' }); this.popupView = popupView return popupView } show = (options = {}) => { this.close() this.currentOptions = { title: '提示', content: '', confirmText: '确定', cancelText: '取消', ...options } this.createPopup() this.popupView.show() } close = () => { if (this.popupView) { this.popupView.close() this.popupView = null } } } export const popup = new NativePopup()