UNIAPP popper气泡弹层【unibest框架下】vue3+typescript
看了下市场的代码,要么写的不怎么好,要么过于复杂。于是把市场的代码下下来了自己改。200行代码撸了个弹出层组件。兼容H5和APP。
功能:
1)只支持上下左右4个方向的弹层不支持侧边靠齐
2)不对屏幕边界适配
3)支持弹层外边点击自动隐藏
4)支持3种内容模式:
1. 弹出提示文本
2. slot内容占位
3. 支持菜单模式
BWT:弹层外点击自动隐藏基于unibest框架的页面模板技术,这里就不放代码了,自己想想怎么弄😏 。提示:使用事件总线模式,放出的代码也提示了部分用法。
效果,H5下:

APP下:

小程序下:

组件代码:
<!--自定义弹出层/菜单组件1)只支持上下左右4个方向的弹层不支持侧边靠齐2)不对屏幕边界适配3)支持弹层外边点击自动隐藏4)支持3种内容模式:1. 文本为内容2. slot内容占位3. 菜单模式@Author Jim 24/10/08-->
<template><view><view class="cc_popper" @click.stop="handleClick"><slot></slot><viewclass="cc_popper_layer border-2rpx border-solid"@click.stop="() => {}":style="[data.layerStyle,{visibility: data.isShow ? 'visible' : 'hidden',opacity: data.isShow ? 1 : 0,color: props.textColor,backgroundColor: props.bgColor,borderColor: 'var(--cc-box-border)'}]"><view class="px-20rpx py-10rpx" v-if="content.length > 0 || $slots.content"><!-- 内容模式 --><slot name="content">{{ content }}</slot></view><view v-else class="py-5rpx px-10rpx"><template v-for="(conf, index) in props.menu" :key="index"><view v-if="index > 0" class="bg-box-border opacity-70 h-2rpx w-full" /><viewclass="px-20rpx py-10rpx menu-item my-5rpx"@click="() => {conf.callback()data.isShow = false}">{{ conf.title }}</view></template></view><view:class="['w-0', 'h-0', 'z-9', 'absolute', 'popper-arrow-on-' + props.direction]":style="[data.arrowStyle]"/></view></view></view>
</template>
<script lang="ts" setup>
import { CSSProperties } from 'vue'
import * as utils from '@/utils'
let instanceconst { screenWidth } = uni.getSystemInfoSync()const pixelUnit = screenWidth / 750 // rpx->px比例基数export interface MenuConf {icon?: string // 指示图标title: string // 菜单文本callback: () => void // 点击事件
}const props = withDefaults(defineProps<{textColor?: string // 指定内部文本颜色bgColor?: stringborderColor?: stringcontent?: string // 可以指定文本content,或者指定 slot content来显示弹窗内容menu?: Array<MenuConf> // 下拉菜单模式direction?: 'top' | 'bottom' | 'left' | 'right' // 弹层位置alwaysShow: boolean}>(),{textColor: 'var(--cc-txt)',bgColor: 'var(--cc-box-fill)', // 默认弹框色borderColor: 'var(--cc-box-border)', // 默认弹框边框色content: '',menu: () => [],direction: 'top',alwaysShow: false}
)const data = reactive<{isShow: booleanlayerStyle: CSSProperties // CSS定义一层够了arrowStyle: CSSProperties
}>({isShow: false,layerStyle: {},arrowStyle: {}
})onMounted(() => {instance = getCurrentInstance()if (props.alwaysShow) {nextTick(() => handleClick())}
})onUnmounted(() => {if (!props.alwaysShow) {utils.off(utils.Global.CC_GLOBAL_CLICK, hideLayer) // 移除全局点击监听}
})const hideLayer = (event: MouseEvent) => {data.isShow = falseutils.off(utils.Global.CC_GLOBAL_CLICK, hideLayer)
}const handleClick = async () => {if (data.isShow) {if (props.alwaysShow) {return}utils.off(utils.Global.CC_GLOBAL_CLICK, hideLayer)return (data.isShow = false)}const rects: UniApp.NodeInfo[] = await utils.getRectAll('.cc_popper,.cc_popper_layer', instance)const srcRect: UniApp.NodeInfo = rects[0]const layerRect: UniApp.NodeInfo = rects[1]data.arrowStyle['border' + props.direction.charAt(0).toUpperCase() + props.direction.slice(1)] ='10rpx solid var(--cc-box-border)'switch (props.direction) {case 'top': {data.layerStyle.left = `${(srcRect.width - layerRect.width) / 2}px`data.layerStyle.bottom = `${srcRect.height + 16 * pixelUnit}px`data.arrowStyle.left = `${layerRect.width / 2 - 12 * pixelUnit}px`console.log(data.arrowStyle.left)break}case 'bottom': {data.layerStyle.left = `${(srcRect.width - layerRect.width) / 2}px`data.layerStyle.top = `${srcRect.height + 16 * pixelUnit}px`data.arrowStyle.left = `${layerRect.width / 2 - 12 * pixelUnit}px`break}case 'left': {data.layerStyle.right = `${srcRect.width + 16 * pixelUnit}px`data.layerStyle.top = `${(srcRect.height - layerRect.height) / 2}px`data.arrowStyle.top = `${layerRect.height / 2 - 12 * pixelUnit}px`break}case 'right': {data.layerStyle.left = `${srcRect.width + 16 * pixelUnit}px`data.layerStyle.top = `${(srcRect.height - layerRect.height) / 2}px`data.arrowStyle.top = `${layerRect.height / 2 - 12 * pixelUnit}px`break}}data.isShow = trueif (!props.alwaysShow) {utils.on(utils.Global.CC_GLOBAL_CLICK, hideLayer)}
}
</script>
<style lang="scss" scoped>
$arrow-size: 12rpx;
$arrow-offset: -12rpx;.cc_popper {position: relative;display: inline-block;
}.cc_popper_layer {position: absolute;display: inline-block;white-space: nowrap;border-radius: 10rpx;transition: opacity 0.3s ease-in-out;
}.popper-arrow-on-top {bottom: $arrow-offset;border-right: $arrow-size solid transparent;border-left: $arrow-size solid transparent;
}.popper-arrow-on-right {left: $arrow-offset;border-top: $arrow-size solid transparent;border-bottom: $arrow-size solid transparent;
}.popper-arrow-on-left {right: $arrow-offset;border-top: $arrow-size solid transparent;border-bottom: $arrow-size solid transparent;
}.popper-arrow-on-bottom {top: $arrow-offset;border-right: $arrow-size solid transparent;border-left: $arrow-size solid transparent;
}.menu-item {&:active {background-color: #88888840;}
}
</style>
测试页面:
<template><view class="text-txt w-full h-full"><view>消息</view><view class="x-items-between px-200rpx pt-100rpx"><cc-popper direction="left" content="说啥好呢" alwaysShow><view class="w-100rpx"><u-button text="左边" /></view></cc-popper><view class="w-100rpx"><cc-popper direction="top" content="向上看" alwaysShow><view class="w-100rpx"><u-button text="上面" /></view></cc-popper><cc-popper direction="bottom" content="下边也没有" alwaysShow><view class="w-100rpx mt-20rpx"><u-button text="下面" /></view></cc-popper></view><cc-popper direction="right" content="右边找找" alwaysShow><view class="w-100rpx"><u-button text="右边" /></view></cc-popper></view><view class="x-items-between px-150rpx pt-400rpx"><cc-popper alwaysShow><view class="w-200rpx"><u-button shape="circle" text="烎" /></view><template #content><text class="text-100rpx">🤩</text></template></cc-popper><cc-popper alwaysShow :menu="data.menu"><div class="w-100rpx h-100rpx bg-red"></div></cc-popper></view></view>
</template>
<script lang="ts" setup>
import { MenuConf } from '@/components/ccframe/cc-popper.vue'const data = reactive<{menu: Array<MenuConf>
}>({menu: [{title: '口袋1',callback: () => {console.log('糖果')}},{title: '口袋2',callback: () => {console.log('退出系统')}},{title: '口袋3',callback: () => {console.log('空的')}}]
})
</script>
对了,菜单的图标支持还没写。等用到的时候再加上去,代码放这存档,后面再更新:)
相关文章:
UNIAPP popper气泡弹层【unibest框架下】vue3+typescript
看了下市场的代码,要么写的不怎么好,要么过于复杂。于是把市场的代码下下来了自己改。200行代码撸了个弹出层组件。兼容H5和APP。 功能: 1)只支持上下左右4个方向的弹层不支持侧边靠齐 2)不对屏幕边界适配 3)支持弹层外边点击自动隐藏 4)支持…...
launcher.py: error: the following arguments are required: --output_dir
记录一个LLaMA-Factroy配置过程。 安装 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip install -e ".[torch,metrics]"训练 CUDA_VISIBLE_DEVICES0 llamafactory-cli train example/train_lora/.yaml按理说配置好文件应…...
C语言基础之结构体
今天我们来讲讲C语言基础的最后一个知识点了 —— 结构体。不知道大家对前面的C语言基础的知识点掌握的怎么样了呢?下面我们就开始讲解结构体的相关知识点吧! 什么是结构体呢?或者说结构体有什么作用呢?对于复杂对象来说ÿ…...
Redis入门第四步:Redis发布与订阅
欢迎继续跟随《Redis新手指南:从入门到精通》专栏的步伐!在本文中,我们将深入探讨Redis的发布与订阅(Pub/Sub)模式。这是一种强大的消息传递机制,适用于各种实时通信场景,如聊天应用、实时通知和…...
MySQL 之权限与授权
MySQL 权限及授权系统用于控制数据库用户对数据库资源的访问和操作权限。它提供了一种细粒度的安全控制机制,确保只有被授权的用户才能执行特定的操作。MySQL 的权限控制体系非常灵活,支持多种权限类型及级别(数据库、表、列、存储过程等&…...
解决方案:Pandas里面的loc跟iloc,有什么区别
文章目录 一、现象二、解决方案案例使用loc使用iloc 简单总结 一、现象 在用Pandas库处理数据的时候,久而久之不用loc跟iloc,难免会有些混乱记混 二、解决方案 在Pandas中,loc和iloc是两种常用的数据选择方法,它们的主要区别在…...
C# 和 C++ 混合编程
以下是一个关于 C# 和 C 混合编程 的教程详细目录,涵盖了混合编程中的各个重要方面: 目录 1. 引言 1.1 什么是混合编程? 1.2 为什么选择 C# 和 C 进行混合编程? 1.3 应用场景和优势 2. 基本概念 2.1 C# 和 C 的基础差异 2.…...
Vxe UI vue vxe-table 实现表格单元格选中功能
Vxe UI vue vxe-table 实现表格单元格选中功能 在表格中实现鼠标点击任意单元格,选取的功能,通过 mouse-config 配置就可以开启单选功能,多选单元格选取功能需安装插件支持。 代码 参数说明 mouse-config 鼠标配置项: selected&…...
组合模式详解
1、组合模式基本介绍 1) 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以 表示“整体-部分”的层次关系。 2) 组合模式依据树形结构来组合对象,用来表示部…...
AltiumDesigner脚本开发-DIP封装制作
1.点击工具栏的运行工具(蓝色向右三角图标)可以执行脚本程序; 2.点击菜单栏Run->Run可以执行脚本程序; 3.在脚本编辑器中,按键盘的F9键可以执行脚本程序; 4.通过菜单栏执行脚本程序(需要将程序添加到菜单栏中&am…...
乌班图基础设施安装之Mysql8.0+Redis6.X安装
简介:云服务器基础设施安装之 Mysql8.0Redis6.X 安装 Docker安装 # 按照依赖 yum install -y yum-utils device-mapper-persistent data lvm2 Docker Mirror 从去年开始. hub.docker.com[1] 在国内的访问速度极慢. 当时大家主要还是依赖国内的一些镜像源: 如中科…...
【动态规划-最长递增子序列(LIS)】力扣673.最长递增子序列的个数
给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。 注意 这个数列必须是 严格 递增的。 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。 示例 2: 输入: [2,2,2,2,2] 输出: 5 解释:…...
SQL优化 where谓词条件is null优化
1.创建测试表及谓词条件中包含is null模拟语句 create table t641 as select * from dba_objects; set autot trace select SUBOBJECT_NAME,OBJECT_NAME from t641 where OBJECT_NAMEWRI$_OPTSTAT_SYNOPSIS$ and SUBOBJECT_NAME is null; 2.全表扫描逻辑读1237 3.创建等值谓词条…...
Starrocks 元数据恢复 failed to load journal type 10242
fe 启动异常 2024-10-08 09:24:57.66908:00 INFO (stateChangeExecutor|87) [DatabaseTransactionMgr.replayUpsertTransactionState():1702] remove expired transaction: TransactionState. txn_id: 189324, label: delete_031c5090-7e2d-11ef-bdd8-000c29967e13, db id: 100…...
《深度学习》神经语言模型 Word2vec CBOW项目解析、npy/npz文件解析
目录 一、关于word2vec 1、什么是word2vec 2、常用训练算法 1)CBOW 2)SkipGram 二、关于npy、npz文件 1、npy文件 1)定义 2)特性 3)用途 4)保存及读取 运行结果: 运行结果…...
黄粱一梦,镜花水月总是空
总有人间一两风,埋我十万八千梦 自古以来,梦在我们的生活中一直是一个神秘玄幻而又发人深省的存在,我们一生中有三分之一的时间都在睡觉,做过的梦也是丰富多彩数不胜数。 而从科学的角度来说,梦是我们潜意识里的生活…...
【分布式事务-01】分布式事务之2pc两阶段提交
redis系列整体栏目 内容链接地址【一】分布式事务之2pc两阶段提交https://zhenghuisheng.blog.csdn.net/article/details/142406325 分布式事务之2pc两阶段提交 一,分布式事务之2pc两阶段提交1,两阶段提交(2pc)2,2pc两阶段提交实现思路3&…...
docker 安装 rabbitMQ
第一步:准备工作 # 打开docker目录 [rootMuYu ~]# cd /usr/local/docker/ # 创建rabbitmq文件夹 [rootMuYu docker]# mkdir rabbitmq # 打开rabbitmq文件夹 [rootMuYu docker]# cd rabbitmq/ # 创建挂载目录 [rootMuYu rabbitmq]# mkdir data 第二步ÿ…...
知识改变命运 数据结构【java对象的比较】
0:前言 在基本数据类型中,我们可以直接使用号比较是否相等,还记的学堆哪里时候,插入一个数据,就会与其他数据进行比较,当时我们传入的是Integer类型,在Integer类里面已经实现了compare。 如果…...
01_23 种设计模式之《简单工厂模式》
文章目录 一、什么是设计模式二、设计模式类型简单工厂模式及应用场景定义抽象产品类和具体产品类实现工厂类客户端代码注意事项 一、什么是设计模式 设计模式:在软件研发过程中,经过实战验证,用于解决在特定环境下、重复出现的,…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
