Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ElementUI-table拖动表头并更新数据示例 #31

Open
Kelichao opened this issue Oct 11, 2018 · 0 comments
Open

ElementUI-table拖动表头并更新数据示例 #31

Kelichao opened this issue Oct 11, 2018 · 0 comments

Comments

@Kelichao
Copy link
Owner

Kelichao commented Oct 11, 2018

注意

  • 1.会有表格头拖动后不更新视图的问题,用key解决。
  • 2.改变数据源,组件不触发更新是因为javascript限制,所以数组用splice处理,或者用Vue.set()方法来触发 vue数组更新检测
<template>
	<div class="g-table">

		<!-- 保存布局开始 -->
		<div class="g-table_head f-df f-aic ">
			<div class="f-f1">
				<slot name="head"></slot>
			</div>
			<div v-if="layoutOpen" class="g-table_head_right f-df" style="position:relative;">
				<span class="select_tip">列</span>
				<el-select v-model="value11" multiple size="mini" collapse-tags style="margin-right: 20px" placeholder="" @change="selectChange">
					<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
					</el-option>
				</el-select>
				<el-button type="" icon="el-icon-check" @click="saveLayout" size="mini">保存布局</el-button>
			</div>
		</div>
		<!-- 保存布局结束 -->

		<div class="g-table_sort" v-if="sortTypeList.length">
			<label>排序:</label>
			<el-tag class="g-table_sort_tag" @close="tagClose(tag)" size='small' v-for="(tag) in sortTypeList" :key="tag.label"
			 closable v-if="tag.sortType" :type="tag.sortType">
				{{tag.label}}
			</el-tag>
		</div>

		<!-- 表格体开始 -->
		<div class="g-table_body">
			<el-table :data="tableData" header-cell-class-name="" highlight-current-row @current-change="currentChange"
			 @selection-change="handleSelectionChange" ref="table">
				<el-table-column v-if=tableBox type="selection" width="55"></el-table-column>

				<template v-for="item in tableHeader">


					<!-- 格式化字段开始 -->
					<el-table-column :prop="item.prop" :label="item.label" :width="item.width" :formatter="item.formatter"
					 :render-header="renderHeader" :key="item.key">
						<template slot-scope="scope">

							<template v-if="item.hide"></template>
							<template>
								<template>
									<slot name="temp" :item=item :data="tableData[scope.$index][item.prop]" :row="tableData[scope.$index]">{{tableData[scope.$index][item.prop]}}</slot>
								</template>
							</template>
						</template>
					</el-table-column>
					<!-- 格式化字段结束 -->

				</template>
			</el-table>

			<el-pagination v-if=pageFlag :small="true" @size-change="handleSizeChange" @current-change="handleCurrentChange"
			 :current-page="currentPage" :page-sizes="[10, 20, 30, 40]" :page-size="10" layout="total, sizes, prev, pager, next, jumper"
			 :total="pageTotal">
			</el-pagination>
		</div>
		<!-- 表格体结束 -->
	</div>
</template>

<script type="text/javascript">
	import { http, fetch } from '@/js/http'
	import { mapGetters } from 'vuex';
	import { Message, Notification } from 'element-ui'
	import util from '@/js/util'
	export default {
		name: "gMesTableTemplate",
		data() {
			return {
				value11: '',
				options: [],
				sortTypeList: [],
				layout: [],
				sortString: '',
				enterArr:[],

				// 页码参数
				currentPage: 1,
				numPerPage: 10,// 每页数量
				
			}
		},
		props: {
			pageTotal: {
				type: Number,
				default: 0
			},
			getData: {
				type: Function,
				default: new Function
			},
			pageFlag: {
				type: Boolean,
				default: true,
			},
			tableBox: {
				type: Boolean,
				default: true,
			},
			tableData: {
				type: Array,
				default: function () {
					return [];
				}
			},
			tableHeader: {
				type: Array,
				default: function () {
					return [];
				}
			},
			tableId: {
				type: String,
				default: ''
			},
			sortOpen: {
				type: Boolean,
				default: false
			},
			tableId: {
				type: String,
				default: ''
			},
			sortOpen: {
				type: Boolean,
				default: false
			},
			layoutOpen: {
				type: Boolean,
				default: false
			}
		},
		computed: {
			...mapGetters({
				MenuCode: 'getMenuCode',
			}),
		},
		created() {
			if (this.tableId == '') {
				return Message('tableId不能为空,将无法保存表格布局');
			}

			http.get(`/manage/tableLayout?navTabId=${this.MenuCode}&tableId=${this.tableId}`).then((res) => {

				if (res.data) {
					const layout = JSON.parse(res.data.layoutJson);
					const arr = [];

					if (layout.length) this.calc(JSON.parse(res.data.layoutJson));

					this.tableHeader.forEach((item) => {
						arr.push({ label: item.label, value: item.prop })
						if (!item.hide) this.value11.push(item.prop);
						if (item.sortType && this.sortOpen) {
							this.sortTypeList.push(item);
						}
					})
					this.enterArr = new Array(this.tableHeader.length).fill(false);
					this.options = arr;
				}
			})
		},
		methods: {
			getDataByPage() {
				this.getData({
					numPerPage: this.numPerPage,
					currentPage: this.currentPage,
				})
			},
			// 改变每页页码
			handleSizeChange(idx) {
				this.numPerPage = idx || 10;
				this.currentPage = 1;
				this.getDataByPage();
			},
			handleCurrentChange(idx) {
				this.currentPage = idx;
				this.getDataByPage();
			},
			renderHeader(h, { column, $index }) {
				const item = this.tableHeader[$index - 1];
				const iconArr = { 'desc': 'el-icon-mes-sort-down', 'asc': 'el-icon-mes-sort-up' };
				return h(
					'div', {
						'class': ['gthead-cell', ,this.enterArr[$index-1] ? 'gthead-cell-enterBg':''],
						'attrs': {
							'draggable': true,
						},
						on: {
							dragstart: ($event) => {
								this.handleStart($event, column, $index)
							},
							drop: ($event) => {
								this.handleMouseDown($event, column, $index);
								this.enterArr.splice($index-1,1,false);
							},
							dragleave:($event) => { this.enterArr.splice($index-1,1,false);},
							dragover: ($event) => {
								this.handleMousemove($event, column, $index);
								this.enterArr.splice($index-1,1,true);
							},
						}
					}, [
						h('a', column.label),
						h('span', {
							'class': ['sort']
						}, [this.sortOpen ? h('i', {
							'class': item.sortType == '' ? 'el-icon-mes-sort' : iconArr[item.sortType],
							'on': {
								click: () => { this.sortChange(item) }
							}
						}) : ''
							])
					])
			},
			sortChange(item) {
				let index = undefined;
				item.sortType = this.sortTypeChange(item.sortType)
				this.sortTypeList.forEach((v, i) => {
					if (v.prop == item.prop) {
						index = i;
						v.sortType = item.sortType
					}
				})
				if (index === undefined) {
					this.sortTypeList.push(item)
				};
				this.getSortString()
			},
			handleEdit(i, row) {
				console.log(i, row.stationCode)
			},
			sortTypeChange(type) {
				if (!type) return 'asc'
				return type == 'asc' ? 'desc' : 'asc'
			},
			getSortString() {
				let arr = this.sortTypeList.map((item) => {
					return `${item.prop} ${item.sortType}`
				});
				this.$emit('sorts', arr.join(','))
			},
			tagClose(tag) {
				for (const [i, v] of this.sortTypeList.entries()) {
					if (v.prop === tag.prop) {
						this.sortTypeList.splice(i, 1);
						break
					}
				}
				for (const [i, v] of this.tableHeader.entries()) {
					if (v.prop === tag.prop) {
						v.sortType = '';
						break
					}
				}
				this.getSortString()
			},
			handleMouseDown(e, col, index) {
				// 开始点下标
				const startIndex = parseInt(e.dataTransfer.getData("startIndex")) - 1;
				// 结束点下标
				const endIndex = index - 1;
				// 将换位置的那个剔除并存储  注:不可用JSON.stringify进行复制,内置的方法全部都消失,无法监听。
				var templateStart = this.tableHeader[startIndex];
				var templateEnd = this.tableHeader[endIndex];// Object.assign({},this.tableHeader[endIndex]);
				var value11Start = this.value11[startIndex];
				var value11End = this.value11[endIndex];
				
				// 在模板上的key用于更新渲染,否则,视图无变化。
				this.tableHeader.forEach((value, key) => {
					value.key = util.random(100000);
				});
				
				// 迭代方法可以触发数组set/get
				this.tableHeader.splice(startIndex, 1,  templateEnd);
				this.tableHeader.splice(endIndex, 1, templateStart);

				// 更改表头存储值
				this.value11.splice(startIndex, 1,  value11End);
				this.value11.splice(endIndex, 1, value11Start);
				// console.log(this.tableHeader)

			},
			handleMousemove(e, col, index) {
				e.preventDefault()
			},
			handleStart(e, col, index) {
				e.dataTransfer.setData("startIndex", index);
			},
			currentChange(item) {
				this.$emit('current-change', item)
				// console.log(item, 2)
			},
			handleSelectionChange(item) {
				this.$emit('handle-selectionChange', item)
			},
			selectChange(item) {
				this.calc(item)
			},
			saveLayout() {
				const data = {
					layoutJson: JSON.stringify(this.value11),
					navTabId: this.MenuCode,
					tableId: this.tableId
				}
				fetch.post('/manage/tableLayout', data)
					.then((res) => {
						if (res.code === 'success') {
							Notification({ title: '成功', message: '布局保持成功', type: 'success' })
							this.getDataByPage();
						}
					})
			},
			calc(val) {
				for (let [i, item] of this.tableHeader.entries()) {
					var index = val.findIndex((n) => item.prop == n);
					if (index > -1) {
						item.hide = false;
						this.tableHeader.splice(index, 0, ...this.tableHeader.splice(i, 1))
					}
					else {
						item.hide = true;
					}
				}
			},
		}
	}
</script>
<style lang="scss" scoped>
		.g-table{
		  padding:0 10px;
		  &_head{
			height:40px;
			margin-top:10px;
			&_left{
			  button{
				margin-right:10px;
			  }
			}
			&_right{
			  width:160px;
			  .select_tip{
				position: absolute;
				z-index: 9;
				left: 12px;
				top: 0px;
				font-size: 12px;
				color: #b18d8d;
				cursor: pointer;
				pointer-events: none;
				line-height: 27px;
			  }
			}
		  }
		  &_body{
			margin:10px 0;
		  }
		  &_sort{
			padding:10px 1px 0px;
			label{
			  font-weight:600;
			}
			&_tag{
			  margin:0 5px;
			}
		  }
		}
	  </style>
	  <style lang="scss">
		.g-table_head_right{
		  position:relative;
		  .el-select__tags{
			opacity:0;
		  }
		  .el-tag__close{
			display:none
		  }
		}
		.gthead-cell{
		  padding:0 !important;
		  margin:0 !important;
		  opacity : 0.99;
		  width:100%;
		  cursor:move;
		  display:flex !important;
		  align-items:center;
		  a{
			cursor:move;
		  }
		  .display-none{
			display:none
		  }
		  .sort{
			cursor:pointer;
			display:flex;
			i{
			  font-size:18px
			}
		  }
		}
		.gthead-cell-enterBg{
		  background:#2F6298;
		  color:#fff;
		}
		.g-table_body{
		  .el-table{
			th{
			  padding:0;
			}
		  }
		}
		.el-select-dropdown.is-multiple {
		  .el-select-dropdown__item{
			padding: 0 24px 0 10px;
		  }
		  .el-select-dropdown__item.selected:after{
			right:5px;
		  }
		}
	  </style>
	  
	  
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant