Element-UI 解決el-table中圖片懸浮被遮擋問(wèn)題小結(jié)
在開(kāi)發(fā)中,發(fā)現(xiàn)element-ui在el-table中添加圖片懸浮顯示時(shí),會(huì)被單元格遮擋的問(wèn)題。通過(guò)查詢得到的解決辦法,大多是修改.el-table類中相關(guān)樣式屬性,但經(jīng)過(guò)驗(yàn)證發(fā)現(xiàn)會(huì)影響到其他正常功能的使用。對(duì)于此問(wèn)題解決其實(shí)也并不難,將懸浮圖片放在body節(jié)點(diǎn)下,通過(guò)定位顯示即可。所以對(duì)于此問(wèn)題,將通過(guò)Vue.directive鉤子函數(shù),自定義彈框來(lái)實(shí)現(xiàn)。

一、Vue.directive
在解決上述問(wèn)題前,先了解下Vue.directive構(gòu)子函數(shù)相關(guān)功能。除了Vue中核心功能默認(rèn)內(nèi)置的指令(v-model和v-show),Vue也允許注冊(cè)自己的指令。如果需要對(duì)DOM元素進(jìn)行底層操作,這時(shí)就會(huì)用到自定義指令了,directive為“指令”的意思。
1.1 自定義指令對(duì)象中構(gòu)子函數(shù)
一個(gè)指令定義對(duì)象中提供了幾個(gè)構(gòu)子函數(shù),具體如下表:
| 序號(hào) | 名稱 | 描述 |
|---|---|---|
| 1 | bind | 只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置。 |
| 2 | inserted | 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用 (僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)。 |
| 3 | update | 所在組件的 VNode 更新時(shí)調(diào)用,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變,也可能沒(méi)有。但是你可以通過(guò)比較更新前后的值來(lái)忽略不必要的模板更新。 |
| 4 | componentUpdated | 指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用。 |
| 5 | unbind | 只調(diào)用一次,指令與元素解綁時(shí)調(diào)用。 |
示例代碼如下:
// 注冊(cè)
Vue.directive('my-directive', {
bind: function(){},
inserted: function(){},
update: function(){},
componentUpdated: function(){},
unbind: function(){}
})除了以上方式外,如果想注冊(cè)局部指令,組件中也接受一個(gè)directives的選項(xiàng),代碼如下:
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}1.2 指令構(gòu)子函數(shù)的參數(shù)
指令鉤子函數(shù)會(huì)被傳入以下參數(shù),具體如下表:
| 序號(hào) | 名稱 | 屬性 | 描述 |
|---|---|---|---|
| 1 | el | 指令所綁定的元素,可以用來(lái)直接操作 DOM。 | |
| 2 | binding | 一個(gè)對(duì)象,包含以下 property: | |
| 3 | name | 指令名,不包括 v- 前綴。 | |
| 4 | value | 指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值為 2。 | |
| 5 | oldValue | 指令綁定的前一個(gè)值,僅在 update 和 componentUpdated 鉤子中可用。無(wú)論值是否改變都可用。 | |
| 6 | expression | 字符串形式的指令表達(dá)式。例如 v-my-directive="1 + 1" 中,表達(dá)式為 "1 + 1"。 | |
| 7 | expression | 傳給指令的參數(shù),可選。例如 v-my-directive:foo 中,參數(shù)為 "foo"。 | |
| 8 | modifiers | 一個(gè)包含修飾符的對(duì)象。例如:v-my-directive.foo.bar 中,修飾符對(duì)象為 { foo: true, bar: true }。 | |
| 9 | vnode | Vue 編譯生成的虛擬節(jié)點(diǎn)。 | |
| 10 | oldVnode | 上一個(gè)虛擬節(jié)點(diǎn),僅在 update 和 componentUpdated 鉤子中可用。 |
注間:除了el之外,其它參數(shù)都應(yīng)該是只讀的,切勿進(jìn)行修改。如果需要在鉤子之間共享數(shù)據(jù),建立通過(guò)元素的dataset來(lái)進(jìn)行。
二、圖片懸浮功能開(kāi)發(fā)
這里將通過(guò)注冊(cè)局部指令,來(lái)實(shí)現(xiàn)圖片懸浮顯示的功能,在組件中定義directives選項(xiàng)。如須全局注冊(cè),可以將以下功能移植到Vue.directive()中定義。
html中在img標(biāo)簽上添加v-suspended,代碼如下:
<template>
<div>
<el-table size="mini" border :data="tableData">
<el-table-column type="index" label="序號(hào)" 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="創(chuàng)建時(shí)間" prop="createtime"></el-table-column>
<el-table-column label="更新時(shí)間" 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
}此時(shí)打開(kāi)瀏覽器控制中,可以發(fā)現(xiàn)輸出對(duì)應(yīng)img的DOM節(jié)點(diǎn),如下圖:

2.1 創(chuàng)建懸浮框
首先,我們需要通過(guò)javascript創(chuàng)建一個(gè)DOM容器,用來(lái)顯示懸浮圖片區(qū)域,在項(xiàng)目目錄中創(chuàng)建suspendedDialog.js,并引入到頁(yè)面中,來(lái)實(shí)現(xiàn)懸浮框的創(chuàng)建并插入。

2.1.1 樣式
這里樣式通過(guò)less編寫(xiě)的,注意您項(xiàng)目中使用的css預(yù)處理器。另外需要注意的是,此彈框默認(rèn)為display:none(不顯示模式),只有當(dāng)鼠標(biāo)懸浮到對(duì)應(yīng)圖片上時(shí),通過(guò)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"; // 內(nèi)容器類選擇器名稱
this.imgClassName = "imgs"; // 圖片節(jié)點(diǎn)類選擇器名稱
this.dialogWidth = 240; // 外容器寬度
this.sDialog = document.createElement('div'); // 外層容器
this.innerBox = document.createElement('div'); // 內(nèi)容器對(duì)象
this.imgBox = document.createElement('img'); // 圖片節(jié)點(diǎn)對(duì)象
}
/**
* 初始化DOM,并添加到body中
*/
initialDom(){
const sDialog = document.getElementById(this.idName); // 查詢節(jié)點(diǎn)
// 如果節(jié)點(diǎn)存在,則結(jié)束后續(xù)操作
if(sDialog) return;
// 初始經(jīng)屬性
this.sDialog.id = this.idName;
this.innerBox.classList.add(this.innerClassName);
this.imgBox.classList.add(this.imgClassName);
// 將DOM追加到對(duì)應(yīng)容器中
this.innerBox.append(this.imgBox);
this.sDialog.append(this.innerBox);
document.body.append(this.sDialog);
}
/**
* 顯示與隱藏
* @param {Object} flag
* @param {Object} callback 回調(diào)函數(shù)
*/
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();單例模式是一種常見(jiàn)的設(shè)計(jì)模式,目的是確保一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)來(lái)訪問(wèn)這個(gè)唯一的實(shí)例。
2.1.3 頁(yè)面引入
頁(yè)面代碼如下:
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
}當(dāng)在鉤子函數(shù)中初始化彈框后,則頁(yè)面中節(jié)點(diǎn)創(chuàng)建了一個(gè)單例的DOM節(jié)點(diǎn)。如下圖:

2.2 監(jiān)聽(tīng)事件
通過(guò)mouseenter、mouseleave事件來(lái)判斷,鼠標(biāo)是否經(jīng)過(guò)對(duì)應(yīng)圖上節(jié)點(diǎn)或是已離開(kāi)節(jié)點(diǎn)。 這里需要注意的是,鼠標(biāo)當(dāng)在圖片或懸浮區(qū)域圖片上時(shí),懸浮框都正常顯示,移出來(lái)隱藏。
2.2.1 修改SuspendedDialog類
此時(shí)SuspendedDialog類需要做兩個(gè)修改,一是增加setImgUrl()函數(shù),用于修改圖片地址;二是增加懸浮框鼠標(biāo)移入移出監(jiān)聽(tīng)事件,用于監(jiān)聽(tīng)?wèi)腋】蚴欠耧@示操作。代碼如下:
/*
* 定義彈框類
*/
class SuspendedDialog{
constructor(){
this.idName = "suspended-dialog"; // 定義容器ID選擇器名稱
this.innerClassName = "inner"; // 內(nèi)容器類選擇器名稱
this.imgClassName = "imgs"; // 圖片節(jié)點(diǎn)類選擇器名稱
this.dialogWidth = 240; // 外容器寬度
this.sDialog = document.createElement('div'); // 外層容器
this.innerBox = document.createElement('div'); // 內(nèi)容器對(duì)象
this.imgBox = document.createElement('img'); // 圖片節(jié)點(diǎn)對(duì)象
}
/**
* 初始化DOM,并添加到body中
*/
initialDom(){
const sDialog = document.getElementById(this.idName); // 查詢節(jié)點(diǎn)
// 如果節(jié)點(diǎn)存在,則結(jié)束后續(xù)操作
if(sDialog) return;
// 初始經(jīng)屬性
this.sDialog.id = this.idName;
this.innerBox.classList.add(this.innerClassName);
this.imgBox.classList.add(this.imgClassName);
// 將DOM追加到對(duì)應(yīng)容器中
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;
}
/**
* 添加監(jiān)聽(tīng)事件
*/
addEvent(){
this.sDialog.addEventListener('mouseenter', e => this.toggle(true)); // 鼠標(biāo)移入懸浮框區(qū)域時(shí)保持顯示
this.sDialog.addEventListener('mouseleave', e => this.toggle(false)); // 鼠標(biāo)移出懸浮框區(qū)域時(shí)隱藏
}
/**
* 顯示與隱藏
* @param {Object} flag
* @param {Object} callback 回調(diào)函數(shù)
*/
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 頁(yè)面中事件監(jiān)聽(tīng)與圖片顯示
當(dāng)鼠標(biāo)移入圖片時(shí),先執(zhí)行toggle函數(shù)顯示懸浮框,當(dāng)懸浮框顯示后執(zhí)行回調(diào)函數(shù)(只有彈框顯示出來(lái)后,方可獲取真實(shí)的參數(shù)數(shù)據(jù))。在執(zhí)行回調(diào)函數(shù)時(shí),將當(dāng)前鼠標(biāo)所在圖片的地址獲取,并將其賦給懸浮框中的img節(jié)點(diǎn)對(duì)象。
代碼如下 :
import sDialog from './suspendedDialog.js'
export default {
// ...
directives: {
// 自定義懸浮v-suspended
suspended: {
bind: (el) => {
// 初始化懸浮框
sDialog.initialDom();
// 鼠標(biāo)經(jīng)過(guò)圖片并未移出時(shí)執(zhí)行回調(diào)函數(shù)
el.addEventListener('mouseenter', function(e) {
// 顯示懸浮彈框,顯示后獲取相應(yīng)的參數(shù)信息
sDialog.toggle(true, () => {
sDialog.setImgUrl(el.src);
});
});
// 鼠標(biāo)移出圖片區(qū)域時(shí),隱藏懸浮彈框
el.addEventListener('mouseleave', () => sDialog.toggle(false));
}
}
},
// end
}運(yùn)行后結(jié)果如下圖:

2.3 計(jì)算懸浮框位置
如上結(jié)果可見(jiàn),現(xiàn)在鼠標(biāo)放到對(duì)應(yīng)的圖片上后,懸浮框可以顯示對(duì)應(yīng)圖片信息了;但是懸浮框還未與圖片進(jìn)行對(duì)齊,此地則需要通過(guò)獲取相應(yīng)參數(shù)數(shù)據(jù),進(jìn)行計(jì)算來(lái)重新指定懸浮框位置。
2.3.1修改SuspendedDialog類
在SuspendedDialog類中新增resetPosition()函數(shù),用于修正懸浮彈框在新圖片的位置。
示例代碼如下:
/*
* 定義彈框類
*/
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 頁(yè)面中獲取元素邊界信息
當(dāng)SuspendedDialog類中修正彈框位置的resetPosition()函數(shù)定義好后,頁(yè)面中則可以直接調(diào)用了。而DOM元素的邊界信息,通過(guò)el.getBoundingClientRect()直接獲取即可。
示例代碼如下:
import sDialog from './suspendedDialog.js'
export default {
// ...
directives: {
// 自定義懸浮v-suspended
suspended: {
bind: (el) => {
// 初始化懸浮框
sDialog.initialDom();
// 鼠標(biāo)經(jīng)過(guò)圖片并未移出時(shí)執(zhí)行回調(diào)函數(shù)
el.addEventListener('mouseenter', function(e) {
// 顯示懸浮彈框,顯示后獲取相應(yīng)的參數(shù)信息
sDialog.toggle(true, () => {
sDialog.resetPosition(el.getBoundingClientRect()); // 修正彈框位置
sDialog.setImgUrl(el.src); // 修改新的圖片地址
});
});
// 鼠標(biāo)移出圖片區(qū)域時(shí),隱藏懸浮彈框
el.addEventListener('mouseleave', () => sDialog.toggle(false));
}
}
},
// end
}此時(shí)當(dāng)鼠標(biāo)放到圖片上后,控制臺(tái)會(huì)輸出此圖片元素的邊界信息,如下圖:

另外,懸浮框現(xiàn)在也可以和圖片對(duì)齊顯示了,如下圖:

2.3.3 內(nèi)填充邊距
如圖可見(jiàn),其實(shí)懸浮彈框并未與圖片進(jìn)行對(duì)齊,這是由于在定義樣式時(shí),給外容器添加padding: 12px內(nèi)填充邊距。
右圖可以清晰看出懸浮彈框三層結(jié)構(gòu),為什么這里要定義兩個(gè)div容器,其目的是解決鼠標(biāo)從圖片區(qū)域滑到懸浮彈框區(qū)域時(shí),中間不會(huì)現(xiàn)出空隙;因?yàn)槭髽?biāo)一旦移出圖片,懸浮框會(huì)立即隱藏掉,則不會(huì)出現(xiàn)鼠標(biāo)在懸浮框上保持顯示情況;而增加內(nèi)填充,圖片與懸浮框看似存在間距,但實(shí)際是保持連續(xù)性。


所以我們將內(nèi)填充距離減掉里可,SuspendedDialog類再次調(diào)整,代碼如下:
/*
* 定義彈框類
*/
class SuspendedDialog{
constructor(){
this.idName = "suspended-dialog"; // 定義容器ID選擇器名稱
this.innerClassName = "inner"; // 內(nèi)容器類選擇器名稱
this.imgClassName = "imgs"; // 圖片節(jié)點(diǎn)類選擇器名稱
this.dialogWidth = 240; // 外容器寬度
this.dialogPadding = 12; // 外容器內(nèi)填充
this.sDialog = document.createElement('div'); // 外層容器
this.innerBox = document.createElement('div'); // 內(nèi)容器對(duì)象
this.imgBox = document.createElement('img'); // 圖片節(jié)點(diǎn)對(duì)象
}
// ...
/**
* 重新指定彈框位置
* @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();此時(shí)如下圖可見(jiàn),頂部顯示已對(duì)齊狀態(tài)。

在實(shí)際開(kāi)發(fā)中,可能會(huì)遇到下圖底部超出情況,或者左側(cè)、右側(cè)超出情況。這里就不細(xì)講了,對(duì)界面要求較高的朋友,可以在resetPosition()函數(shù)中,通過(guò)DOM的邊界信息或其他節(jié)點(diǎn)數(shù)據(jù),進(jìn)行相應(yīng)計(jì)算來(lái)多方位處理,使其能按您的需求展示出來(lái)。

到此這篇關(guān)于Element-UI 解決el-table中圖片懸浮被遮擋問(wèn)題的文章就介紹到這了,更多相關(guān)Element-UI 圖片懸浮被遮擋內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VuePress在build打包時(shí)window?document?is?not?defined問(wèn)題解決
這篇文章主要為大家介紹了VuePress在build打包時(shí)window?document?is?not?defined問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
vue created鉤子函數(shù)與mounted鉤子函數(shù)的用法區(qū)別
這篇文章主要介紹了vue created鉤子函數(shù)與mounted鉤子函數(shù)的用法區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
vue+elementUI實(shí)現(xiàn)多文件上傳與預(yù)覽功能實(shí)戰(zhàn)記錄(word/PDF/圖片/docx/doc/xlxs/txt)
這篇文章主要給大家介紹了關(guān)于利用vue+elementUI實(shí)現(xiàn)多文件上傳與預(yù)覽功能的相關(guān)資料,包括word/PDF/圖片/docx/doc/xlxs/txt等格式文件上傳,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Vue?瀏覽器本地存儲(chǔ)的問(wèn)題小結(jié)
這篇文章主要介紹了Vue?瀏覽器本地存儲(chǔ),LocalStorage 和 SessionStorage 統(tǒng)稱為 WebStorage,存儲(chǔ)大小一般支持5mb左右,但是不同的瀏覽器也有區(qū)別,具體內(nèi)容介紹跟隨小編一起看看吧2022-04-04
Ant Design Vue如何生成動(dòng)態(tài)菜單a-menu
這篇文章主要介紹了Ant Design Vue如何生成動(dòng)態(tài)菜單a-menu問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
使用vuetify實(shí)現(xiàn)全局v-alert消息通知的方法
使用強(qiáng)大的Vuetify開(kāi)發(fā)前端頁(yè)面,結(jié)果發(fā)現(xiàn)官方?jīng)]有提供簡(jiǎn)便的全局消息通知組件,所以自己動(dòng)手寫(xiě)了一個(gè)簡(jiǎn)單的組件,接下來(lái)通過(guò)本文給大家介紹使用vuetify實(shí)現(xiàn)全局v-alert消息通知的詳細(xì)代碼,感興趣的朋友跟隨小編一起看看吧2024-02-02
Vue動(dòng)態(tài)獲取數(shù)據(jù)后控件不可編輯問(wèn)題
這篇文章主要介紹了Vue動(dòng)態(tài)獲取數(shù)據(jù)后控件不可編輯問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04

