| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- 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()
|