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-suspended
    suspended: {
      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-suspended
    suspended: {
      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-suspended
    suspended: {
      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-suspended
    suspended: {
      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.mfbz.cn/a/714685.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTTP协议 快速入门

http概述 无状态性&#xff1a;HTTP是一个无状态协议&#xff0c;这意味着服务器不会在请求之间保存任何会话信息。每个请求都是独立的&#xff0c;服务器不会记住之前的请求。 请求-响应模型&#xff1a;HTTP通信是基于客户端发送请求和服务器返回响应的模型。客户端&#xf…

面向对象初级的内存分布图

1.一个对象的内存图 2.二个对象的内存图 3.二个引用指向同一个对象 4.this的内存布局图 创建了一个Student类的对象s1,因为有new,所有在堆区开辟了一些内存空间,比如把这些内存空间的地址值叫001 形参name是竹小玲, 也就是对象s调用method方法的地址值, this表示方法调用者的地…

MicroPython 环境下使用 ESP32 连接百度 AI 大模型

前言 在物联网领域&#xff0c;ESP32 由于其丰富的功能和低功耗性能成为了一种流行的选择。结合 MicroPython&#xff0c;它为开发者提供了一个高效的开发环量&#xff0c;让 Python 程序员也能轻松介入到嵌入式系统和 IoT 应用的开发之中。本文将介绍如何利用这些技术&#x…

内存-VSS、RSS、PSS、USS

一、 VSS 虚拟耗用内存大小&#xff0c;是进程可以访问的所有虚拟内存的总量&#xff0c;包括进程独自占用的物理内存、和其他进程共享的内存、分配但未使用的内存。 RSS 驻留内存大小&#xff0c;是进程当前实际占用的物理内存大小&#xff0c;包括进程独自占用的物理内存、…

【ROS里程计】中部分代码解释

bool OdomNodePub::Odom_Reset(ubt_odom::odomreset::Request& req, ubt_odom::odomreset::Response& res) {if(req.cmd "reset"){OdomResetFlag true;}else{OdomResetFlag false;}res.state "success";return true; } 该函数是一个ROS节点中…

如何判断一个js对象是否存在循环引用

一、背景 在前端JSON.stringfy是我们常用的一个方法&#xff0c;可以将一个对象序列化。 例如将如下对象序列化 const person { name: kalory, age:18}JSON.stringfy(person) // 结果 {"name":"kalory","age":18}将一个数组序列化const arr …

Modbus转Profibus网关接变频器:实现工业自动化无缝连接

一、背景 在工业自动化领域&#xff0c;Modbus和Profibus是两种常见的通讯协议&#xff0c;而变频器作为控制电机转速的重要设备。为了实现不同设备之间的无缝连接和数据传输&#xff0c;现场大多数采用Modbus转Profibus网关&#xff08;XD-MDPB100&#xff09;来解决Modbus设…

常见场景的业务逻辑漏洞以及安全设计

前言 目前常规漏洞的挖掘越来越困难&#xff0c;在这种情况下&#xff0c;我们可以多去看看业务逻辑方面的漏洞&#xff0c;也是复杂的系统&#xff0c;越有可能出现这方面的问题。本篇文章就来看看常见的一些场景下都有哪些业务漏洞。 由于本人水平有限&#xff0c;文章中可…

论文笔记:ATime-Aware Trajectory Embedding Model for Next-Location Recommendation

Knowledge and Information Systems, 2018 1 intro 1.1 背景 随着基于位置的社交网络&#xff08;LBSNs&#xff09;&#xff0c;如Foursquare和Facebook Places的日益流行&#xff0c;大量用户签到数据变得可用 这些大量签到数据的可用性带来了许多有用的应用&#xff0c;以…

【AI实践】Dify开发应用和对接微信

自定义应用 创建应用有2种&#xff0c; 从应用模板创建 空白应用&#xff0c;也就是自定义应用 选择翻译助手 Translation assistant模板创建一个应用 自定义应用&#xff0c;创建一个child_accompany_bot自定的应用&#xff0c;用来支持家长&#xff0c;如何解决低龄儿童的…

LLVM后端 td文件 tablegen 模式匹配 寄存器 指令集 calling convention

目录 一、寄存器 1.1 寄存器定义 1.2 寄存器分类 二、指令集 2.1 指令集定义 2.2 模式匹配 2.2.1 PatFrags与PatFrag 2.2.2 OutPatFrag 2.2.3 PatLeaf 2.2.4 ImmLeaf 2.2.5 IntImmLeaf和FPImmLeaf 2.2.6 Pat 2.2.7 ComplexPattern 2.3 指令合法化 2.3.1 Promote…

异常向量表的设置

1、Linux Kernel中对异常向量表的填充 linux/arch/arm64/kernel/entry.S kernel_ventry 是一个定义异常向量的宏&#xff1b; 在该宏中&#xff0c;程序跳转到了b el\el\ht()\regsize()\label; 以为异常向量的第6行为例&#xff0c;其实就是跳转到了bl el1h_64_irq; 然后你去搜…

YOLOv10涨点改进SPPF创新结构,重新设计全局平均池化层和全局最大池化层,增强全局视角信息和不同尺度大小的特征

本文改进:SPPF_improve利用全局平均池化层和全局最大池化层,加入一些全局背景信息和边缘信息,从而获取全局视角信息并减轻不同尺度大小所带来的影响,强烈推荐,适合直接使用,paper创新级。 目录 1,YOLOv10介绍 1.1 C2fUIB介绍 1.2 PSA介绍 1.3 SCDown 2.SPP &SP…

哇塞,超好吃的麻辣片,一口就爱上

最近&#xff0c;我发现了一款让人欲罢不能的美食——食家巷麻辣片&#xff01;&#x1f60d; 一打开包装&#xff0c;那浓郁的麻辣香气就扑鼻而来&#xff0c;瞬间刺激着我的嗅觉神经。&#x1f603;食家巷麻辣片的外观色泽鲜艳&#xff0c;红通通的一片&#xff0c;看着就特…

计算机组成原理之定点除法

文章目录 定点除法运算原码恢复余数法原码不恢复余数法&#xff08;加减交替法&#xff09;运算规则 习题 定点除法运算 注意 &#xff08;1&#xff09;被除数小于除数的时候&#xff0c;商0 &#xff08;2&#xff09;接下来&#xff0c;有一个除数再原来的基础上&#xff0c…

Linux2-系统自有服务防火墙与计划任务

一、什么是防火墙 防火墙主要用于防范网络攻击&#xff0c;防火墙一般分为软件防火墙、硬件防火墙 1、Windows中的防护墙设置 2、防火墙的作用 3、Linux中的防火墙分类 Centos6、Centos6>防火墙>iptables防火墙 防火墙系统管理工具 Centos7>防火墙>firewalld防火…

单目标应用:基于三角拓扑聚合优化算法TTAO的微电网优化(MATLAB代码)

一、微电网模型介绍 微电网多目标优化调度模型简介_vmgpqv-CSDN博客 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、三角拓扑聚合优化算法求解微电网 2.1算法简介 三角拓扑聚合优化算法&…

USB2.0高速转接芯片CH347应用开发手册

CH347应用开发手册 V1.3 一、简介 CH347是一款USB2.0高速转接芯片&#xff0c;以实现USB-UART(HID串口/VCP串口)、USB-SPI、USB-I2C、USB-JTAG以及USB-GPIO等接口&#xff0c;分别包含在芯片的四种工作模式中。 CH347DLL用于为CH347芯片提供操作系统端的UART/SPI/I2C/JTAG/B…

Windows11和Ubuntu22双系统安装指南

一、需求描述 台式机电脑&#xff0c;已有Windows11操作系统&#xff0c;想要安装Ubuntu22系统&#xff08;版本任意&#xff09;。其中Windows安装在Nvme固态上&#xff0c;Ubuntu安装在Sata固态上&#xff0c;双盘双系统。开机时使用Grub控制进入哪个系统&#xff0c;效果图…

Win10“始终使用此应用打开”不见了怎么办?

问题背景 真是服了&#xff0c;昨天家里停电把我电脑系统盘固态烧掉了&#xff0c;于是换了个新的固态给电脑装上新系统。结果这个版本的Win10系统居然无法修改默认应用。具体问题见下面两个图&#xff0c;以py文件为例。 图一&#xff1a;“选择打开方式时没有始终使用此应用…