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

news2024/12/25 0:53:20

        在开发中,发现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.coloradmin.cn/o/1829065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络知识点全面总结回顾

物理层 OSI模型&#xff1a;数据链路层&#xff08;流量控制&#xff09;&#xff0c;从传输层开始端到端&#xff1b;每一层的元素都称为实体&#xff0c;同一层的是对等实体&#xff1b;三个重要概念&#xff1a;服务&#xff08;下层为上层提供调用&#xff09;&#xff0c…

非连续分配管理方式(重点)

目录 一. 基本分页存储管理1.1 什么是分页存储1.2 页表 二. 基本地址变换机构三. 具有快表的地址变换机构3.1 什么是快表3.2 引入快表后, 地址的变换过程3.3 局部性原理 四. 两级页表4.1 单级页表存在什么问题?如何解决?4.2 两级页表的原理、逻辑地址结构4.3 如何实现地址变换…

机器学习笔记 - 用于3D点云数据分割的Point Net的训练

一、数据集简述 ​在本教程中,我们将学习如何在斯坦福 3D 室内场景数据集 ( S3DIS )上训练 Point Net 进行语义分割。S3DIS 是一个 3D 数据集,包含来自多栋建筑的室内空间点云,占地面积超过 6000 平方米。Point Net使用整个点云,能够执行分类和分割任务。如果你一直在关注 …

【机器学习】机器学习与教育科技在个性化教学中的融合应用与性能优化新探索

文章目录 引言机器学习与教育科技的基本概念机器学习概述监督学习无监督学习强化学习 教育科技概述学生学习行为分析个性化学习路径推荐智能化教育评估 机器学习与教育科技的融合应用实时学习数据分析数据预处理特征工程 学生成绩预测与优化模型训练模型评估 个性化学习路径推荐…

初始-Nativefier

--无奈只能靠自己 Nativefier 是什么&#xff1a; Nativefier 是一个命令行工具&#xff0c;仅仅通过一行代码就可以轻松地为任何的网站创建桌面应用程序&#xff0c;应用程序通过 Electron 打包成系统可执行文件&#xff08;如.app, .exe 等&#xff09;&#xff0c;可以运行在…

AI探索:最佳落地应用场景

如果说今年的风口&#xff0c;那一定是 AI。不过AI像一把双刃剑&#xff0c;既有助益也有风险。我们将从IBM Watson的高飞与坠落&#xff0c;到Google Allo的黯然失色&#xff0c;探索AI应用中的教训。同时&#xff0c;瑞幸咖啡的成功故事展现了凭借策略得当的AI应用&#xff0…

MySQL第三方图形化工具:DBeaver

操纵数据库的语言&#xff0c;基于功能划分为4类&#xff1a; 数据定义:DDL(Data Definition Language)库的创建删除、表的创建删除等 数据操纵:DML(Data ManipulationLanguage)新增数据、删除数据、修改数据等 数据控制:DCL(Data ControlLanguage)新增用户、删除用户、密码…

javaWeb项目-springboot+vue人事管理系统功能介绍

本项目源码&#xff1a;java-springbootvue人事管理系统源码说明文档资料资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot…

Redis 键空间迭代 Scan

引言 在平时线上Redis维护工作中&#xff0c;有时候需要从Redis实例成千上万的key中找出特定前缀的key列表来手动处理数据&#xff0c;可能是修改他的值&#xff0c;也可能是删除key。 Redis提供了一个简单暴力的指令keys用来列出所有满足特定正则字符串规则的key。 127.0.0…

【C++】实现学生管理系统(完整版)

&#x1f495;&#x1f495;&#x1f495;大家好&#xff0c;这是作业侠系列之C实现学生管理系统&#xff0c;还是那句话&#xff0c;大家不想cv或者cv了跑不起来,三连后都可以来找我要源码&#xff0c;私信或评论留下你的邮箱即可。有任何问题有可以私聊我&#xff0c;大家觉得…

课时154:项目发布_手工发布_手工发布

1.2.3 手工发布 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习 基础知识 简介 为了合理的演示生产环境的项目代码发布&#xff0c;同时又兼顾实际实验环境的资源&#xff0c;我们这里将 B主机和C主机 用一台VM主机来实现&#xff0c;A主机单…

牛客网刷题 | BC118 N个数之和

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 输入数字N&#xf…

【LeetCode 动态规划】买卖股票的最佳时机问题合集

文章目录 1. 买卖股票的最佳时机含冷冻期 1. 买卖股票的最佳时机含冷冻期 题目链接&#x1f517; &#x1f34e;题目思路&#xff1a; &#x1f34e;题目代码&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();ve…

生产者消费者模型的同步与互斥:C++代码实现

文章目录 一、引言二、生产者消费者模型概述1、基本概念和核心思想2、生产者消费者模型的优点 三、消费者和生产者之间的同步与互斥四、代码实现1、事前准备2、环形队列的实现3、阻塞队列的实现4、两种实现方式的区别 一、引言 在现代计算机系统中&#xff0c;很多任务需要同时…

Spring运维之boo项目表现层测试加载测试的专用配置属性以及在JUnit中启动web服务器发送虚拟请求

测试表现层的代码如何测试 加载测试的专用属性 首先写一个测试 假定我们进行测试的时候要加一些属性 要去修改一些属性 我们可以写一个只在本测试有效的测试 写在配置里 测试 打印输出 我们把配置文件里面的配置注释掉后 我们同样可以启动 package com.example.demo;impo…

专业是软件工程,现在好迷茫,感觉什么都没有学到,该怎么办?

学习软件工程可能会遇到迷茫和困惑的时期&#xff0c;这很正常&#xff0c;尤其是在学习初期。这里有一些建议&#xff0c;或许可以帮助你找到方向&#xff1a; 明确目标&#xff1a;思考你学习软件工程的目的是什么&#xff0c;是为了将来从事软件开发工作&#xff0c;还是对编…

LabVIEW与C#的区别及重新开发自动测试程序的可行性分析

LabVIEW和C#是两种广泛使用的编程语言&#xff0c;各自有不同的应用领域和特点。本文将详细比较LabVIEW与C#在自动测试程序开发中的区别&#xff0c;并分析将已完成的LabVIEW自动测试程序重新用C#开发的合理性。本文帮助评估这种转换的必要性和潜在影响。 LabVIEW与C#的区别 开…

Windows环境利用 OpenCV 中 CascadeClassifier 分类器识别人眼 c++

Windows环境中配置OpenCV 关于在Windows环境中配置opencv的说明&#xff0c;具体可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程。 CascadeClassifier 分类器 CascadeClassifier 是 OpenCV 库中的一个类&#xff0c;它用于实现一种快速的物体检测算法&#xff0c;称…

LSTM模型预测时间序列

长短期记忆模型(Long Short-Term Memory, LSTM)&#xff0c;是一种特殊的循环神经网络&#xff0c;能够学习长期依赖性。长短期记忆模型在各种各样的问题上表现非常出色&#xff0c;现在被广泛使用&#xff0c;例如&#xff0c;文本生成、机器翻译、语音识别、时序数据预测、生…

Matlab电话按键拨号器设计

前言 这篇文章是目前最详细的 Matlab 电话按键拨号器设计开源教程。如果您在做课程设计或实验时需要参考本文章&#xff0c;请注意避免与他人重复&#xff0c;小心撞车。博主做这个也是因为实验所需&#xff0c;我在这方面只是初学者&#xff0c;但实际上&#xff0c;从完全不…