尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

vue3 - popper.js的简单使用

vue3 - popper.js的简单使用
📅 发布时间:2026/6/20 18:14:27

vue3 - popper.js的简单使用

popper.js

官网:https://popper.js.org/docs/v2/modifiers/offset/

npm 安装:

npm i @popperjs/core

背景:

不见得所有库,都会兼容 vue3,总有一些场景,不会被 vue3 覆盖。

场景1:GIS 开发,open-layer 是一个纯 js 的库,代码封装的时候,更倾向于通过 document.createElement() 直接构建弹出层。

场景2:设计全局的相册功能,有些弹出层希望全局复用同一个窗口,不希望增减 dom 节点。

需要设计的内容

popper.js 已经封装了很多内容,使用的时候需要增加下列内容:

1、设计气泡窗口的角标,自己不会写没事,直接使用 element-ui 的设计;
2、添加更合理的点击事件,窗口弹出后,点击任意位置需要关闭窗口;

Javascript代码封装

封装了大部分需要注意的内容。

ts 语法实现,javascript 环境下代码通用。

import {createPopper} from "@popperjs/core";
import {Instance, OptionsGeneric} from "@popperjs/core/lib/types";/*** 可复用的气泡窗口** 用更直接的方式操作 dom,而不使用 vue 进行控制** 场景:* - 窗口内容不变,但是依附组件会发生变化的情况下使用** 原理:* - 基于 popover.js,与 el-popover 底层一致*/
export class Popper {/*** 窗口实例*/public instance: Instance | undefined;/*** 气泡窗口 dom 对象*/public popover: HTMLElement | undefined;/*** 气泡窗口依附的 dom 对象*/public reference: HTMLElement | undefined;/*** 气泡窗口参数设置*/public option: OptionsGeneric = {};/*** 简单的调测日志,用于检测组件的状态变化,popper.js 高级应用会用到*/private post_placement: string | undefined;private logger: TModifier = {phase: 'main',enabled: true,name: 'logger',fn: ({state}: { state: any }) => {// 方向的变化if (this.post_placement !== state.placement) {this.post_placement = state.placement;console.log(this.post_placement);}// 角标的位置信息const {arrow} = state.elements;if (arrow) {console.log(state.modifiersData.arrow);if (state.modifiersData.arrow.centerOffset !== 0) {arrow.setAttribute('data-hide', '');} else {arrow.removeAttribute('data-hide');}}},};/*** 增加日志检测*/public pushLogger(): void {if (!this.options.modifiers) {this.options.modifiers = [];}this.option.modifiers.push(this._logger);}/*** 显示气泡窗口*/public display(): void {if (this.popover) {// don't worry about the issue of attributes cannot be obtained when displaying.this.popover.classList.remove('hidden');}}/*** 隐藏气泡窗口*/public hidden(): void {if (this.popover) {this.popover.classList.add('hidden');}}/*** 初始化气泡窗口,重新绑定窗口和引用之间的关系*/public create(): Instance {this.display();// destroy the popover if it exists.if (this.instance) {this.instance.destroy();}// Pass the button, the tooltip, and some options, and Popper will do the// magic positioning for you:this.instance = createPopper(this.reference!, this.popover!, this.option);return this.instance;}/*** 窗口点击事件,除了触发组件和弹窗组件,任何点击事件都要关闭窗口* @param evt 事件对象*/public windowsEvent(evt: Event): void {if (this.popover) {const target: EventTarget = evt.target;if (!this.popover.contains(target as Node) && !this.reference?.contains(target as Node)) {this.hidden();}}}
}

简单 vue3 组件封装

使用场景:
在各类 change、click 事件中,将 evt.target 传递到当前组件,使窗口自动吸附到触发事件的对象。

样式说明:

  • sea-popper* 样式可以替换成 .el-popper .el-popper__arrow;
  • hidden 效果就是隐藏组件:display: none;
<template><div ref="tooltipRef" role="tooltip" class="sea-popper hidden"><i class="sea-popper__arrow" data-popper-arrow></i><slot></slot></div>
</template><script setup lang="ts">
import {onMounted, onUnmounted, ref, watch} from "vue";
import type {Placement} from "@popperjs/core/lib/enums";
import {OptionsGeneric} from "@popperjs/core/lib/types";
import {Popper} from "./use-popover"/*** 气泡弹窗** 场景:* - 窗口内容不变,但是依附组件会发生变化的情况下使用*/
interface Props {// 需要吸附的组件,注意这是 dom 组件,使用时将 evt.target 传递到当前组件reference?: HTMLElement;// 窗口位置placement?: Placement;// 窗口偏移量,一般无需调整,eg:[0, 8]offset?: number[];
}// 使用 withDefaults 设置默认值
const props = withDefaults(defineProps<Props>(), {placement: 'bottom-start', offset: [0, 8]})// reference
const tooltipRef = ref();// popover-options
const option: OptionsGeneric = {}option.placement = props.placement;if (props.offset != null) {let arr = option.modifiers;if (arr == null) {arr = [];option.modifiers = arr;}arr.push({name: 'offset', options: {offset: props.offset}});
}const popper: Popper = new Popper();
popper.option = option;// 依附组件发生变化的时候,重新绑定组件之间的关系
watch(() => props.reference, (val) => {popper.reference = val;popper.create();
})onMounted(() => {popper.popover = tooltipRef.valuewindow.addEventListener('click', popper.windowsEvent);
})onUnmounted(() => {window.removeEventListener('click', popper.windowsEvent);
})
</script>
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!

相关新闻

  • 文件外发审核管控是什么?主要有何重要性与实施要点?
  • 2025年测试工程师的核心竞争力:会用Dify工作流编排AI测试智能体
  • 2025年11月十大效果图公司对比榜:成本效益与项目案例全面审视

最新新闻

  • 暗黑破坏神2存档编辑器完整指南:三步轻松定制你的D2/D2R游戏体验
  • 2026年评价高的山东HL提升机/提升机料斗/山东提升机链轮厂家精选合集 - 品牌宣传支持者
  • Kimi API开源能力解析与工程化接入实战指南
  • 【JAVA毕设源码分享】springboot基于敏捷开发的项目管理系统(程序+文档+代码讲解+一条龙定制)
  • 2026年靠谱的矿用圆环链用开口式连接环/山东矿用高强度圆环链/圆环链弧齿环/山东圆环链锯齿环多家厂家对比分析 - 行业平台推荐
  • TRK-MPC5604P开发板硬件配置与调试实战指南

日新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号