最近学习了canvas,就拿它做了这么个小东西,感觉已经爱上canvas了。上代码
/* * @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} 当前页,默认false。 add v-1.0.0 } * @property { pageSize : {Number} 每页显示条目个数。 add v-1.0.0 } * @property { pageTotal : {Number} 总条目数。 add v-1.0.0 } * @property { backMultipleSelection : {Array} 回显数据。 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 } * @version 1.0.0 * @edit: 2018/8/15 */ <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"v-drag><el-table-column v-if="!isRadio":type="isType"width="55"align="center"></el-table-column><el-table-column v-if="isType == 'index'":index="indexMethod"type="index":label="'序号'"width="55"align="center"></el-table-column><!--列表的表头循环--><el-table-column v-for="(column, index) in columData":key="index":label="column.name":width="column.width"><template slot-scope="scope"><!--把所有的数据都变成插槽导出--><slot :name="column.key":row="scope.row"></slot></template></el-table-column><template slot=appendv-if="showPage"><div :class="['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></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=makesureplaceholder="输入信息,按回车搜索":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.onmousedown = function (ev) {// 防止奇葩操作if ([2, 3, 4, 5].indexOf(ev.buttons) > -1) {if (selDiv) {oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);}return}// 获取当前scrollTopvar scrollingTop = vnode.context.targetScroll;if (vnode.context.isRadio) return;//初始化不显示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 countI = 0;//获得鼠标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) {// 重置选中cssfor (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]);}}// 判断当前页是否有选中的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.$refs.table.toggleRowSelection(ele, false);vnode.context.multipleSelection.splice(ele, 1);i = i - 1;}})})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("is-scrolling-none");// 两个表格的时候需增加滚屏的高度// var main_scrolling=document.getElementsByClassName("common_table_height");// selDiv.style.left = Math.min(_x, startX)-left+scrolling[0].scrollLeft +main_scrolling[0].scrollLeft+ "px";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) {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;// 防止重复$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},// 表格高度 height: {type: [Number, String],default: 500}},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};},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) {// 确定当前的row的indexvar 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)}});// 如果没有就pushif (!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) {//为当前的row赋值this.currentRow = row;//阻止默认右键点击事件event.returnValue = false;//获取右键坐标this.position.left = event.clientX;this.position.top = event.clientY;//菜单出现的flagthis.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() {console.log(this.multipleSelection)this.$emit("handleSelect", this.multipleSelection);},// 选项发生改变事件 ZZ selectionChange(val) {// console.log(val,"mdzz")// 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";}return;}if (selection.length) {for (var i = 1; i < dom.length; i++) {//为了去掉表头的tr从1开始dom[i].className = "el-table__row seled";}this.multipleSelection = [...this.multipleSelection, ...selection];this.multipleSelection = [...new Set(this.multipleSelection)];} 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) {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();}}})},clearData() {this.multipleSelection = []},// tree确定事件/ makesure(data) {this.$emit('makesure', data);},initMultipleSelection() {this.$nextTick(() => {//获得tr对应index找到对应的dom 加入选中classvar 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]) {this.$refs.table.toggleRowSelection(ele, true);dom[i + 1].className = "el-table__row seled";}});});}});}},watch: {backMultipleSelection: {handler: function (newVal, oldVal) {//为了回显this.initMultipleSelection();},deep: true},currentPage: {handler(newValue, oldValue) {this.page = newValue;},immediate: true},tableData(val) {/* 监听table数据变化时(分页操作),已选中数据做回显 */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.multipleSelection.length > 0) {this.multipleSelection.forEach(item => {this.tableData.forEach((ele, i) => {if (item[this.myKey] == ele[this.myKey]) {this.$refs.table.toggleRowSelection(ele, true);dom[i + 1].className = "el-table__row seled";}});});}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;";}})}},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.initMultipleSelection();this.$refs.table.$refs.bodyWrapper.addEventListener('scroll', this.handleScroll);},beforeDestroy() {this.$refs.table.$refs.bodyWrapper.removeEventListener('scroll', this.handleScroll);} }; </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 tr {cursor: pointer;box-sizing: border-box;border-top: 1px solid #f5f5f5;border-bottom: 1px solid #f5f5f5;}.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;}}.el-table__append-info {position: absolute;bottom: 0px;width: 100%;.el-pagination {text-align: right;}}.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: 14px;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;} } </style>