vue實現(xiàn)el-table點選和鼠標(biāo)框選功能的方法
實現(xiàn)思路: 項目有兩個需求,既能在el-table實現(xiàn)點選又能實現(xiàn)鼠標(biāo)框選
一. 點選實現(xiàn)思路: 使用el-table的cellClick方法,
1.直接給點擊的cell添加類名,cell.classList.add("blue-cell");然后把獲取的數(shù)據(jù)存入數(shù)組,
設(shè)置樣式:
::v-deep .el-table td.blue-cell { border: 1px solid blue !important; }
方法2.如果不添加類名,可以在cellStyle方法里通過存儲的數(shù)組添加邊框,如果是普通滾動可以使用行索引,如果是虛擬滾動,這里需要使用id更為準(zhǔn)確
cellStyle({ row, column, rowIndex, columnIndex }) { // 對xqArr選擇選區(qū)的單元格加藍(lán)邊框 let matchObj = this.xqArr.find( item => item.column === column.index && // item.row === row.index && item.rowId === row.id && item.sampleTime === row.sampleTime ); if (matchObj) { return { border: "1px solid #5E99FD" }; } }
二.鼠標(biāo)框選實現(xiàn)思路:
利用鼠標(biāo)按下和抬起事件,計算框的范圍,框住的cell可以通過類名添加邊框或者依然通過數(shù)組形式. 需要注意的是因為el-table在頁面的右下方,并且數(shù)據(jù)量大,可以滾動,所以需要在計算距離的時候需要減去容器偏移的距離和滾動的高度.
<el-table border :lazy="true" v-loading="loading" @cell-click="cellClick" :cell-class-name="tableCellClassName" @row-contextmenu="rightClick" @row-click="clickTableRow" @mousedown.native="down($event)" @mousemove.native="move($event)" @mouseup.native="up($event)" :data="historyDataTables" :highlight-current-row="true" :stripe="true" :header-cell-style="{ background: '#cff7ff', fontWeight: 'bold', color: '#080809' }" :row-height="30" :total="totalCount" :cell-style="cellStyle" :max-height="maxHeight1" @selection-change="handleSelectionChange" ref="multipleTable" :row-key="row => row.id" id="table" >
<script> export default { data() { return { // 列表集合 historyDataTables: [], select: false, isMouseDown: true, // 是否需要(允許)處理鼠標(biāo)的移動事件 // 定義移動元素div rect: null, // 記錄鼠標(biāo)按下時的坐標(biāo) downX: 0, downY: 0, // 記錄鼠標(biāo)抬起時候的坐標(biāo) mouseX2: this.downX, mouseY2: this.downY, // 表格dom元素 TableDom: null, tableHeaderHeight: 0, selectedData: [], // 鼠標(biāo)框選選中的數(shù)據(jù) selectedCellTop: 0, // 選中單元格距離el-table頂部的距離 selectedCellLeft: 0, // 選中單元格距離el-table左側(cè)的距離 tableRectTop: 0, // el-table距離window頂部的距離 tableRectLeft: 0, // el-table距離window左側(cè)的距離 tableScrollTop: 0, // el-table滾動的距離 } }, mounted() { this.TableDom = this.$refs.multipleTable.$el; // 獲取table元素 // 獲取table的位置,監(jiān)聽窗口變化,table的距離變化 this.getTableMarginLeft(); window.addEventListener("resize", this.getTableMarginLeft); this.clientWidth = document.documentElement.clientWidth || document.body.clientWidth; this.clientHeight = document.documentElement.clientHeight || document.body.cientHeight; this.otherHeight = Math.ceil($(".is-always-shadow").outerHeight()) + Math.ceil($(".is-top").outerHeight()); this.maxHeight1 = this.clientHeight - this.otherHeight - 150 + "px"; var that = this; window.onresize = () => { return (() => { window.clientHeight = document.documentElement.clientHeight || document.body.clientHeight; that.clientHeight = window.clientHeight; })(); }; }, beforeDestroy() { window.removeEventListener("resize", this.getTableMarginLeft); }, methods: { // 獲取table距離頁面左側(cè)和上方的距離 getTableMarginLeft() { const tableRect = this.TableDom.getBoundingClientRect(); // 獲取el-table元素的位置信息 this.tableRectTop = Math.ceil(tableRect.top); this.tableRectLeft = Math.ceil(tableRect.left); }, down(event) { // 當(dāng)允許鼠標(biāo)按下時,才允許處理鼠標(biāo)的移動事件,這里結(jié)合項目其他問題所以設(shè)置了判斷條件 if (this.isMouseDown) { this.select = true; this.rect = document.createElement("div"); // 框選div 樣式 this.rect.style.cssText = "position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px solid #0099FF;background-color:#C3D5ED;z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;"; this.rect.id = "selectDiv"; this.getTableMarginLeft(); const container = document.querySelector(".el-table__body-wrapper"); // 獲取table容器元素 this.TableDom.appendChild(this.rect); // 添加到table元素下 // 取得鼠標(biāo)按下時的坐標(biāo)位置 this.downX = event.x || event.clientX + container.scrollLeft - this.tableRectLeft; // 鼠標(biāo)按下時的x軸坐標(biāo) event.x 兼容火狐瀏覽器, event.clientX 兼容谷歌瀏覽器 this.downY = event.y || event.clientY + container.scrollTop - this.tableRectTop; // 鼠標(biāo)按下時的y軸坐標(biāo) this.rect.style.left = this.downX + "px"; // 設(shè)置你要畫的矩形框的起點位置 this.rect.style.top = this.downY + "px"; // 設(shè)置你要畫的矩形框的起點位置 //設(shè)置你要畫的矩形框的起點位置 this.rect.style.left = this.downX; // 因為在火狐瀏覽器下,上面的代碼不起作用,所以在這里再寫一遍,為什么火狐瀏覽器不起作用,因為火狐瀏覽器下,我們的div是絕對定位的,所以我們要加上px,為什么這里沒加px,因為我們下面要加上px,所以這里不用加 this.rect.style.top = this.downY; } else { return; } }, move(event) { /* 這個部分,根據(jù)你鼠標(biāo)按下的位置,和你拉框時鼠標(biāo)松開的位置關(guān)系,可以把區(qū)域分為四個部分,根據(jù)四個部分的不同, 我們可以分別來畫框,否則的話,就只能向一個方向畫框,也就是點的右下方畫框. */ if (this.select && this.isMouseDown) { // 取得鼠標(biāo)移動時的坐標(biāo)位置 this.mouseX2 = event.clientX; // 鼠標(biāo)移動時的x軸坐標(biāo) this.mouseY2 = event.clientY; // 鼠標(biāo)移動時的y軸坐標(biāo) // 框選元素的顯示與隱藏 if (this.rect.style.display == "none") { this.rect.style.display = ""; } // 框選元素的位置處理 this.rect.style.left = Math.min(this.mouseX2, this.downX) - this.tableRectLeft + "px"; this.rect.style.top = Math.min(this.mouseY2, this.downY) - this.tableRectTop + "px"; // 取得鼠標(biāo)拉框時的起點坐標(biāo) this.rect.style.width = Math.abs(this.mouseX2 - this.downX) + "px"; // 取得鼠標(biāo)拉框時的寬度 this.rect.style.height = Math.abs(this.mouseY2 - this.downY) + "px"; // 取得鼠標(biāo)拉框時的高度 // A part if (this.mouseX2 < this.downX && this.mouseY2 < this.downY) { this.rect.style.left = this.mouseX2 + this.tableRectLeft; this.rect.style.top = this.mouseY2 + this.tableRectTop; } // B part if (this.mouseX2 > this.downX && this.mouseY2 < this.downY) { this.rect.style.left = this.downX + this.tableRectLeft; this.rect.style.top = this.mouseY2 + this.tableRectTop; } // C part if (this.mouseX2 < this.downX && this.mouseY2 > this.downY) { this.rect.style.left = this.mouseX2 + this.tableRectLeft; this.rect.style.top = this.downY + this.tableRectTop; } // D part if (this.mouseX2 > this.downX && this.mouseY2 > this.downY) { this.rect.style.left = this.downX + this.tableRectLeft; this.rect.style.top = this.downY + this.tableRectTop; } } else { return; } this.stopEvent(event); }, // 阻止默認(rèn)事件 stopEvent(event) { if (event.stopPropagation) { // 標(biāo)準(zhǔn)瀏覽器 event.stopPropagation(); // 阻止事件冒泡 event.preventDefault(); // 阻止默認(rèn)事件 } else { // IE瀏覽器 event.cancelBubble = true; event.returnValue = false; } }, // 鼠標(biāo)抬起事件 up() { if (this.select && this.isMouseDown) { const container = document.querySelector(".el-table__body-wrapper"); // 獲取table容器元素 const scrollTop = container.scrollTop; // 獲取el-table的scrollTop和scrollLeft const scrollLeft = container.scrollLeft; const headerWrapper = this.TableDom.querySelector( ".el-table__header-wrapper" ); const tableHeaderHeight = Math.ceil( headerWrapper.getBoundingClientRect().height ); const columns = this.$refs.multipleTable.columns; // 表格的標(biāo)題 const rectLeft = this.rect.offsetLeft + scrollLeft - this.tableRectLeft; const rectTop = this.rect.offsetTop + scrollTop - this.tableRectTop - tableHeaderHeight; const tableBody = document.querySelector(".el-table__body"); tableBody.children[1].childNodes.forEach(element => { for (let index = 0; index < element.childNodes.length; index++) { // 獲取當(dāng)前單元格 const cell = element.childNodes[index]; if ( // 判斷選中的單元格是否在鼠標(biāo)拉框的范圍內(nèi) rectLeft < cell.offsetLeft - this.tableRectLeft + cell.offsetWidth && rectLeft + this.rect.offsetWidth > cell.offsetLeft - this.tableRectLeft && rectTop < cell.offsetTop - this.tableRectTop + cell.offsetHeight && rectTop + this.rect.offsetHeight > cell.offsetTop - this.tableRectTop && index >= 3 // 選中的單元格所在列的索引大于等于3 ) { if (cell.className.indexOf("add") == -1) { // cell.style.border = "1px solid red"; const cellText = cell.innerText; const rowData = this.historyDataTables[element.rowIndex]; // 獲取當(dāng)前單元格所在的行數(shù)據(jù) // 獲取表格的列名的屬性名property let columnProperty = undefined; // 遍歷第一行數(shù)據(jù) // console.log(index, '--index--'); // 框選數(shù)據(jù)所在列的索引 for (const item of columns) { if (item.index === index) { columnProperty = item.property; break; } } // const rowIndex = element.rowIndex; // 將當(dāng)前單元格所在的行數(shù)據(jù)加入到該列數(shù)據(jù)中 const columnIndex = index; const time = rowData.sampleTime; // 選擇要添加到選中行數(shù)組中的屬性 const selected = { rowId: rowData.id, // row: rowIndex, column: columnIndex, sampleTime: time, factor: columnProperty, tag: rowData[columnProperty + "_tag"] || "", tagStatus: rowData[columnProperty + "_tag_status"] || "", mark: rowData[columnProperty + "_mark"] || "" }; // 將選中數(shù)據(jù)加入到狀態(tài)中已有的數(shù)據(jù)中,如果已有相同的數(shù)據(jù),則不加入 if ( !this.selectedData.some(data => this.isEqual(data, selected)) ) { this.selectedData.push(selected); } // 將選中數(shù)據(jù)加入到 xqArr 中 this.selectedData.forEach(item => { // 如果 xqArr 中已有相同數(shù)據(jù),則不加入 if (!this.xqArr.some(data => this.isEqual(data, item))) { this.xqArr.push(item); } }); this.selectedData = []; } } } }); //鼠標(biāo)抬起,就不允許在處理鼠標(biāo)移動事件 this.select = false; //隱藏圖層 if (this.rect) { this.TableDom.removeChild(this.rect); } } else { return; } }, // 定義方法 isEqual 來比較兩個選中數(shù)據(jù)對象是否相同 isEqual(data1, data2) { return ( data1.rowId === data2.rowId && data1.column === data2.column && data1.sampleTime === data2.sampleTime && data1.factor === data2.factor ); } } }
總結(jié)
到此這篇關(guān)于vue實現(xiàn)el-table點選和鼠標(biāo)框選功能的文章就介紹到這了,更多相關(guān)vue el-table點選和鼠標(biāo)框選 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elementPlus?的el-select在提示框關(guān)閉時自動彈出的問題解決
這篇文章主要介紹了elementPlus?的el-select在提示框關(guān)閉時自動彈出閉時自動彈出的問題,主要問題就是因為filterable屬性,根本解決方案是選中的時候讓他失去焦點?el-select有一個visible-change事件,下拉框出現(xiàn)/隱藏時觸發(fā),感興趣的朋友跟隨小編一起看看吧2024-01-01深入淺析Vue.js中 computed和methods不同機制
這篇文章給大家介紹了Vue.js中 computed和methods不同機制,在vue.js中,methods和computed兩種方式來動態(tài)當(dāng)作方法使用,文中還給大家提到了computed和methods的區(qū)別,感興趣的朋友一起看看吧2018-03-03vuex頁面刷新導(dǎo)致數(shù)據(jù)丟失的解決方案
這篇文章主要介紹了vuex頁面刷新導(dǎo)致數(shù)據(jù)丟失的解決方案,幫助大家更好的使用vue框架,感興趣的朋友可以了解下2020-12-12Vue.js 2.0窺探之Virtual DOM到底是什么?
大家可能聽說Vue.js 2.0已經(jīng)發(fā)布,并且在其中新添加如了一些新功能。其中一個功能就是“Virtual DOM”。那么下面這篇文章就來給大家詳細(xì)介紹Vue.js 2.0中的Virtual DOM到底是什么?需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02echarts3如何清空上一次加載的series數(shù)據(jù)
這篇文章主要介紹了echarts3如何清空上一次加載的series數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10淺析Vue中defineProps的解構(gòu)和不解構(gòu)
defineProps?是?Vue?3?Composition?API?中用來聲明組件接收的?props?的方法,本文主要為大家介紹了defineProps的解構(gòu)和不解構(gòu),感興趣的可以了解下2025-02-02