基于Vue实现可以拖拽排序的树形表格
栏目: JavaScript · 发布时间: 6年前
内容简介:项目需要一个可以拖拽排序的树形表格,github上搜了一下,并为找到,大部分都不支持拖拽,所以自己实现了一个简单的组件,已开源数据源(lists)配置lists 配置示例
项目需要一个可以拖拽 排序 的树形表格,github上搜了一下,并为找到,大部分都不支持拖拽,所以自己实现了一个简单的组件,已开源 源代码在这里 ,并发布到npm上,如果有类似需求可以试一下,chrome上没有任何问题
效果图如下:
使用方式
npm i drag-tree-table --save-dev 复制代码
import dragTreeTable from 'drag-tree-table' 复制代码
<dragTreeTable :data="treeData" :onDrag="onTreeDataChange"></dragTreeTable> 复制代码
// state treeData: { lists: [], columns: [] } // methods onTreeDataChange(list) { this.treeData.lists = list }, 复制代码
数据源(lists)配置
参数 | 可选值 | 描述 |
---|---|---|
id | String | 唯一标志 |
parent_id | String | 父节点ID |
order | Number | 排序,0开始,onDrag后order会重置 |
name | String | 默认显示内容 |
open | Boolean | true展开,false收起 |
lists | Array | 子节点 |
lists 配置示例
[ { "id":40, "parent_id":0, "order":0, "name":"动物类", "uri":"/masd/ds", "open":true, "lists":[] },{ "id":5, "parent_id":0, "order":1, "name":"昆虫类", "uri":"/masd/ds", "open":true, "lists":[ { "id":12, "parent_id":5, "open":true, "order":0, "name":"蚂蚁", "uri":"/masd/ds", "lists":[] } ] }, { "id":19, "parent_id":0, "order":2, "name":"植物类", "uri":"/masd/ds", "open":true, "lists":[] } ] 复制代码
列(columns)配置
参数 | 可选值 | 描述 |
---|---|---|
type | 'selection', 'actions' | selection会显示折叠图标,actions指操作栏 |
title | String | 表格标题 |
field | String | 单元格内容取值使用 |
width | Number | 单元格宽度 |
align | left,center,right | 单元格对齐方式,默认局左对齐 |
formatter | Function | 自定义单元格显示内容,参数为当前行数据 |
columns 配置示例
[ { type: 'selection', title: '菜单名称', field: 'name', width: 200, align: 'center', formatter: (item) => { return '<a>'+item.name+'</a>' } }, { title: '链接', field: 'url', width: 200, align: 'center' }, { title: '操作', type: 'action', width: 350, align: 'center', actions: [ { text: '查看角色', onclick: this.onDetail, formatter: (item) => { return '<i>查看角色</i>' } }, { text: '编辑', onclick: this.onEdit, formatter: (item) => { return '<i>编辑</i>' } } ] }, ] 复制代码
实现原理
组件结构
dragTreeTable.vue是入口组件,定义整体结构 row是递归组件(核心组件) clolmn单元格,内容承载 space控制缩进 复制代码
核心点
1. 核心组件row,通过组件递归自己实现树形结构,并非用JSX方式 2. 通过v-html传入函数,返回自定义html,实现单元格内容自定义 3. 通过H5的新特性draggable,实现拖拽,拖拽的同时需要匹配对应的行,并区分上/中/下,分别对应上移/下移/中间插入,并高亮,drop时对数组进行重新排列,生成新的数组 复制代码
递归调用写法如下
<template> <div class="tree-block" draggable="true" @dragstart="dragstart($event)" @dragend="dragend($event)"> <div class="tree-row" @click="toggle" :tree-id="model.id" :tree-p-id="model.parent_id"> <column v-for="(subItem, subIndex) in columns" v-bind:class="'align-' + subItem.align" :field="subItem.field" :width="subItem.width" :key="subIndex"> <span v-if="subItem.type === 'selection'"> <space :depth="depth"/> <span v-if = "model.lists && model.lists.length" class="zip-icon" v-bind:class="[model.open ? 'arrow-bottom' : 'arrow-right']"> </span> <span v-else class="zip-icon arrow-transparent"> </span> <span v-if="subItem.formatter" v-html="subItem.formatter(model)"></span> <span v-else v-html="model[subItem.field]"></span> </span> <span v-else-if="subItem.type === 'action'"> <a class="action-item" v-for="(acItem, acIndex) in subItem.actions" :key="acIndex" type="text" size="small" @click.stop.prevent="acItem.onclick(model)"> <i :class="acItem.icon" v-html="acItem.formatter(model)"></i> </a> </span> <span v-else-if="subItem.type === 'icon'"> {{model[subItem.field]}} </span> <span v-else> {{model[subItem.field]}} </span> </column> <div class="hover-model" style="display: none"> <div class="hover-block prev-block"> <i class="el-icon-caret-top"></i> </div> <div class="hover-block center-block"> <i class="el-icon-caret-right"></i> </div> <div class="hover-block next-block"> <i class="el-icon-caret-bottom"></i> </div> </div> </div> <row v-show="model.open" v-for="(item, index) in model.lists" :model="item" :columns="columns" :key="index" :depth="depth * 1 + 1" v-if="isFolder"> </row> </div> </template> 复制代码
动态匹配实现
filter(x,y) { var rows = document.querySelectorAll('.tree-row') this.targetId = undefined for(let i=0; i < rows.length; i++) { const row = rows[i] const rx = this.getElementLeft(row); const ry = this.getElementTop(row); const rw = row.clientWidth; const rh = row.clientHeight; if (x > rx && x < (rx + rw) && y > ry && y < (ry + rh)) { const diffY = y - ry const hoverBlock = row.children[row.children.length - 1] hoverBlock.style.display = 'block' const targetId = row.getAttribute('tree-id') if (targetId == window.dragId){ this.targetId = undefined return } this.targetId = targetId let whereInsert = '' var rowHeight = document.getElementsByClassName('tree-row')[0].clientHeight if (diffY/rowHeight > 3/4) { if (hoverBlock.children[2].style.opacity !== '0.5') { this.clearHoverStatus() hoverBlock.children[2].style.opacity = 0.5 } whereInsert = 'bottom' } else if (diffY/rowHeight > 1/4) { if (hoverBlock.children[1].style.opacity !== '0.5') { this.clearHoverStatus() hoverBlock.children[1].style.opacity = 0.5 } whereInsert = 'center' } else { if (hoverBlock.children[0].style.opacity !== '0.5') { this.clearHoverStatus() hoverBlock.children[0].style.opacity = 0.5 } whereInsert = 'top' } this.whereInsert = whereInsert } } } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Guns 旗舰版2.1发布,更新树形表格
- 在Bootstrap开发框架中使用bootstrapTable表格插件和jstree树形列表插件时候,对树列表条件和查询...
- MySQL 实现树形的遍历
- 巧用 MyBatis 构建树形结构
- js 将线性数据转为树形
- 树形结构数据存储方案(五):区间嵌套
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。