zoukankan      html  css  js  c++  java
  • vue基于iview树状表格,封装完善

    先安装iview后在使用

    完善按钮不显示问题 ,当children过多时,点击不动问题等

    封装

    <template>
        <div :style="{tableWidth}" class='autoTbale'>
            <table class="table table-bordered" id='hl-tree-table'>
                <thead>
                    <tr>
                        <th v-for="(column,index) in cloneColumns" :key="index+100">
                            <label v-if="column.type === 'selection'">
                                <input type="checkbox" v-model="checks" @click="handleCheckAll">
                            </label>
                            <label v-else>
                                {{ renderHeader(column, index) }}
                                <span class="ivu-table-sort" v-if="column.sortable">
                                    <Icon type="md-arrow-dropup-circle" :class="{on: column._sortType === 'asc'}" @click.native="handleSort(index, 'asc')" />
                                    <Icon type="md-arrow-dropdown-circle" :class="{on: column._sortType === 'desc'}" @click.native="handleSort(index, 'desc')" />
                                </span>
                            </label>
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(item,index) in initItems" :key="item.id" v-show="show(item)" :class="{'child-tr':item.parent}">
                        <td v-for="(column,snum) in columns" :key="column.key" :style=tdStyle(column)>
                            <label v-if="column.type === 'selection'">
                                <input type="checkbox" class="itemCheck" :value="item.id" v-model="checkGroup" @click="handleCheckClick(item,$event,index)">
                            </label>
                            <div v-if="column.type === 'action'">
                                <i-button 
                                    :type="action.type" 
                                    size="small" 
                                    v-for='action in (column.actions)' 
                                    @click="RowClick(item,$event,index,action.text,action.id)" 
                                    :key="action.text">
                                    {{action.text}}
                                </i-button>
                            </div>
                            <label @click="toggle(index,item)" v-if="!column.type">
                                <span v-if='snum==iconRow()'>
                                    <i v-html='item.spaceHtml'></i>
                                <!-- <i v-if="item.children&&item.children.length>0" class="ivu-icon" :class="{'ivu-icon-plus-circled':!item.expanded,'ivu-icon-minus-circled':item.expanded }"></i> -->
                                <Icon 
                                        v-if="item.children&&item.children.length>0"
                                        class="ivu-icon"
                                        :type="!item.expanded? 'md-arrow-dropright':'md-arrow-dropdown'"
                                    />                 
                                    <i v-else class="ms-tree-space"></i>
                                </span> {{renderBody(item,column) }}
                            </label>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </template>
    <script>
    export default {
        name: 'treeGrid',
        props: {
            columns: Array,
            items: {
                type: Array,
                default: function() {
                    return [];
                }
            }
        },
        data() {
            return {
                initItems: [], //处理后数据数组
                cloneColumns: [], //处理后的表头数据
                checkGroup: [], //复选框数组
                checks: false, //全选
                screenWidth: document.body.clientWidth, //自适应宽
                tdsWidth: 0, //td总宽
                timer: false, //控制监听时长
                dataLength: 0, //树形数据长度
            }
        },
        computed: {
            tableWidth() {
                return this.tdsWidth > this.screenWidth && this.screenWidth > 0 ? this.screenWidth + 'px' : '100%'
            }
        },
        watch: {
            screenWidth(val) {
                if (!this.timer) {
                    this.screenWidth = val
                    this.timer = true
                    setTimeout(() => {
                        this.timer = false
                    }, 400)
                }
            },
            items() {
                if (this.items) {
                    this.dataLength = this.Length(this.items)
                    this.initData(this.deepCopy(this.items), 1, null);
                    this.checkGroup = this.renderCheck(this.items)
                    if (this.checkGroup.length == this.dataLength) {
                        this.checks = true
                    } else {
                        this.checks = false
                    }
                }
            },
            columns: {
                handler() {
                    this.cloneColumns = this.makeColumns();
                },
                deep: true
            },
            checkGroup(data) {
                this.checkAllGroupChange(data)
            },
        },
        mounted() {
            if (this.items) {
                this.dataLength = this.Length(this.items)
                this.initData(this.deepCopy(this.items), 1, null);
                this.cloneColumns = this.makeColumns();
                this.checkGroup = this.renderCheck(this.items)
                if (this.checkGroup.length == this.dataLength) {
                    this.checks = true
                } else {
                    this.checks = false
                }
            }
            // 绑定onresize事件 监听屏幕变化设置宽
            this.$nextTick(() => {
                this.screenWidth = document.body.clientWidth
            })
            window.onresize = () => {
                return (() => {
                    window.screenWidth = document.body.clientWidth
                    this.screenWidth = window.screenWidth
                })()
            }
        },
        methods: {
          // 有无多选框折叠位置优化
          iconRow() {
            for (var i = 0, len = this.columns.length; i < len; i++) {
              if (this.columns[i].type == 'selection') {
                return 1
              }
            }
            return 0
          },
            // 设置td宽度,td的align
            tdStyle(column) {
                var style = {}
                if (column.align) {
                    style["text-align"] = column.align;
                }
                if (column.width) {
                    style["min-width"] = column.width + 'px';
                }
                return style;
            },
            // 排序事件
            handleSort(index, type) {
                this.cloneColumns.forEach((col) => col._sortType = 'normal');
                if (this.cloneColumns[index]._sortType === type) {
                    this.cloneColumns[index]._sortType = 'normal'
                } else {
                    this.cloneColumns[index]._sortType = type
                }
                this.$emit('on-sort-change', this.cloneColumns[index]['key'], this.cloneColumns[index]['_sortType'])
            },
            // 点击某一行事件
            RowClick(data, event, index, text,action) {
                let result = this.makeData(data)
                this.$emit('on-row-click', result, event, index, text, action)
            },
            // 点击事件 返回数据处理
            makeData(data) {
                const t = this.type(data);
                let o;
                if (t === 'array') {
                    o = [];
                } else if (t === 'object') {
                    o = {};
                } else {
                    return data;
                }
                if (t === 'array') {
                    for (let i = 0; i < data.length; i++) {
                        o.push(this.makeData(data[i]));
                    }
                } else if (t === 'object') {
                    for (let i in data) {
                        if (i != 'spaceHtml' && i != 'parent' && i != 'level' && i != 'expanded' && i != 'isShow' && i !=
                            'load') {
                            o[i] = this.makeData(data[i]);
                        }
                    }
                }
                return o;
            },
            // 处理表头数据
            makeColumns() {
                let columns = this.deepCopy(this.columns);
                this.tdsWidth = 0
                columns.forEach((column, index) => {
                    column._index = index;
                    column._width = column.width ? column.width : '';
                    column._sortType = 'normal';
                    this.tdsWidth += column.width ? parseFloat(column.width) : 0;
                });
                return columns;
            },
            // 数据处理 增加自定义属性监听
            initData(items, level, parent) {
                this.initItems = []
                let spaceHtml = "";
                for (var i = 1; i < level; i++) {
                    spaceHtml += "<i class='ms-tree-space'></i>"
                }
                items.forEach((item, index) => {
                    item = Object.assign({}, item, {
                        "parent": parent,
                        "level": level,
                        "spaceHtml": spaceHtml
                    });
                    if ((typeof item.expanded) == "undefined") {
                        item = Object.assign({}, item, {
                            "expanded": false
                        });
                    }
                    if ((typeof item.show) == "undefined") {
                        item = Object.assign({}, item, {
                            "isShow": false
                        });
                    }
                    if ((typeof item.isChecked) == "undefined") {
                        item = Object.assign({}, item, {
                            "isChecked": false
                        });
                    }
                    item = Object.assign({}, item, {
                        "load": (item.expanded ? true : false)
                    });
                    this.initItems.push(item);
                    if (item.children && item.expanded) {
                        this.initData(item.children, level + 1, item);
                    }
                })
            },
            //  隐藏显示
            show(item) {
                return ((item.level == 1) || (item.parent && item.parent.expanded && item.isShow));
            },
            toggle(index, item) {
                let level = item.level + 1;
                let spaceHtml = "";
                for (var i = 1; i < level; i++) {
                    spaceHtml += "<i class='ms-tree-space'></i>"
                }
                if (item.children) {
                    if (item.expanded) {
                        item.expanded = !item.expanded;
                        this.close(index, item);
                    } else {
                        item.expanded = !item.expanded;
                        if (item.load) {
                            this.open(index, item);
                        } else {
                            item.load = true;
                            item.children.forEach((child, childIndex) => {
                                this.initItems.splice((index + childIndex + 1), 0, child);
                                //设置监听属性
                                this.$set(this.initItems[index + childIndex + 1], 'parent', item);
                                this.$set(this.initItems[index + childIndex + 1], 'level', level);
                                this.$set(this.initItems[index + childIndex + 1], 'spaceHtml', spaceHtml);
                                this.$set(this.initItems[index + childIndex + 1], 'isShow', true);
                                this.$set(this.initItems[index + childIndex + 1], 'expanded', false);
                            })
                        }
                    }
                }
            },
            open(index, item) {
                if (item.children) {
                    item.children.forEach((child, childIndex) => {
                        child.isShow = true;
                        if (child.children && child.expanded) {
                            this.open(index + childIndex + 1, child);
                        }
                    })
                }
            },
            close(index, item) {
                if (item.children) {
                    item.children.forEach((child, childIndex) => {
                        child.isShow = false;
                        child.expanded = false;
                        if (child.children) {
                            this.close(index + childIndex + 1, child);
                        }
                    })
                }
            },
            //点击check勾选框,判断是否有children节点 如果有就一并勾选
            handleCheckClick(data, event, index){
                data.isChecked = !data.isChecked;
                var arr = data.children;
                if(arr){
                    if(data.isChecked){
                        this.checkGroup.push(data.id);
                        for (let i=0; i<arr.length; i++){
                            this.checkGroup.push(arr[i].id)
                        }
                    }else {
                        for (var i=0; i<this.checkGroup.length; i++){
                            if(this.checkGroup[i] == data.id){
                                this.checkGroup.splice(i,1)
                            }
                            for (var j=0; j<arr.length; j++){
                                if(this.checkGroup[i] == arr[j].id){
                                    this.checkGroup.splice(i,1);
                                }
                            }
                        }
                    }
                }
            },
            //checkbox 全选 选择事件
            handleCheckAll() {
                this.checks = !this.checks;
                if (this.checks) {
                    this.checkGroup = this.getArray(this.checkGroup.concat(this.All(this.items)))
                } else {
                    this.checkGroup = []
                }
                // this.$emit('on-selection-change', this.checkGroup)
            },
            // 数组去重
            getArray(a) {
                var hash = {},
                    len = a.length,
                    result = [];
                for (var i = 0; i < len; i++) {
                    if (!hash[a[i]]) {
                        hash[a[i]] = true;
                        result.push(a[i]);
                    }
                }
                return result;
            },
            checkAllGroupChange(data) {
                if (this.dataLength > 0 && data.length === this.dataLength) {
                    this.checks = true;
                } else {
                    this.checks = false;
                }
                this.$emit('on-selection-change', this.checkGroup)
            },
            All(data) {
                let arr = []
                data.forEach((item) => {
                    arr.push(item.id)
                    if (item.children && item.children.length > 0) {
                        arr = arr.concat(this.All(item.children));
                    }
                })
                return arr
            },
            // 返回树形数据长度
            Length(data) {
                let length = data.length
                data.forEach((child) => {
                    if (child.children) {
                        length += this.Length(child.children)
                    }
                })
                return length;
            },
            // 返回表头
            renderHeader(column, $index) {
                if ('renderHeader' in this.columns[$index]) {
                    return this.columns[$index].renderHeader(column, $index);
                } else {
                    return column.title || '#';
                }
            },
            // 返回内容
            renderBody(row, column, index) {
                return row[column.key]
            },
            // 默认选中
            renderCheck(data) {
                let arr = []
                data.forEach((item) => {
                    if (item._checked) {
                        arr.push(item.id)
                    }
                    if (item.children && item.children.length > 0) {
                        arr = arr.concat(this.renderCheck(item.children));
                    }
                })
                return arr
            },
            // 深度拷贝函数
            deepCopy(data) {
                var t = this.type(data),
                    o, i, ni;
                if (t === 'array') {
                    o = [];
                } else if (t === 'object') {
                    o = {};
                } else {
                    return data;
                }
                if (t === 'array') {
                    for (i = 0, ni = data.length; i < ni; i++) {
                        o.push(this.deepCopy(data[i]));
                    }
                    return o;
                } else if (t === 'object') {
                    for (i in data) {
                        o[i] = this.deepCopy(data[i]);
                    }
                    return o;
                }
            },
            type(obj) {
                var toString = Object.prototype.toString;
                var map = {
                    '[object Boolean]': 'boolean',
                    '[object Number]': 'number',
                    '[object String]': 'string',
                    '[object Function]': 'function',
                    '[object Array]': 'array',
                    '[object Date]': 'date',
                    '[object RegExp]': 'regExp',
                    '[object Undefined]': 'undefined',
                    '[object Null]': 'null', 
                    '[object Object]': 'object'
                };
                return map[toString.call(obj)];
            }
        },
        beforeDestroy() {
            window.onresize = null
        }
    }
    </script>
    <style>
    .autoTbale {
        overflow: auto;
    }
    table {
        width: 100%;
        border-spacing: 0;
        border-collapse: collapse;
    }
    .table-bordered {
        border: 1px solid #EBEBEB;
    }
    .table>tbody>tr>td,
    .table>tbody>tr>th,
    .table>thead>tr>td,
    .table>thead>tr>th {
        border-top: 1px solid #e7eaec;
        line-height: 1.42857;
        padding: 8px;
        vertical-align: middle;
    }
    .table-bordered>tbody>tr>td,
    .table-bordered>tbody>tr>th,
    .table-bordered>tfoot>tr>td,
    .table-bordered>tfoot>tr>th,
    .table-bordered>thead>tr>td,
    .table-bordered>thead>tr>th {
        border: 1px solid #e7e7e7;
    }
    .table>thead>tr>th {
        border-bottom: 1px solid #DDD;
    }
    .table-bordered>thead>tr>td,
    .table-bordered>thead>tr>th {
        background-color: #F5F5F6;
    }
    #hl-tree-table>tbody>tr {
        background-color: #fbfbfb;
    }
    #hl-tree-table>tbody>.child-tr {
        background-color: #fff;
    }
    label {
        margin: 0 8px;
    }
    .ms-tree-space {
        position: relative;
        top: 1px;
        display: inline-block;
        font-style: normal;
        font-weight: 400;
        line-height: 1;
        width: 14px;
        height: 14px;
    }
    .ms-tree-space::before {
        content: ""
    }
    #hl-tree-table th>label {
        margin: 0;
    }
    </style>
    View Code

    使用

    <template>
        <div>
            <tree-grid 
                :items='data' 
                :columns='columns'
                @on-row-click='rowClick'
                @on-selection-change='selectionClick'
                @on-sort-change='sortClick'
            ></tree-grid>
        </div>
    </template>
    <script>
    import TreeGrid from '../components/TableGrid'
    export default {
        name: "TableGrid",
        components: {
            TreeGrid
        },
        data() {
            return {
                columns: [
                    {
                    type: 'selection',
                     '50',
                    }, {
                        title: '编码',
                        key: 'code',
                        sortable: true,
                         '150',
                    }, {
                        title: '名称',
                        key: 'name',
                         '150',
                    }, {
                        title: '状态',
                        key: 'status',
                         '150',
                    }, {
                        title: '备注',
                        key: 'remark',
                         '150',
                    }, {
                        title: '操作',
                        type: 'action',
                        actions: [{
                            type: 'primary',
                            id:'edit', // 用于区分编辑和删除,在打印时使用
                            text: '编辑'
                        }, {
                            type: 'error',
                            id: 'del',
                            text: '删除'
                        }],
                         '150',
                    }
                ],
                data: [
                    {
                        id: '1',
                        code: '1',
                        name: '测试数据1',
                        status: '启用',
                        remark: '测试数据测试数据',
                        _checked: true
                    }, {
                        id: '2',
                        code: '2',
                        name: '测试数据2',
                        status: '启用',
                        remark: '测试数据测试数据',
                        children: [
                            {
                                id: '01',
                                code: '21',
                                name: '21',
                                status: '启用',
                                remark: '测试数据测试数据',
                                children: [{
                                    id: '211',
                                    code: '211',
                                    name: '测试数据022',
                                    status: '启用',
                                    remark: '测试数据测试数据',
                                    children: [{
                                        id: '2111',
                                        code: '2111',
                                        name: '测试数据022',
                                        status: '启用',
                                        remark: '测试数据测试数据',
                                    }]
                                }, {
                                    id: '212',
                                    code: '212',
                                    name: '测试数据023',
                                    status: '启用',
                                    remark: '测试数据测试数据',
                                }]
                            }, 
                            {
                                id: '02',
                                code: '22',
                                name: '测试数据02',
                                status: '启用',
                                remark: '测试数据测试数据',
                                
                            }
                        ]
                    }, {
                        id: '3',
                        code: '3',
                        name: '测试数据3',
                        status: '启用',
                        remark: '测试数据测试数据'
                    }, {
                        id: '4',
                        code: '4',
                        name: '测试数据4',
                        status: '启用',
                        remark: '测试数据测试数据'
                    }
                ]
            }
        },
        methods: {
            rowClick(data, event,index,text,action) {
                console.log('当前点击: ' , action )
                console.log('当前行数据: ' ,  data )
                console.log('点击行号: ' , index )
                console.log('点击事件: ' , event )
            },
            selectionClick(arr) {
                console.log('选中数据id数组:' , arr)
            },
            sortClick(key, type) {
                console.log( 'asc:正序,desc:降序' )
                console.log('排序字段:' , key)
                console.log('排序规则:' , type)
            }
        }
    }
    </script>
    View Code

  • 相关阅读:
    2、selinux服务的操作
    1、添加nginx到全局变量中
    linux每日命令(1):which
    QT重载基类绘制函数并在基类绘制结果基础上进行子类的绘制
    QT信号槽无法正常通信的原因
    mapgis6.7+加密狗+二次开发SDK库
    KMP算法参考及C语言实现
    elastic search
    RabbitMq docker集群
    RabbitMq安装
  • 原文地址:https://www.cnblogs.com/-roc/p/11834582.html
Copyright © 2011-2022 走看看