前言:主要是 table 表格框选功能
实现功能如下:
- 表格框选功能
- 右键操作功能(删除、查看、编辑)
- 分页功能
- 表头分类筛选功能
- 回显功能(显示默认选中数据)
- 排序功能
- 行禁用不可选功能
不说废话,直接上代码,简单粗暴。。。
1、组件
/*
* @auhor : 开发部-前端组-李鑫超
* @property { tableData : {Array} 表格数据 add v-1.0.0 }
* @property { columData : {Array} 表头数据 add v-1.0.0 }
* @property { menuList : {Array} 右键菜单 add v-1.0.0 }
* @property { myKey : {String} 唯一标识。 add v-1.0.0 }
* @property { isRadio : {Boolean} 是否单选,默认false。 add v-1.0.0 }
* @property { showpage : {Boolean} 是否显示分页,默认false。 add v-1.0.0 }
* @property { currentPage : {Number} 当前页,默认1。 add v-1.0.0 }
* @property { pageSize : {Number} 每页显示条目个数, 默认20。 add v-1.0.0 }
* @property { pageTotal : {Number} 总条目数。 add v-1.0.0 }
* @property { backMultipleSelection : {Array} 回显数据。 add v-1.0.0 }
* @property { emptyText : {String} 空数据时显示的文本内容,默认暂无数据。 add v-1.0.0 }
* @property { rowDisabled : {String} 行禁用时,根据该字段判断。 add v-1.0.0 }
* @property { pageDataFlag : {Boolean} 翻页时,是否保存其他页面选中的数据,默认值false。 add v-1.0.0 }
* @property { sortable : {Boolean,String} 对应列是否可以排序,如果设置为 'custom',则代表用户希望远程排序,需要监听 Table 的 sort-change 事件。 add v-1.0.0 }
* @method { makesure : {Function(data)} 表头tree点击事件 add v-1.0.0 }
* @method { menuClick : {Function(item)} item 表格右键选项事件 add v-1.0.0 }
* @method { currentPageChange : {Function(page)} 当前页改变事件事件 add v-1.0.0 }
* @method { handleSelect : {Function(data)} 选中数据时会触发该事件 add v-1.0.0 }
* @method { sortChange : {Function(column, prop, order)} 点击表头排序按钮会触发该事件 add v-1.0.0 }
* @version 1.2.0
* @edit: 2018/10/24
*/
<template>
<div class='air-table-wrapper'>
<el-table ref="table"
:show-header="true"
:data="tableData"
tooltip-effect="dark"
style="width: 100%;"
:height="height"
:header-row-class-name="headerClassName"
id="table"
@row-click="rowClick"
@selection-change="selectionChange"
@select-all="selectAll"
@select="selectItem"
@row-contextmenu="rowContextmenu"
@row-dblclick="rowDblclick"
@header-click="headerClick"
@empty-text="emptyText"
@sort-change="sortChange"
v-drag>
<!-- checkbox -->
<el-table-column type="selection"
width="56"
align="center"
:selectable="selectable"></el-table-column>
<!-- index 序号 -->
<el-table-column v-if="isType == 'index'"
:index="indexMethod"
type="index"
:label="'序号'"
width="56"
align="center"></el-table-column>
<!--列表的表头循环-->
<el-table-column v-for="(column, index) in columData"
:key="index"
:sortable="sortable"
:label="column.name"
:width="column.width">
<template slot-scope="scope">
<!--把所有的数据都变成插槽导出-->
<slot :name="column.key"
:row="scope.row"></slot>
</template>
</el-table-column>
<!-- 分页 -->
<template slot=append
v-if="currentshowPage">
<div :class="showAdd ? 'el-table__append-pageAdd el-table__append-page': 'el-table__append-page'">
<el-pagination @size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="page"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="pageTotal">
</el-pagination>
</div>
</template>
<!-- 添加按钮 -->
<template slot=append
v-if="showAdd">
<airButton buttonType="colorButtonroundOrange"
@click="addClick"></airButton>
</template>
</el-table>
<!-- 右键菜单 -->
<air-contex-menu v-if="menuList.length"
:position="position"
:toggleShow="toggleShow"
:menuList="menuList"
@menuClick="menuClick">
</air-contex-menu>
<!-- 弹出窗 -->
<tree-dialog ref="treeDialog"
:pid="treePid"
:name="treeName"
:id="treeId"
:data="treeData"
@makesure=makesure
placeholder="输入信息,按回车搜索"
:title='treeTitle'>
</tree-dialog>
</div>
</template>
<script>
import airContexMenu from "./contextMenu.js";
import treeDialog from "@/components/newCommon/dialog/treeDialog.vue";
export default {
name: "airtable",
// 框选的指令
directives: {
drag: {
// 指令的定义
inserted: function (el, binding, vnode) {
var oDiv = el;
vnode.context.tableTop = getY(oDiv);
vnode.context.tableLeft = getX(oDiv);
//方法是确定列表到屏幕的位置
function getX(obj) {
var parObj = obj;
var left = obj.offsetLeft;
while ((parObj = parObj.offsetParent)) {
left += parObj.offsetLeft;
}
return left;
}
//方法是确定列表到屏幕的位置
function getY(obj) {
var parObj = obj;
var top = obj.offsetTop;
while ((parObj = parObj.offsetParent)) {
top += parObj.offsetTop;
}
return top;
}
// 禁止右键默认菜单
oDiv.oncontextmenu = function () {
return false;
}
oDiv.onmousedown = function (ev) {
// 防止奇葩操作
if ([2, 3, 4, 5].indexOf(ev.buttons) > -1) {
if (selDiv) {
oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);
}
return
}
// 获取当前scrollTop
var scrollingTop = vnode.context.targetScroll;
if (vnode.context.isRadio) return;
vnode.context.$selectState(true);
//初始化不显示
vnode.context.toggleShow = false;
//确保用户在移动鼠标的时候只初始化一次选中
var flag = true;
// 获取表格的宽高
let tableWidth = vnode.context.$el.clientWidth;
let tableHeight = vnode.context.$el.clientHeight;
//用来存储列表
var selList = [];
//获得指令下的dom对应的表格
var fileNodes = oDiv.getElementsByTagName("tr");
//获得鼠标
var evt = window.event || arguments[0];
var startX = evt.x || evt.clientX;
var startY = evt.y || evt.clientY;
var top, left;
//时时获得
top = getY(oDiv);
left = getX(oDiv);
var selDiv = document.createElement("div");
selDiv.style.cssText =
"position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px solid rgba(255,165,22,0.38);background-color:rgba(0,0,0,0.38);z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;";
selDiv.id = "selectDiv";
oDiv.getElementsByClassName("el-table__body")[0].appendChild(selDiv);
selDiv.style.left = startX + "px";
selDiv.style.top = startY + "px";
var _x = null;
var _y = null;
vnode.context.clearEventBubble(evt);
// 打开开关
vnode.context.mouseflag = true;
// 鼠标拖动时画框
document.onmousemove = function (ev) {
evt = window.event || arguments[0];
_x = evt.x || evt.clientX;
_y = evt.y || evt.clientY;
// 为了确定是点击事件还是移动事件
if (Math.abs(_x - startX) < 5 && Math.abs(_y - startY) < 5) {
return;
}
vnode.context.selectItemFlag = false;
// 为了确保只有一次的渲染每次框选都把默认选中为空(针对当前页)
if (flag) {
// 重置选中css
for (var i = 0; i < fileNodes.length; i++) {
if (fileNodes[i].className.indexOf("el-table__row") != -1) {
fileNodes[i].className = "el-table__row";
selList.push(fileNodes[i]);
}
}
// 判断翻页是否保存选中数据
// if (vnode.context.pageDataFlag) {
// 判断当前页是否有选中的
vnode.context.tableData.forEach((item) => {
vnode.context.$refs.table.toggleRowSelection(item, false);
vnode.context.multipleSelection.forEach((ele, i) => {
if (item[vnode.context.myKey] == ele[vnode.context.myKey]) {
vnode.context.multipleSelection.splice(i, 1);
i = i - 1;
}
})
})
// } else {
// vnode.context.multipleSelection = []
// }
flag = false;
}
// 判断鼠标移动是否超出在当前表格区域
if (_x <= left || _x >= left + tableWidth || _y <= top || _y >= top + tableHeight) {
document.onmousemove = null;
if (selDiv) {
oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);
}
(selList = null),
(_x = null),
(_y = null),
(selDiv = null),
(startX = null),
(startY = null),
(evt = null);
vnode.context.mouseflag = false;
vnode.context.$handleSelect();
}
if (vnode.context.mouseflag) {
if (selDiv.style.display == "none") {
selDiv.style.display = "";
}
var scrolling = oDiv.getElementsByClassName("el-table__body-wrapper");
// 两个表格的时候需增加滚屏的高度
// var main_scrolling=document.getElementsByClassName("common_table_height");
// selDiv.style.left = Math.min(_x, startX)-left+scrolling[0].scrollLeft +main_scrolling[0].scrollLeft+ "px";
// console.log(scrolling)
selDiv.style.left =
Math.min(_x, startX) - left + scrolling[0].scrollLeft + "px";
//48是表头的高度
// selDiv.style.top = Math.min(_y, startY)-top - 48 + scrolling[0].scrollTop+main_scrolling[0].scrollTop+ "px";
selDiv.style.top =
Math.min(_y, startY) - top - oDiv.getElementsByClassName("is-leaf")[0].offsetHeight + scrollingTop + "px";
selDiv.style.width = Math.abs(_x - startX) + "px";
if (scrolling[0].scrollTop > scrollingTop) {
selDiv.style.height = Math.abs(_y - startY) + scrolling[0].scrollTop + "px";
} else {
selDiv.style.height = Math.abs(_y - startY) + "px";
}
// ---------------- 关键算法确定列表的选中靠的是index---------------------
var _l = selDiv.offsetLeft,
_t = selDiv.offsetTop;
var _w = selDiv.offsetWidth,
_h = selDiv.offsetHeight;
for (var i = 0; i < selList.length; i++) {
var sl = selList[i].offsetWidth + selList[i].offsetLeft;
var st = selList[i].offsetHeight + selList[i].offsetTop;
if (
sl > _l &&
st > _t &&
selList[i].offsetLeft < _l + _w &&
selList[i].offsetTop < _t + _h
) {
if (selList[i].className.indexOf("seled") == -1 && !vnode.context.tableData[i][vnode.context.rowDisabled]) {
selList[i].className = selList[i].className + " seled";
vnode.context.$refs.table.toggleRowSelection(
vnode.context.tableData[i],
true
)
vnode.context.multipleSelection.push(vnode.context.tableData[i])
}
} else {
if (selList[i].className.indexOf("seled") != -1) {
selList[i].className = "el-table__row";
vnode.context.$refs.table.toggleRowSelection(
vnode.context.tableData[i],
false
)
let index = vnode.context.multipleSelection.indexOf(vnode.context.tableData[i])
vnode.context.multipleSelection.splice(index, 1)
}
}
}
// ---------------- 关键算法结束---------------------
}
if (document.onmousemove) {
vnode.context.clearEventBubble(evt);
}
};
//在鼠标抬起后做的重置
oDiv.onmouseup = function () {
//把鼠标移动事初始化
document.onmousemove = null;
if (selDiv) {
oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);
}
(selList = null),
(_x = null),
(_y = null),
(selDiv = null),
(startX = null),
(startY = null),
(evt = null);
vnode.context.mouseflag = false;
vnode.context.$selectState(false);
// 防止重复$handleSelect()事件
if (!vnode.context.selectItemFlag) {
vnode.context.$handleSelect();
vnode.context.selectItemFlag = false;
}
};
};
}
}
},
components: {
airContexMenu, treeDialog
},
props: {
// 对于列表中唯一的字段myKey默认为id
myKey: {
type: String,
default: "id"
},
//列表的数据
tableData: {
type: Array,
default: () => []
},
//传过来的表头信息
columData: {
type: Array,
default: () => []
},
//有没有checkbox
isType: {
type: String,
default: "selection"
},
//右键菜单
menuList: {
type: Array,
default: () => []
},
//分页的总页数
pageTotal: {
type: Number,
default: 0
},
// 每页显示条数
pageSize: {
type: Number,
default: 20
},
// 当前页
currentPage: {
type: Number,
default: 1
},
// 当表格需要单选的时候
isRadio: {
type: Boolean,
default: false
},
// table 回显数据
backMultipleSelection: {
type: Array,
default: () => []
},
// 是否显示分页
showPage: {
type: Boolean,
default: true
},
// 是否显示添加按钮
showAdd: {
type: Boolean,
default: false
},
// 表格高度
height: {
type: [Number, String],
default: 500
},
// 空数据时显示的文本内容
emptyText: {
type: String,
default: "暂无数据"
},
// 行禁用事件
rowDisabled: {
type: String,
default: "disabled"
},
// 翻页是否保存数据
pageDataFlag: {
type: Boolean,
default: true
},
// 对应列是否可以排序,如果设置为 'custom',则代表用户希望远程排序,需要监听 Table 的 sort-change 事件
sortable: {
type: [Boolean, String],
default: false
}
},
data() {
return {
//指令中确定的时候是鼠标按下事件
mouseflag: false,
//选中的数组
multipleSelection: [],
//控制右键菜单弹出显示
dialogVisible: false,
//右键鼠标的位置
position: {
left: 0,
top: 0
},
//控制右键显示隐藏
toggleShow: false,
//分页当前的页数
page: this.currentPage,
//当前右键点击的列
currentRow: [],
//当前滚动的距离,
targetScroll: 0,
// 是否点击单选按钮
selectItemFlag: false,
// 表头tree 数据
treeData: [],
treeName: '',
treePid: '',
treeId: '',
treeTitle: "",
// 表格top距离
tableTop: null,
tableLeft: null,
timer: null,
currentshowPage: true
};
},
methods: {
// 换算index
indexMethod(index) {
return index + (this.page - 1) * this.pageSize + 1;
},
//清除默认事件
clearEventBubble(evt) {
if (evt.stopPropagation) evt.stopPropagation();
else evt.cancelBubble = true;
if (evt.preventDefault) evt.preventDefault();
else evt.returnValue = false;
},
//列表单击选中事件
rowClick(row, event, column) {
if (row.disabled) {
return
}
// 确定当前的row的index
var index = 0;
this.tableData.forEach((ele, i) => {
if (ele[this.myKey] == row[this.myKey]) {
index = i + 1;
}
});
let flag = false;
this.toggleShow = false;
// 单选
if (this.isRadio) {
// 每次点击重置
var dom = this.$refs.table.$el.getElementsByTagName("tr");
this.tableData.forEach(ele => {
this.$refs.table.toggleRowSelection(ele, false);
});
for (var i = 1; i < dom.length; i++) {
dom[i].className = "el-table__row";
}
this.$refs.table.toggleRowSelection(row, true);
this.$refs.table.$el.getElementsByTagName("tr")[index].className =
"el-table__row seled";
this.multipleSelection = Array.of(row)
this.$handleSelect();
return
}
this.selectItemFlag = true;
// 如果有就删除
this.multipleSelection.forEach((ele, i) => {
if (ele[this.myKey] == row[this.myKey]) {
this.$refs.table.toggleRowSelection(row, false);
this.$refs.table.$el.getElementsByTagName("tr")[index].className =
"el-table__row";
flag = true;
this.multipleSelection.splice(i, 1)
}
});
// 如果没有就push
if (!flag) {
this.$refs.table.toggleRowSelection(row, true);
//后期优化吧 element的方法用不了 只能自己改变类名
this.$refs.table.$el.getElementsByTagName("tr")[index].className =
"el-table__row seled";
this.multipleSelection.push(row)
}
this.$handleSelect();
},
//列表右键点击事件
rowContextmenu(row, event) {
if (row[this.rowDisabled]) {
return
}
//确定当前的row的index
var index = 0;
this.tableData.forEach((ele, i) => {
if (ele[this.myKey] == row[this.myKey]) {
index = i + 1;
}
});
// 每次点击重置
var dom = this.$refs.table.$el.getElementsByTagName("tr");
this.tableData.forEach(ele => {
this.$refs.table.toggleRowSelection(ele, false);
});
for (var i = 1; i < dom.length; i++) {
dom[i].className = "el-table__row";
}
this.$refs.table.toggleRowSelection(row, true);
this.$refs.table.$el.getElementsByTagName("tr")[index].className =
"el-table__row seled";
this.multipleSelection = Array.of(row)
this.$handleSelect();
//为当前的row赋值
this.currentRow = row;
//阻止默认右键点击事件
event.returnValue = false;
//获取右键坐标
this.position.left = event.clientX;
this.position.top = event.clientY;
//菜单出现的flag
this.toggleShow = true;
//显示弹出窗
this.$emit("contextmenu", row, event);
},
//右键菜单弹出事件
menuClick(item) {
//右键点击以后隐藏
this.toggleShow = false;
this.$emit("rowContextmenu", item, this.currentRow);
},
//每页条数变化 ui定死每页20条
handleSizeChange(val) {
// console.log(`每页 ${val} 条`);
},
// 当前页变化
handleCurrentChange(val) {
this.page = val;
this.$emit("currentPageChange", this.page);
},
//当批量选中结束调用
$handleSelect() {
this.removal();
// 过滤掉禁用的数据
this.multipleSelection = this.multipleSelection.filter((item) => {
return !item[this.rowDisabled]
});
this.$emit("handleSelect", this.multipleSelection);
},
// 根据myKey去重
removal() {
let hash = {};
this.multipleSelection = this.multipleSelection.reduce((preVal, curVal) => {
hash[curVal[this.myKey]] ? '' : hash[curVal[this.myKey]] = true && preVal.push(curVal);
return preVal
}, [])
},
// 是否框选 state
$selectState(state) {
this.$emit("selectState", state);
},
// 选项发生改变事件 ZZ
selectionChange(val) {
// this.multipleSelection = val;
},
//监听表格的滚动
handleScroll(e) {
this.targetScroll = e.target.scrollTop;
},
//当单选时触发的事件
selectItem(selection, row) {
this.selectItemFlag = true;
this.rowClick(row);
},
//当表头多选是触发的事件
selectAll(selection) {
this.selectItemFlag = true;
var dom = this.$refs.table.$el.getElementsByTagName("tr");
if (this.isRadio) {
this.tableData.forEach(ele => {
this.$refs.table.toggleRowSelection(ele, false);
});
for (var i = 1; i < dom.length; i++) {
dom[i].className = "el-table__row";
}
this.multipleSelection = [];
this.$handleSelect();
return;
}
if (selection.length) {
for (var i = 1; i < dom.length; i++) {
//为了去掉表头的tr从1开始
dom[i].className = "el-table__row seled";
}
// if(this.pageDataFlag){
this.multipleSelection = [...this.multipleSelection, ...selection];
// }else{
// this.multipleSelection = selection;
// }
this.removal();
} else {
for (var i = 1; i < dom.length; i++) {
dom[i].className = "el-table__row";
}
this.tableData.forEach((item) => {
this.multipleSelection.forEach((ele, i) => {
if (item[this.myKey] == ele[this.myKey]) {
this.multipleSelection.splice(i, 1)
i = i - 1;
}
})
})
}
this.$handleSelect();
},
//双击事件
rowDblclick(row, event) {
if (row.disabled) {
return
}
this.$emit("rowDblclick", row, event);
},
// 表头点击事件
headerClick(column, event) {
if (event.target.nodeName === 'DIV')
this.columData.map((item, index) => {
if (item.name == column.label) {
if (item.tree && item.tree.data.length) {
this.$refs.treeDialog.$el.getElementsByClassName("el-dialog")[0].style.top = this.tableTop + 53 + 'px';
this.$refs.treeDialog.$el.getElementsByClassName("el-dialog")[0].style.left = this.tableLeft + (event.path[1].scrollWidth) * (index) + 55 + 'px';
this.treeData = item.tree.data;
this.treePid = item.tree.pid;
this.treeId = item.tree.id;
this.treeName = item.tree.name;
this.treeTitle = item.name;
this.$refs.treeDialog.dialogOpen();
}
}
})
},
// tree确定事件/
makesure(data) {
this.$emit('makesure', data);
},
// 添加按钮点击事件
addClick() {
this.$emit('addClick');
},
// 初始化回显数据
initMultipleSelection() {
this.$nextTick(() => {
var dom = this.$refs.table.$el.getElementsByTagName("tr");
this.$refs.table.clearSelection();
this.tableData.forEach((ele, i) => {
dom[i + 1].className = "el-table__row";
});
//为了传过来的值进行回显
if (this.backMultipleSelection.length > 0) {
this.backMultipleSelection.forEach(item => {
this.tableData.forEach((ele, i) => {
if (item[this.myKey] == ele[this.myKey] && !ele[this.rowDisabled]) {
this.$refs.table.toggleRowSelection(ele, true);
dom[i + 1].className = "el-table__row seled";
}
});
});
}
});
},
// 自适应分页的位置
initPage() {
if (!this.currentshowPage) return
// 分页显示的位置
let obj = this.$refs.table.$el.getElementsByClassName("el-table__body-wrapper")[0];
// 判断是否有滚动条
if (obj.scrollHeight > obj.clientHeight) {
this.$refs.table.$el.getElementsByClassName("el-table__append-wrapper")[0].style.cssText = "";
} else {
this.$refs.table.$el.getElementsByClassName("el-table__append-wrapper")[0].style.cssText = "position:absolute;right:0;bottom:0;";
}
},
// 行禁用事件
selectable(row, index) {
if (row[this.rowDisabled]) {
return false
} else {
return true
}
},
// 清空回显数据
clearMultipleSelection() {
this.multipleSelection = [];
},
/*
*@method 表头排序点击事件
*@param 1 column行数据
*@param 2 prop == "ascending" 排序
* prop == "descending" 降序
*@param 3 order排序规则
*@return {返回值类型} 返回值说明
*/
sortChange(column, prop, order) {
this.$emit("sortChange", column, prop, order);
}
},
watch: {
backMultipleSelection: {
handler: function (newVal, oldVal) {
//为了回显
this.multipleSelection = newVal;
this.initMultipleSelection();
},
deep: true
},
currentPage: {
handler(newValue, oldValue) {
this.page = newValue;
},
immediate: true
},
showPage: {
handler(newValue, oldValue) {
this.currentshowPage = newValue;
},
immediate: true
},
tableData(val) {
/* 监听table数据变化时(分页操作),已选中数据做回显 */
this.$nextTick(() => {
// 判断翻页是否保存选中数据
// if (this.pageDataFlag) {
var dom = this.$refs.table.$el.getElementsByTagName("tr");
this.$refs.table.clearSelection();
this.tableData.forEach((ele, i) => {
dom[i + 1].className = "el-table__row";
});
//为了已选中数据进行回显
if (this.multipleSelection.length > 0) {
this.multipleSelection.forEach(item => {
this.tableData.forEach((ele, i) => {
if (item[this.myKey] == ele[this.myKey] && !ele[this.rowDisabled]) {
this.$refs.table.toggleRowSelection(ele, true);
dom[i + 1].className = "el-table__row seled";
}
});
});
}
// }else{
// this.multipleSelection = [];
// }
this.initPage();
})
}
},
computed: {
// 通过滚动距计算阴影 class
headerClassName() {
if (this.targetScroll == 0) {
return "air-table-header__class"
} else if (this.targetScroll > 0 && this.targetScroll <= 100) {
return "air-table-header__class air-table-header__scroll1"
} else if (this.targetScroll > 100 && this.targetScroll <= 200) {
return "air-table-header__class air-table-header__scroll2"
} else {
return "air-table-header__class air-table-header__scroll3"
}
}
},
mounted() {
document.onclick = () => {
this.toggleShow = false;
};
this.multipleSelection = this.backMultipleSelection;
this.initMultipleSelection();
this.$refs.table.$refs.bodyWrapper.addEventListener('scroll', this.handleScroll);
this.timer = setTimeout(() => {
this.initPage();
}, 20);
},
beforeDestroy() {
this.$refs.table.$refs.bodyWrapper.removeEventListener('scroll', this.handleScroll);
clearTimeout(this.timer);
}
};
</script>
<style lang="scss">
@import "../../../public/style/mixin.scss";
.air-table-wrapper {
@include wh(100%, 100%);
%scroll-calss {
width: 100%;
height: 1px;
position: absolute;
top: 51px;
left: 0;
content: "";
z-index: 2;
}
.seled {
background: #f5f5f5 !important;
}
.no-seled {
background: #ffffff !important;
}
.el-table__body-wrapper {
overflow: auto;
}
.el-table__body tr {
cursor: pointer;
box-sizing: border-box;
border-top: 1px solid #f5f5f5 !important;
border-bottom: 1px solid #f5f5f5 !important;
}
.air-table-header__class th {
padding: 9px 0 !important;
box-sizing: border-box;
border-bottom: 1px solid #f5f5f5 !important;
}
.air-table-header__scroll1 {
position: relative;
&::after {
@extend %scroll-calss;
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2),
0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
}
}
.air-table-header__scroll2 {
position: relative;
&::after {
@extend %scroll-calss;
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
}
.air-table-header__scroll3 {
position: relative;
&::after {
@extend %scroll-calss;
box-shadow: 0 3px 3px -2px rgba(0, 0, 0, 0.2),
0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 1px 8px 0 rgba(0, 0, 0, 0.12);
}
}
.el-table__body td {
box-sizing: border-box;
border-bottom: 1px solid #f5f5f5;
}
.hover-row {
border-top: 1px solid #f5f5f5;
border-bottom: 1px solid #f5f5f5;
background: #fafafa;
}
.el-table__append-page {
.el-pagination {
text-align: right;
margin: 48px 0;
.btn-prev {
@extend %airLeft;
}
.btn-next {
margin-right: 0px;
@extend %airRight;
}
.el-pager li {
@extend %elPagerLi;
}
.el-pagination__total {
@extend %elPaginationTotal;
}
}
.el-pagination button:disabled {
color: #bdbdbd;
}
}
.el-table__append-pageAdd {
.el-pagination {
margin: 48px 0 76px !important;
.btn-prev {
@extend %airLeft;
}
.btn-next {
margin-right: 0px;
@extend %airRight;
}
.el-pager li {
@extend %elPagerLi;
}
.el-pagination__total {
@extend %elPaginationTotal;
}
}
.el-pagination button:disabled {
color: #bdbdbd;
}
}
.air-table__context--menu {
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2),
0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
.air-table__context--list {
cursor: pointer;
height: 48px;
@include flexCenter(flex-start, center);
.air-table__context--icon {
font-size: 20px;
margin-left: 20px;
color: #757575;
}
.air-table__context--info {
font-size: 14px;
margin-left: 20px;
color: #212121;
}
}
.air-table__context--list:hover {
background: #f5f5f5;
}
}
.el-table th {
padding: 9px 0 !important;
}
.air-treeDialog-wrappers .el-dialog {
margin: 0 !important;
}
.el-table-column--selection .cell {
padding-left: 20px;
padding-right: 10px;
}
}
</style>
复制代码
2、css样式
.air-table-wrapper {
display: flex;
flex-direction: column;
@include wh(100%, 100%);
.el-table__body {
overflow: hidden;
// padding-bottom: 139px;
}
.el-table__body td .concat-table-container {
max-width: 350px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer
}
.el-table__fixed-body-wrapper {
position: relative
}
.el-table__body tr {
height: $tableRowHeight;
}
.el-table__body-wrapper .is-scrolling-none {
height: auto !important;
}
.el-table {
width: 100%;
// min-height: 900px;
// height:-webkit-calc(100% - 56px) !important;
td {
border-bottom: none;
height: $tableRowHeight;
padding: 0px;
max-width: 400px;
}
th.is-leaf {
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
height: 53px;
font-size: 16px;
color: rgba(0, 0, 0, 0.87);
}
th {
&:first-child {
// border-left: 4px solid #fff;
//text-align: center
}
.cell {
height: 34px !important;
font-weight: 100;
line-height: 34px;
overflow: visible !important;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 400px;
}
}
.el-table__body {
tr {
td:first-child {
// border-left: 4px solid #fff;
//text-align: center
}
}
tr.hover-row {
td {
background: rgba(0, 0, 0, 0.02)
}
// td:first-child{border-left: 4px solid $themeColor}
}
tr.current-row {
td {
background: rgba(0, 0, 0, 0.04)
}
// td:first-child{border-left: 4px solid $themeColor}
}
.el-checkbox__inner{
@include wh(16px, 16px);
border: 2px solid #bdbdbd;
}
.el-radio__inner {
@include wh(16px, 16px);
border: 2px solid #bdbdbd;
border-radius: 0px
}
}
.el-table__header {
.el-checkbox__inner {
@include wh(16px, 16px);
border: 2px solid #bdbdbd;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{
top: 7px;
}
}
.el-checkbox__inner::after {
-webkit-box-sizing: content-box;
box-sizing: content-box;
content: "";
border: 2px solid #fff;
border-left: 0;
border-top: 0;
height: 7px;
left: 4px;
position: absolute;
top: 1px;
}
.el-radio__label {
display: none
}
.el-radio__inner::after {
-webkit-box-sizing: content-box;
box-sizing: content-box;
content: "";
border: 2px solid #fff;
transform: rotate(45deg) scaleY(1);
border-left: 0;
border-top: 0;
height: 7px;
left: 4px;
position: absolute;
top: 1px;
border-radius: 0px;
background: none
}
.el-radio__input.is-checked .el-radio__inner::after {
transform: rotate(45deg) scaleY(1);
}
}
}
复制代码
3、contextMenu.js
export default {
name: 'airContexMenu',
props: {
position: {
type: Object,
default: () => {
return {
top: 0,
left: 0
}
}
},
toggleShow:{
type:Boolean,
default: false
},
menuList : {
type: Array,
default: () => []
}
},
render(h) {
var self = this;
var menuInfo = [];
this.menuList.forEach((ele)=>{
menuInfo.push(h('li',{
style: {
width:"100%",
display:"flex"
},
class: ['air-table__context--list','ripple'],
on: {
click:function (){
self.$emit('menuClick', ele)
}
}
},
[
h('i', {
class: [ele.icon,'air-table__context--icon']
}),
h('span',{class:['air-table__context--info']}, ele.name)
]))
})
return h(
'div', {
style: {
width:"300px",
padding: "8px 0px",
position:"fixed",
left: this.position.left + "px",
top: this.position.top + "px",
display: this.toggleShow ? "block" : "none",
zIndex:99999,
backgroundColor:"#fff",
borderRadius:"4px"
},
class: ['air-table__context--menu']
},
menuInfo
);
},
computed: {
},
data() {
return {
};
},
created() {
},
methods: {
menuClick(){
}
}
};
复制代码
3、treeDialog.vue
/*
* @property { data : {Array} 接口传来的数组 }
* @property { showCheckbox : {Boolean} 是否显示多选小方框 }
* @property { placeholder : {String} 提示语,上方搜索框提示语。 }
* @method @check : 父组件使用check来接收已选中的所有数据组成的数组
* @property { width : {String} 弹窗的宽度可以传50%也可以传200px }
* @property { title : {String} 弹窗上方的名字 }
* @property { showScreen : {Boolean} 是否需要筛选框 }
* @property { id : {String} id字段 }
* @property { pid : {String} 父id字段 }
* @property { name : {String} name字段 }
* @method @nodeclick : 节点被点击时的回调
* @property { defaultExpandAll : {Boolean} 是否默认展开 }
* @method @dialogOpen 打开弹出框
* @method @dialogClose 关闭弹出框
* @method closeOnClickModal 是否可以点击遮罩层来关闭
* @method close 关闭事件
* @version 1.0.0
* @edit: 2018/8/2
*/
<template>
<div class="air-treeDialog-wrappers">
<el-dialog :title="treeTitle"
:visible.sync="dialogVisible"
:width="width"
@close="closed"
:before-close = "beforeclose">
<commonfiltertree :placeholder="placeholder"
:data="allData"
:showCheckbox="showCheckbox"
@check='getcheckdata'
:showScreen="showScreen"
@click='getCurrentKey'
@checkkey='getCheckedKeys'
:defaultExpandAll="defaultExpandAll"
:defaultCheckedKeys="defaultCheckedKeys"
:id="treeId"
:pid="treePid"
:name="treeName"
:isfilterText="isfilterText"
:close-on-click-modal="closeOnClickModal"
ref="tree"></commonfiltertree>
<div class="foot">
<airButton class="foot-button"
@click="dialogClose"
buttonType="colorButtonOrange"
buttonName="确定"></airButton>
</div>
</el-dialog>
</div>
</template>
<script>
import commonfiltertree from "@/components/newCommon/tree/tree.vue";
export default {
props: {
//提示语,上方搜索框提示语
placeholder: {
type: String,
default: ""
},
//处理好的数据
data: {
type: Array,
default: () => []
},
// 是否显示多选小方框
showCheckbox: {
type: Boolean,
default: true
},
//弹窗宽度
width: {
type: String,
default: "360px"
},
//题目(水费电费水电费)
title: {
type: String,
default: ""
},
//是否需要筛选框
showScreen: {
type: Boolean,
default: true
},
//是否默认展开
defaultExpandAll: {
type: Boolean,
default: false
},
//id 的字段名
id: {
type: String,
default: "id"
},
//父id 的字段名
pid: {
type: String,
default: "pid"
},
//内容的字段名
name: {
type: String,
default: "name"
},
// //回显数组
// defaultCheckedKeys: {
// type: Array,
// default: () => []
// }
closeOnClickModal: {
type: Boolean,
default: true
}
},
components: {
commonfiltertree
},
data() {
return {
filterText: '',
countent: "",
checkbox: this.showCheckbox,
data1: new Array,
dialogTableVisible: false,
screen: this.showScreen,
dialogVisible: false,
allData: this.data,
treeName: this.name,
treeId: this.id,
treePid: this.pid,
treeTitle: this.title,
checkKeyData: [],
isfilterText: false,
defaultCheckedKeys: []
};
},
watch: {
filterText(val) {
this.$refs.tree2.filter(val);
},
data(val) {
this.allData = val;
},
pid(val) {
this.treePid = val;
},
id(val) {
this.treeId = val;
},
name(val) {
this.treeName = val;
},
title(val) {
this.treeTitle = val;
}
},
methods: {
getcheckdata(data) {
//有多选框的时候返回的data数组
this.$emit('check', data);
},
getCurrentKey(data) {
//点击的时候返回当前点击的key
this.checkKeyData = data;
this.defaultCheckedKeys[0] = data.id;
console.log(this.defaultCheckedKeys)
this.$emit('click', data);
},
getCheckedKeys(data) {
//有多选框时返回的key所组成的数组
this.checkKeyData = data;
this.$emit('checkkey', data);
},
//打开弹出框
dialogOpen() {
this.dialogVisible = true;
this.isfilterText = false;
},
//关闭弹出框
dialogClose() {
this.dialogVisible = false;
this.isfilterText = true;
this.$emit('makesure', this.checkKeyData);
},
//关闭返回
closed() {
this.$emit("closed");
this.dialogVisible = false;
},
beforeclose(done){
this.dialogVisible = false;
this.$refs.tree.clearnodekey()
}
}
};
</script>
<style lang="scss" >
// @import "../../../public/style/common.scss";
.air-treeDialog-wrappers {
.el-dialog {
//min-height: 280px;
max-height: 568px;
border-radius: 4px;
box-shadow: 0px 20px 20px #777;
}
.el-dialog .el-dialog__header {
background-color: transparent;
}
.el-dialog .el-dialog__headerbtn .el-dialog__close {
color: #000;
}
.el-dialog__headerbtn {
top: 16px;
}
.el-dialog .el-dialog__header {
border-bottom: 1px solid #fafafa;
}
.el-dialog__body {
padding: 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.expanded {
color: #616161;
}
.is-leaf {
color: transparent;
}
.air-tree-wrappers .el-tree {
margin-bottom: 0px;
}
.foot {
width: 100%;
height: 56px;
background-color: #fff;
border-top: 1px solid #f5f5f5;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
.foot-button {
float: right;
margin-top: 11px;
margin-right: 24px;
}
}
}
</style>
复制代码
结语: 通过操作 DOM 来改变 class ,感觉有点累赘,希望能有大神指出不足之处!