Element-UI - 解决el-table中图片悬浮被遮挡问题

        在开发中,发现element-ui在el-table中添加图片悬浮显示时,会被单元格遮挡的问题。通过查询得到的解决办法,大多是修改.el-table类中相关样式属性,但经过验证发现会影响到其他正常功能的使用。对于此问题解决其实也并不难,将悬浮图片放在body节点下,通过定位显示即可。所以对于此问题,将通过Vue.directive钩子函数,自定义弹框来实现。

一、Vue.directive

        在解决上述问题前,先了解下Vue.directive构子函数相关功能。除了Vue中核心功能默认内置的指令(v-model和v-show),Vue也允许注册自己的指令。如果需要对DOM元素进行底层操作,这时就会用到自定义指令了,directive为“指令”的意思。

1.1 自定义指令对象中构子函数 

        一个指令定义对象中提供了几个构子函数,具体如下表:

序号名称描述
1bind只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
2inserted被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
3update所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
4componentUpdated指令所在组件的 VNode 及其子 VNode 全部更新后调用。
5unbind只调用一次,指令与元素解绑时调用。

        示例代码如下:

// 注册
Vue.directive('my-directive', {bind: function(){},inserted: function(){},update: function(){},componentUpdated: function(){},unbind: function(){}
})

        除了以上方式外,如果想注册局部指令,组件中也接受一个directives的选项,代码如下:

directives: {focus: {// 指令的定义inserted: function (el) {el.focus()}}
}

1.2 指令构子函数的参数

        指令钩子函数会被传入以下参数,具体如下表:

序号名称属性描述
1el指令所绑定的元素,可以用来直接操作 DOM。
2binding一个对象,包含以下 property:
3name指令名,不包括 v- 前缀。
4value指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
5oldValue指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
6expression字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
7expression传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
8modifiers一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
9vnodeVue 编译生成的虚拟节点。
10oldVnode上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

注间:除了el之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建立通过元素的dataset来进行。

二、图片悬浮功能开发

        这里将通过注册局部指令,来实现图片悬浮显示的功能,在组件中定义directives选项。如须全局注册,可以将以下功能移植到Vue.directive()中定义。

html中在img标签上添加v-suspended,代码如下:

<template><div><el-table size="mini" border :data="tableData"><el-table-column type="index" label="序号" width="50px"></el-table-column><el-table-column label="名称" prop="name"></el-table-column><el-table-column label="图片" prop="thumb"><template slot-scope="scope"><div class="thumb"><img v-if="scope.row.thumb" :src="scope.row.thumb" class="img" v-suspended /></div></template></el-table-column><el-table-column label="创建时间" prop="createtime"></el-table-column><el-table-column label="更新时间" prop="updatetime"></el-table-column></el-table></div>
</template>

js部分代码如下:

export default {data(){return {tableData: [{name: "Angular", thumb: require("@/assets/angular.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "VueJs", thumb: require("@/assets/logo.png"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "NuxtJs", thumb: require("@/assets/nuxtjs.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "React", thumb: require("@/assets/react.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"}]}},directives: {// 自定义悬浮v-suspendedsuspended: {bind: (el) => {console.log('el', el);}}},// end
}

        此时打开浏览器控制中,可以发现输出对应img的DOM节点,如下图:

2.1 创建悬浮框

        首先,我们需要通过javascript创建一个DOM容器,用来显示悬浮图片区域,在项目目录中创建suspendedDialog.js,并引入到页面中,来实现悬浮框的创建并插入。

2.1.1 样式

        这里样式通过less编写的,注意您项目中使用的css预处理器。另外需要注意的是,此弹框默认为display:none(不显示模式),只有当鼠标悬浮到对应图片上时,通过js控制其显示与隐藏。代码如下:

@width: 240px;#suspended-dialog{display: none;width: @width;min-height: @width;position: fixed;left: 0;top: 0;z-index: 1000;padding: 12px;.inner{background-color: #fff;padding: 12px;box-shadow: 0 0 10px rgba(0, 0, 0, .2);border-radius: 8px;width: 100%;height: 100%;overflow: hidden;box-sizing: border-box;}img.imgs{width: 100%;height: 100%;}
}

2.1.2 SuspendedDialog类

        在suspendedDialog.js文件中定义SuspendedDialog类,用于初始化图片悬浮框,以及修改悬浮框位置和显示或隐藏。代码如下:

/** 定义弹框类*/
class SuspendedDialog{constructor(){this.idName = "suspended-dialog";       // 定义容器ID选择器名称this.innerClassName = "inner";          // 内容器类选择器名称this.imgClassName = "imgs";             // 图片节点类选择器名称this.dialogWidth = 240;                 // 外容器宽度this.sDialog = document.createElement('div');   // 外层容器this.innerBox = document.createElement('div');  // 内容器对象this.imgBox = document.createElement('img');    // 图片节点对象}/*** 初始化DOM,并添加到body中*/initialDom(){const sDialog = document.getElementById(this.idName);   // 查询节点// 如果节点存在,则结束后续操作if(sDialog) return;// 初始经属性this.sDialog.id = this.idName;this.innerBox.classList.add(this.innerClassName);this.imgBox.classList.add(this.imgClassName);// 将DOM追加到对应容器中this.innerBox.append(this.imgBox);this.sDialog.append(this.innerBox);document.body.append(this.sDialog);}/*** 显示与隐藏* @param {Object} flag* @param {Object} callback  回调函数*/toggle(flag, callback = () => {}){if(flag && 'block'!=this.sDialog.style.display){this.sDialog.style.display = 'block';callback();} else if(!flag && 'none'!=this.sDialog.style.display){this.sDialog.style.display = 'none';callback();}}
}
export default new SuspendedDialog();

        单例模式是一种常见的设计模式,目的是确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一的实例。

2.1.3 页面引入

页面代码如下:

import sDialog from './suspendedDialog.js'
export default {data(){return {tableData: [{name: "Angular", thumb: require("@/assets/angular.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "VueJs", thumb: require("@/assets/logo.png"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "NuxtJs", thumb: require("@/assets/nuxtjs.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"},{name: "React", thumb: require("@/assets/react.jpg"), createtime: "2024/6/15", updatetime: "2024/6/15"}]}},directives: {// 自定义悬浮v-suspendedsuspended: {bind: (el) => {sDialog.initialDom();}}},// end
}

        当在钩子函数中初始化弹框后,则页面中节点创建了一个单例的DOM节点。如下图:

2.2 监听事件

        通过mouseenter、mouseleave事件来判断,鼠标是否经过对应图上节点或是已离开节点。  这里需要注意的是,鼠标当在图片或悬浮区域图片上时,悬浮框都正常显示,移出来隐藏。

2.2.1 修改SuspendedDialog类

        此时SuspendedDialog类需要做两个修改,一是增加setImgUrl()函数,用于修改图片地址;二是增加悬浮框鼠标移入移出监听事件,用于监听悬浮框是否显示操作。代码如下:

/** 定义弹框类*/
class SuspendedDialog{constructor(){this.idName = "suspended-dialog";       // 定义容器ID选择器名称this.innerClassName = "inner";          // 内容器类选择器名称this.imgClassName = "imgs";             // 图片节点类选择器名称this.dialogWidth = 240;                 // 外容器宽度this.sDialog = document.createElement('div');   // 外层容器this.innerBox = document.createElement('div');  // 内容器对象this.imgBox = document.createElement('img');    // 图片节点对象}/*** 初始化DOM,并添加到body中*/initialDom(){const sDialog = document.getElementById(this.idName);   // 查询节点// 如果节点存在,则结束后续操作if(sDialog) return;// 初始经属性this.sDialog.id = this.idName;this.innerBox.classList.add(this.innerClassName);this.imgBox.classList.add(this.imgClassName);// 将DOM追加到对应容器中this.innerBox.append(this.imgBox);this.sDialog.append(this.innerBox);document.body.append(this.sDialog);// 追加事件this.addEvent();}/*** 修改图片路径* @param {Object} _url*/setImgUrl(_url){this.imgBox.src = _url;}/*** 添加监听事件*/addEvent(){this.sDialog.addEventListener('mouseenter', e => this.toggle(true));    // 鼠标移入悬浮框区域时保持显示this.sDialog.addEventListener('mouseleave', e => this.toggle(false));   // 鼠标移出悬浮框区域时隐藏}/*** 显示与隐藏* @param {Object} flag* @param {Object} callback  回调函数*/toggle(flag, callback = () => {}){if(flag && 'block'!=this.sDialog.style.display){this.sDialog.style.display = 'block';callback();} else if(!flag && 'none'!=this.sDialog.style.display){this.sDialog.style.display = 'none';callback();}}
}
export default new SuspendedDialog();

2.2.2 页面中事件监听与图片显示

        当鼠标移入图片时,先执行toggle函数显示悬浮框,当悬浮框显示后执行回调函数(只有弹框显示出来后,方可获取真实的参数数据)。在执行回调函数时,将当前鼠标所在图片的地址获取,并将其赋给悬浮框中的img节点对象。

        代码如下 :

import sDialog from './suspendedDialog.js'
export default {// ...directives: {// 自定义悬浮v-suspendedsuspended: {bind: (el) => {// 初始化悬浮框sDialog.initialDom();// 鼠标经过图片并未移出时执行回调函数el.addEventListener('mouseenter', function(e) {// 显示悬浮弹框,显示后获取相应的参数信息sDialog.toggle(true, () => {sDialog.setImgUrl(el.src);});});// 鼠标移出图片区域时,隐藏悬浮弹框el.addEventListener('mouseleave', () => sDialog.toggle(false));}}},// end
}

        运行后结果如下图:

        

2.3 计算悬浮框位置

        如上结果可见,现在鼠标放到对应的图片上后,悬浮框可以显示对应图片信息了;但是悬浮框还未与图片进行对齐,此地则需要通过获取相应参数数据,进行计算来重新指定悬浮框位置。

2.3.1 修改SuspendedDialog类

        在SuspendedDialog类中新增resetPosition()函数,用于修正悬浮弹框在新图片的位置。

        示例代码如下:

/** 定义弹框类*/
class SuspendedDialog{// .../*** 重新指定弹框位置* @param {Object} boundingClientRect*/resetPosition(boundingClientRect){console.log('bounding', boundingClientRect);this.sDialog.style.top = boundingClientRect.top + "px";this.sDialog.style.left = (boundingClientRect.width + boundingClientRect.left) + "px";}
}
export default new SuspendedDialog();

2.3.2 页面中获取元素边界信息

        当SuspendedDialog类中修正弹框位置的resetPosition()函数定义好后,页面中则可以直接调用了。而DOM元素的边界信息,通过el.getBoundingClientRect()直接获取即可。

        示例代码如下:

import sDialog from './suspendedDialog.js'
export default {// ...directives: {// 自定义悬浮v-suspendedsuspended: {bind: (el) => {// 初始化悬浮框sDialog.initialDom();// 鼠标经过图片并未移出时执行回调函数el.addEventListener('mouseenter', function(e) {// 显示悬浮弹框,显示后获取相应的参数信息sDialog.toggle(true, () => {sDialog.resetPosition(el.getBoundingClientRect());      // 修正弹框位置sDialog.setImgUrl(el.src);                              // 修改新的图片地址});});// 鼠标移出图片区域时,隐藏悬浮弹框el.addEventListener('mouseleave', () => sDialog.toggle(false));}}},// end
}

        此时当鼠标放到图片上后,控制台会输出此图片元素的边界信息,如下图:

        另外,悬浮框现在也可以和图片对齐显示了,如下图:

2.3.3 内填充边距

        如图可见,其实悬浮弹框并未与图片进行对齐,这是由于在定义样式时,给外容器添加padding: 12px内填充边距。

        右图可以清晰看出悬浮弹框三层结构,为什么这里要定义两个div容器,其目的是解决鼠标从图片区域滑到悬浮弹框区域时,中间不会现出空隙;因为鼠标一旦移出图片,悬浮框会立即隐藏掉,则不会出现鼠标在悬浮框上保持显示情况;而增加内填充,图片与悬浮框看似存在间距,但实际是保持连续性。

        所以我们将内填充距离减掉里可,SuspendedDialog类再次调整,代码如下:

/** 定义弹框类*/
class SuspendedDialog{constructor(){this.idName = "suspended-dialog";       // 定义容器ID选择器名称this.innerClassName = "inner";          // 内容器类选择器名称this.imgClassName = "imgs";             // 图片节点类选择器名称this.dialogWidth = 240;                 // 外容器宽度this.dialogPadding = 12;                // 外容器内填充this.sDialog = document.createElement('div');   // 外层容器this.innerBox = document.createElement('div');  // 内容器对象this.imgBox = document.createElement('img');    // 图片节点对象}// .../*** 重新指定弹框位置* @param {Object} boundingClientRect*/resetPosition(boundingClientRect){this.sDialog.style.top = (boundingClientRect.top - this.dialogPadding) + "px";this.sDialog.style.left = (boundingClientRect.width + boundingClientRect.left) + "px";}
}
export default new SuspendedDialog();

        此时如下图可见,顶部显示已对齐状态。

        在实际开发中,可能会遇到下图底部超出情况,或者左侧、右侧超出情况。这里就不细讲了,对界面要求较高的朋友,可以在resetPosition()函数中,通过DOM的边界信息或其他节点数据,进行相应计算来多方位处理,使其能按您的需求展示出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/351684.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《人生海海》读后感

麦家是写谍战的高手&#xff0c;《暗算》《风声》等等作品被搬上荧屏后&#xff0c;掀起了一阵一阵的收视狂潮。麦家声名远扬我自然是知道的&#xff0c;然而我对谍战似乎总是提不起兴趣&#xff0c;因此从来没有拜读过他的作品。这几天无聊时在网上找找看看&#xff0c;发现了…

数据结构笔记-2、线性表

2.1、线性表的定义和基本操作 如有侵权请联系删除。 2.1.1、线性表的定义&#xff1a; ​ 线性表是具有相同数据类型的 n (n>0) 个数据元素的有限序列&#xff0c;其中 n 为表长&#xff0c;当 n 0 时线性表是一个空表。若用 L 命名线性表&#xff0c;则其一般表示为&am…

爬虫初学篇

初次学习爬虫&#xff0c;知识笔记小想 目录&#x1f31f; 一、&#x1f349;基础知识二、&#x1f349;http协议&#xff1a;三、&#x1f349;解析网页(1) xpath的用法&#xff1a;(2) bs4解析器的解释&#xff1a;(3) python字符编码的错误&#xff1a;(4) 正则表达式&#…

第零篇——数学到底应该怎么学?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 宏观讲解数学定位&#xff0c;数学学习方式方法&#xff0c;再次详细学习…

Golang | Leetcode Golang题解之第160题相交链表

题目&#xff1a; 题解&#xff1a; func getIntersectionNode(headA, headB *ListNode) *ListNode {if headA nil || headB nil {return nil}pa, pb : headA, headBfor pa ! pb {if pa nil {pa headB} else {pa pa.Next}if pb nil {pb headA} else {pb pb.Next}}retu…

单调栈(续)、由斐波那契数列讲述矩阵快速降幂技巧

在这里先接上一篇文章单调栈&#xff0c;这里还有单调栈的一道题 题目一&#xff08;单调栈续&#xff09; 给定一个数组arr&#xff0c; 返回所有子数组最小值的累加和 就是一个数组&#xff0c;有很多的子数组&#xff0c;每个数组肯定有一个最小值&#xff0c;要把所有子…

【stm32-新建工程】

stm32-新建工程 ■ 下载相关STM32Cube官方固件包&#xff08;F1&#xff0c;F4&#xff0c;F7&#xff0c;H7&#xff09;■ 1. ST官方搜索STM32Cube■ 2. 搜索 STM32Cube■ 3. 点击获取软件■ 4. 选择对应的版本下载■ 5. 输入账号信息■ 6. 出现下载弹框&#xff0c;等待下载…

MySQL 使用 MyFlash 快速恢复误删除、误修改数据

一、MyFlash MyFlash 是由美团点评公司技术工程部开发并维护的一个开源工具&#xff0c;主要用于MySQL数据库的DML操作的回滚。这个工具通过解析binlog日志&#xff0c;帮助用户高效、方便地进行数据恢复。MyFlash的优势在于它提供了更多的过滤选项&#xff0c;使得回滚操作变…

云计算在保险行业的应用:太平财险团财险理赔新核心业务系统案例

随着科技的快速发展&#xff0c;云计算技术已经成为推动保险行业数字化转型的重要力量。云计算为保险公司提供了弹性、可扩展的计算资源&#xff0c;使其能够灵活应对业务高峰和低谷&#xff0c;提高业务运营效率和风控水平。太平财险与太平金科联合开发的“团财险理赔新核心业…

LLVM 中 的 pass 及其管理机制

概述 LLVM 编译器框架的核心概念是任务调用和执行 编译器开发者将IR分解为不同的处理对象&#xff0c;并将其处理过程实现为单独的pass类型。在编译器初始化&#xff0c;pass被实例化&#xff0c;并被添加到pass管理中 pass 管理器(pass manager) 以流水线的方式将各个独立的…

HCS-华为云Stack-容器网络

HCS-华为云Stack-容器网络 容器隧道overlay VPC网络

vue3轮播图怎么做

先看效果 实现代码 <n-carouseleffect"card"dot-type"line"draggable:autoplay"!isHovered":current-index"currentIndex"prev-slide-style"transform: translateX(-150%) translateZ(-450px);opacity:1"next-slide-st…

结构设计模式 - 桥接设计模式 - JAVA

桥接设计模式 一. 介绍二. 桥接模式示例2.1 定义实现部分和具体实现2.2 定义抽象部分和细化抽象部分2.3 测试2.4 解释 三. 结论 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一.…

windows11 x64 23H2 企业纯净版2024.6.16

闲来无事试安装了下da_nao_yan的 【6月12日更新】Windows11 22631.3737企业版 23H2 自用优化版 &#xff08;原版地址&#xff1a;https://bbs.pcbeta.com/viewthread-1985546-1-1.html&#xff09;&#xff0c;感觉比原版流畅多了&#xff0c;重新按照自己习惯封装了下&#x…

使用 C# 进行面向对象编程:第 9 部分

使用 OOP 的用户活动日志 应用程序背后的关键概念 在这一部分中&#xff0c;我们将使用之前学到的一些 OOP 概念。我们将创建一个小型应用程序。在继续之前&#xff0c;请阅读我的文章user-activity-log-using-C-Sharp-with-sql-server/。在本课程中&#xff0c;我们将再次使…

LabVIEW进行负载测试

本文介绍了如何使用LabVIEW进行负载测试&#xff0c;通过一个具体案例详细讲解了测试系统的组成、工作原理和实现方法。系统采用先进的硬件和软件架构&#xff0c;结合LabVIEW的强大功能&#xff0c;成功实现了对设备的高效负载测试&#xff0c;确保了系统的可靠性和性能。 项…

拥抱开源,构建未来:王嘉树与 TDengine 的开源之旅

在当代的技术浪潮中&#xff0c;开源文化不仅催生了无数创新技术&#xff0c;也为广大技术爱好者提供了一个展示才华、相互学习的平台。我们今天采访到的这位北京邮电大学电子工程学院的研究生&#xff0c;就是在这样的背景下&#xff0c;通过开源活动不断探索、学习并实现自我…

2024年汉字小达人活动还有4个多月开赛:来做18道历年选择题备考吧

结合最近几年的活动安排&#xff0c;预计2024年第11届汉字小达人比赛还有4个多月就启动&#xff0c;那么孩子们如何利用这段时间有条不紊地准备汉字小达人比赛呢&#xff1f; 我的建议是充分利用即将到来的暑假&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0…

Docker 安装 MySQL5.7 和 MySQL8

文章目录 安装 MySQL5.7拉取镜像前期准备启动容器 安装MySQL8.0拉取镜像查看镜像前期准备启动容器 安装 MySQL5.7 拉取镜像 docker pull mysql:5.7拉下来镜像后 执行 docker images 此时我们已经有这个镜像了。 前期准备 在根目录下创建 app &#xff0c; 在 app 目录下创建…

蚂蚁SEO的蜘蛛对网页收录有帮助吗 ?

网页蜘蛛对网站收录有着至关重要的帮助。在深入探讨这一话题之前&#xff0c;我们首先需要了解网页蜘蛛的工作原理及其在互联网生态系统中的角色。 网页蜘蛛&#xff0c;也被称为网络爬虫或网络机器人&#xff0c;是搜索引擎的核心组成部分。它们按照特定的算法和规则&#xff…