Element-UI 解決el-table中圖片懸浮被遮擋問題小結
在開發(fā)中,發(fā)現element-ui在el-table中添加圖片懸浮顯示時,會被單元格遮擋的問題。通過查詢得到的解決辦法,大多是修改.el-table類中相關樣式屬性,但經過驗證發(fā)現會影響到其他正常功能的使用。對于此問題解決其實也并不難,將懸浮圖片放在body節(jié)點下,通過定位顯示即可。所以對于此問題,將通過Vue.directive鉤子函數,自定義彈框來實現。
一、Vue.directive
在解決上述問題前,先了解下Vue.directive構子函數相關功能。除了Vue中核心功能默認內置的指令(v-model和v-show),Vue也允許注冊自己的指令。如果需要對DOM元素進行底層操作,這時就會用到自定義指令了,directive為“指令”的意思。
1.1 自定義指令對象中構子函數
一個指令定義對象中提供了幾個構子函數,具體如下表:
序號 | 名稱 | 描述 |
---|---|---|
1 | bind | 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。 |
2 | inserted | 被綁定元素插入父節(jié)點時調用 (僅保證父節(jié)點存在,但不一定已被插入文檔中)。 |
3 | update | 所在組件的 VNode 更新時調用,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變,也可能沒有。但是你可以通過比較更新前后的值來忽略不必要的模板更新。 |
4 | componentUpdated | 指令所在組件的 VNode 及其子 VNode 全部更新后調用。 |
5 | unbind | 只調用一次,指令與元素解綁時調用。 |
示例代碼如下:
// 注冊 Vue.directive('my-directive', { bind: function(){}, inserted: function(){}, update: function(){}, componentUpdated: function(){}, unbind: function(){} })
除了以上方式外,如果想注冊局部指令,組件中也接受一個directives的選項,代碼如下:
directives: { focus: { // 指令的定義 inserted: function (el) { el.focus() } } }
1.2 指令構子函數的參數
指令鉤子函數會被傳入以下參數,具體如下表:
序號 | 名稱 | 屬性 | 描述 |
---|---|---|---|
1 | el | 指令所綁定的元素,可以用來直接操作 DOM。 | |
2 | binding | 一個對象,包含以下 property: | |
3 | name | 指令名,不包括 v- 前綴。 | |
4 | value | 指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值為 2。 | |
5 | oldValue | 指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。無論值是否改變都可用。 | |
6 | expression | 字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式為 "1 + 1"。 | |
7 | expression | 傳給指令的參數,可選。例如 v-my-directive:foo 中,參數為 "foo"。 | |
8 | modifiers | 一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象為 { foo: true, bar: true }。 | |
9 | vnode | Vue 編譯生成的虛擬節(jié)點。 | |
10 | oldVnode | 上一個虛擬節(jié)點,僅在 update 和 componentUpdated 鉤子中可用。 |
注間:除了el之外,其它參數都應該是只讀的,切勿進行修改。如果需要在鉤子之間共享數據,建立通過元素的dataset來進行。
二、圖片懸浮功能開發(fā)
這里將通過注冊局部指令,來實現圖片懸浮顯示的功能,在組件中定義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="創(chuàng)建時間" 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 }
此時打開瀏覽器控制中,可以發(fā)現輸出對應img的DOM節(jié)點,如下圖:
2.1 創(chuàng)建懸浮框
首先,我們需要通過javascript創(chuàng)建一個DOM容器,用來顯示懸浮圖片區(qū)域,在項目目錄中創(chuàng)建suspendedDialog.js,并引入到頁面中,來實現懸浮框的創(chuàng)建并插入。
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"; // 圖片節(jié)點類選擇器名稱 this.dialogWidth = 240; // 外容器寬度 this.sDialog = document.createElement('div'); // 外層容器 this.innerBox = document.createElement('div'); // 內容器對象 this.imgBox = document.createElement('img'); // 圖片節(jié)點對象 } /** * 初始化DOM,并添加到body中 */ initialDom(){ const sDialog = document.getElementById(this.idName); // 查詢節(jié)點 // 如果節(jié)點存在,則結束后續(xù)操作 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 }
當在鉤子函數中初始化彈框后,則頁面中節(jié)點創(chuàng)建了一個單例的DOM節(jié)點。如下圖:
2.2 監(jiān)聽事件
通過mouseenter、mouseleave事件來判斷,鼠標是否經過對應圖上節(jié)點或是已離開節(jié)點。 這里需要注意的是,鼠標當在圖片或懸浮區(qū)域圖片上時,懸浮框都正常顯示,移出來隱藏。
2.2.1 修改SuspendedDialog類
此時SuspendedDialog類需要做兩個修改,一是增加setImgUrl()函數,用于修改圖片地址;二是增加懸浮框鼠標移入移出監(jiān)聽事件,用于監(jiān)聽懸浮框是否顯示操作。代碼如下:
/* * 定義彈框類 */ class SuspendedDialog{ constructor(){ this.idName = "suspended-dialog"; // 定義容器ID選擇器名稱 this.innerClassName = "inner"; // 內容器類選擇器名稱 this.imgClassName = "imgs"; // 圖片節(jié)點類選擇器名稱 this.dialogWidth = 240; // 外容器寬度 this.sDialog = document.createElement('div'); // 外層容器 this.innerBox = document.createElement('div'); // 內容器對象 this.imgBox = document.createElement('img'); // 圖片節(jié)點對象 } /** * 初始化DOM,并添加到body中 */ initialDom(){ const sDialog = document.getElementById(this.idName); // 查詢節(jié)點 // 如果節(jié)點存在,則結束后續(xù)操作 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; } /** * 添加監(jiān)聽事件 */ addEvent(){ this.sDialog.addEventListener('mouseenter', e => this.toggle(true)); // 鼠標移入懸浮框區(qū)域時保持顯示 this.sDialog.addEventListener('mouseleave', e => this.toggle(false)); // 鼠標移出懸浮框區(qū)域時隱藏 } /** * 顯示與隱藏 * @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 頁面中事件監(jiān)聽與圖片顯示
當鼠標移入圖片時,先執(zhí)行toggle函數顯示懸浮框,當懸浮框顯示后執(zhí)行回調函數(只有彈框顯示出來后,方可獲取真實的參數數據)。在執(zhí)行回調函數時,將當前鼠標所在圖片的地址獲取,并將其賦給懸浮框中的img節(jié)點對象。
代碼如下 :
import sDialog from './suspendedDialog.js' export default { // ... directives: { // 自定義懸浮v-suspended suspended: { bind: (el) => { // 初始化懸浮框 sDialog.initialDom(); // 鼠標經過圖片并未移出時執(zhí)行回調函數 el.addEventListener('mouseenter', function(e) { // 顯示懸浮彈框,顯示后獲取相應的參數信息 sDialog.toggle(true, () => { sDialog.setImgUrl(el.src); }); }); // 鼠標移出圖片區(qū)域時,隱藏懸浮彈框 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(); // 鼠標經過圖片并未移出時執(zhí)行回調函數 el.addEventListener('mouseenter', function(e) { // 顯示懸浮彈框,顯示后獲取相應的參數信息 sDialog.toggle(true, () => { sDialog.resetPosition(el.getBoundingClientRect()); // 修正彈框位置 sDialog.setImgUrl(el.src); // 修改新的圖片地址 }); }); // 鼠標移出圖片區(qū)域時,隱藏懸浮彈框 el.addEventListener('mouseleave', () => sDialog.toggle(false)); } } }, // end }
此時當鼠標放到圖片上后,控制臺會輸出此圖片元素的邊界信息,如下圖:
另外,懸浮框現在也可以和圖片對齊顯示了,如下圖:
2.3.3 內填充邊距
如圖可見,其實懸浮彈框并未與圖片進行對齊,這是由于在定義樣式時,給外容器添加padding: 12px內填充邊距。
右圖可以清晰看出懸浮彈框三層結構,為什么這里要定義兩個div容器,其目的是解決鼠標從圖片區(qū)域滑到懸浮彈框區(qū)域時,中間不會現出空隙;因為鼠標一旦移出圖片,懸浮框會立即隱藏掉,則不會出現鼠標在懸浮框上保持顯示情況;而增加內填充,圖片與懸浮框看似存在間距,但實際是保持連續(xù)性。
所以我們將內填充距離減掉里可,SuspendedDialog類再次調整,代碼如下:
/* * 定義彈框類 */ class SuspendedDialog{ constructor(){ this.idName = "suspended-dialog"; // 定義容器ID選擇器名稱 this.innerClassName = "inner"; // 內容器類選擇器名稱 this.imgClassName = "imgs"; // 圖片節(jié)點類選擇器名稱 this.dialogWidth = 240; // 外容器寬度 this.dialogPadding = 12; // 外容器內填充 this.sDialog = document.createElement('div'); // 外層容器 this.innerBox = document.createElement('div'); // 內容器對象 this.imgBox = document.createElement('img'); // 圖片節(jié)點對象 } // ... /** * 重新指定彈框位置 * @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();
此時如下圖可見,頂部顯示已對齊狀態(tài)。
在實際開發(fā)中,可能會遇到下圖底部超出情況,或者左側、右側超出情況。這里就不細講了,對界面要求較高的朋友,可以在resetPosition()函數中,通過DOM的邊界信息或其他節(jié)點數據,進行相應計算來多方位處理,使其能按您的需求展示出來。
到此這篇關于Element-UI 解決el-table中圖片懸浮被遮擋問題的文章就介紹到這了,更多相關Element-UI 圖片懸浮被遮擋內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
VuePress在build打包時window?document?is?not?defined問題解決
這篇文章主要為大家介紹了VuePress在build打包時window?document?is?not?defined問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07vue created鉤子函數與mounted鉤子函數的用法區(qū)別
這篇文章主要介紹了vue created鉤子函數與mounted鉤子函數的用法區(qū)別,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11vue+elementUI實現多文件上傳與預覽功能實戰(zhàn)記錄(word/PDF/圖片/docx/doc/xlxs/txt)
這篇文章主要給大家介紹了關于利用vue+elementUI實現多文件上傳與預覽功能的相關資料,包括word/PDF/圖片/docx/doc/xlxs/txt等格式文件上傳,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-08-08Ant Design Vue如何生成動態(tài)菜單a-menu
這篇文章主要介紹了Ant Design Vue如何生成動態(tài)菜單a-menu問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01