element-ui 實現table整列的拖動

演示地址
css

1. 先動態渲染表頭,給每個表頭添加一個class=virtual 的畫虛線的類名,同時給每一個表頭加上鼠標點擊、拖動、擡起事件:mousedown->mousemove->mouseup.html

2. 點擊時肯定點擊的哪一個,拖動的時候肯定拖動的方向,擡起的時候肯定放在的位置。vue

3. 改變數據實現拖動完成效果。element-ui

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>自定義表頭樣式和整列的拖動</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui@2.3.7/lib/theme-chalk/index.css">
    <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
    <script src="https://unpkg.com/element-ui@2.3.7/lib/index.js"></script>
    <style>
        *{
            padding:0;
            margin:0;
        }
        body {
            padding:50px;
            overflow-x: hidden;
        }
        .thead-cell{
            position: relative;
        }
        .drag_table th {
            cursor: move;
        }
        .virtual {
            position: fixed;
            display: block;
            margin-top: -35px;
            margin-left: -11px; 
        }
        .drag_active_left .virtual {
            border-left: 1px dotted #666;
            z-index: 99;
        }
        .drag_active_right .virtual {
            border-right: 1px dotted #666;
            z-index: 99;
        }
        /* 
            給選中要拖動的列添加背景色,若是在完整項目內部的組件,因此這個組件的style,不能加scoped,不然添加不上樣式
            若是使用了sass或者less,能夠加scoped 而後在用特殊手法處理樣式
        */
        .dragging_column {
            background-color: #f3f3f3 !important;
        }
        
    </style>
</head>

<body>
    <div id="app">
            <p style="text-align:center;font-size:20px;margin-bottom:50px;">自定義表頭樣式和整列的拖動</p>
            <div @mouseleave="moveTableOutside">
                <el-table class="drag_table" :data="tableData" border stripe :cell-class-name="cellClassName" :header-cell-class-name="headerCellClassName">
                    <el-table-column v-for="(col, index) in tableHeader" :key="index" :prop="col.prop" :label="col.label" :column-key="index.toString()" :render-header="renderHeader">
                    </el-table-column>
                </el-table>
            </div>
        </div>
</body>
<script>
    var Main = {
        data() {
            return {
                tableData: [{
                    name: '王小虎',
                    date: '2016-05-02',
                    address: '上海市普陀區金沙江路 1518 弄'
                }, {
                    name: '王老五',
                    date: '2016-05-04',
                    address: '上海市普陀區金沙江路 1517 弄'
                }, {
                    name: '王大錘',
                    date: '2016-05-01',
                    address: '上海市普陀區金沙江路 1519 弄'
                }, {
                    name: '王小龍',
                    date: '2016-05-03',
                    address: '上海市普陀區金沙江路 1516 弄'
                }],
                tableHeader: [{
                    prop: 'name',
                    label: '姓名'
                }, {
                    prop: 'date',
                    label: '時間'
                }, {
                    prop: 'address',
                    label: '地址'
                }],
                dragState: {
                    startIndex: -1, // 拖動起始元素的index
                    endIndex: -1, // 拖動結束元素的index
                    afterMoveIndex: -1, // 拖動後元素的index
                    dragging: false, // 是否正在拖動
                    direction: null, // 拖動方向
                    moveTableOutsideBack: false // 拖出到table外以後又拖回來
                }
            }
        },
        methods: {
            // drag_table在渲染表頭時調用
            renderHeader(h, {
                column,
                $index
            }) {
                // 這裏能夠根據$index的值來對自身需求進行修改,
                return h('span', {
                    'class': ['thead-cell'],
                    style: {
                        'display': 'block',
                        'width': '100%',
                        'cursor': 'move',
                    },
                    on: {
                        mousedown: ($event) => {
                            this.handleMouseDown($event, column)
                        },
                        mouseup: ($event) => {
                            this.handleMouseUp($event, column)
                        },
                        mousemove: ($event) => {
                            this.handleMouseMove($event, column)
                        }
                    }
                }, [
                    h('span', [
                        // 給每一個表頭添加icon 能夠不須要
                        h('span', {
                            class: $index === 0 ? 'el-icon-star-off' : $index === 1 ? 'el-icon-time' : $index === 2 ? 'el-icon-location' : '',
                        }),
                        h('span', column.label)
                    ]),
                    // 給每一個表頭添加一個class=virtual 是畫虛線的類名。
                    h('span', {
                        'class': ['virtual']
                    })
                ])
            },
            // 按下鼠標開始拖動 設置列的背景色
            handleMouseDown(e, column) {
                // 判斷是鼠標左鍵
                if (e.button === 0) {
                    this.dragState.dragging = true
                    this.dragState.startIndex = parseInt(column.columnKey)
                    console.log(`開始移動的位置 ${this.dragState.startIndex}`)
                    // 給當前要拖動列的th設置class
                    document.querySelectorAll('.drag_table table thead tr th')[this.dragState.startIndex].className += ' ' + 'dragging_column';
                    // 給拖動時的虛擬容器添加寬高                    
                    let table = document.getElementsByClassName('drag_table')[0]
                    let virtual = document.getElementsByClassName('virtual')
                    // 設置新插入的span.virtual的標籤 每一列的寬度、高度
                    for (let item of virtual) {
                        item.style.height = table.clientHeight - 1 + 'px'
                        item.style.width = item.parentElement.parentElement.clientWidth + 'px'
                    }
                    this.dragState.moveTableOutsideBack = false
                }
            },
            // 拖動中
            handleMouseMove(e, column) {
                // 判斷是鼠標左鍵
                if (e.button === 0) {
                    if (this.dragState.dragging) {
                        let currentIndex = parseInt(column.columnKey) // 拖動的當前列index
                        console.log(`移動到了${currentIndex}`)
                        if (currentIndex !== this.dragState.startIndex) {
                            this.dragState.direction = currentIndex - this.dragState.startIndex < 0 ? 'left' : 'right' // 判斷拖動方向
                            this.dragState.afterMoveIndex = currentIndex
                        } else {
                            this.dragState.direction = null
                        }
                    } else {
                        return false
                    }
                }
            },
            // 鼠標放開結束拖動
            handleMouseUp(e, column) {
                // 判斷是鼠標左鍵
                if (e.button === 0) {
                    // 拖出當前table外以後又拖回來,再也不進行易位操做(拖出去時已處理)
                    if (this.dragState.moveTableOutsideBack) {
                        return false
                    } else {
                        this.dragState.endIndex = parseInt(column.columnKey) // 記錄結束列index
                        console.log(`結束移動的位置 ${this.dragState.endIndex}`)
                        if (this.dragState.startIndex !== this.dragState.endIndex) {
                            this.dragColumn(this.dragState)
                        }
                        this.finishDragInit()
                    }
                }
            },
            // 拖動到當前table以外的處理
            moveTableOutside() {
                if (this.dragState.dragging) {
                    this.dragState.endIndex = this.dragState.startIndex
                    console.log(`已移動到table外,結束移動的位置 ${this.dragState.endIndex}`)
                    if (this.dragState.startIndex !== this.dragState.endIndex) {
                        this.dragColumn(this.dragState)
                    }
                    this.finishDragInit()
                    this.dragState.moveTableOutsideBack = true
                }
            },
            // 拖動易位
            dragColumn({
                startIndex,
                endIndex,
                direction
            }) {
                console.log(`從${startIndex}移動到了${endIndex}`)
                // 排除掉鼠標點擊table外面,而後拖入進table報錯
                if (startIndex < 0) {
                    return;
                }
                // 判斷是向左移動仍是向右移動
                // 把移動的列插在某個列前面或者後面,而後在刪除移動的列
                if (direction === 'left') {
                    this.tableHeader.splice(endIndex, 0, this.tableHeader[startIndex])
                    this.tableHeader.splice(startIndex + 1, 1)
                } else {
                    this.tableHeader.splice(endIndex + 1, 0, this.tableHeader[startIndex])
                    this.tableHeader.splice(startIndex, 1)
                }
            },
            // 拖動完成後的初始化
            finishDragInit() {
                // 給當前要拖動列的th取消class
                for (var item of document.querySelectorAll('.drag_table table thead tr th')) {
                    item.className = String(item.className).split("dragging_column").join("");
                }
                // 再次初始化拖動狀態
                this.dragState = {
                    startIndex: -1,
                    endIndex: -1,
                    afterMoveIndex: -1,
                    dragging: false,
                    direction: null,
                    moveTableOutsideBack: false
                }
            },
            // 動態給表頭單元格添加 class,實現拖動中的虛線效果
            /* 這個監聽在table渲染的時候會執行一遍。 而後還會有兩個條件會觸發執行: 1. 綁定的數據發生變化的時候(即爲表格內容變化就觸發)。header變化觸發header-cell-class-name,表格數據變化觸發cell-class-name. 2. return返回值 若是綁定了data,若是此data變化也會觸發執行。至關於對這個data進行了監聽隨之觸發這個方法。 */
            headerCellClassName({
                column,
                columnIndex
            }) {
                console.log(1111111)
                return columnIndex === this.dragState.afterMoveIndex ? `drag_active_${this.dragState.direction}` : ''
            },
            // 動態給表頭單元格th添加class,實現拖動中的背景
            cellClassName({
                column,
                columnIndex
            }) {
                console.log(22222)
                return (columnIndex === this.dragState.startIndex ? `dragging_column` : '')
            },
        },
        mounted() {
            var that = this;
            setTimeout(function() {
                //  that.tableHeader[0].label = 'wwwwww';
                //  that.tableData[0].name = 'wwwwww';
                //  console.log()
                // console.log(document.querySelectorAll('.drag_table .el-table_2_column_4')[0])
                // document.querySelectorAll('.drag_table table thead tr th')[0].className += ' ' + 'dragging_column';
                // that.dragState.startIndex = '1'
            }, 5000)
        }
    }
    var Ctor = Vue.extend(Main)
    new Ctor().$mount('#app')
</script>

</html>
相關文章
相關標籤/搜索