当前位置:   article > 正文

Element - el-tree 树形结构拖拽以及增删改查_element plus el-tree 拖拽

element plus el-tree 拖拽

1、SystemTreeItem.vue

  1. <el-tree
  2. :data="treeData"
  3. node-key="id"
  4. default-expand-all
  5. :expand-on-click-node="false"
  6. @node-drop="handleDrop"
  7. @node-drag-enter="nodeDragEnter"
  8. draggable
  9. :allow-drop="allowDrop"
  10. :allow-drag="allowDrag"
  11. >
  12. <span class="custom-tree-node" :class="{isDisabled: node.data.enabled === false}" slot-scope="{ node, data }" :key="data.id">
  13. <template v-if="!node.data.isEdit">
  14. <el-tooltip class="item" effect="light" :content="node.data.knowledgeName" :open-delay="1000" placement="bottom">
  15. <span class="label" v-if="node.data.enabled" @dblclick="nodeClick(data,node,true)">{{ node.data.knowledgeName }}</span>
  16. <span class="label isDisabled" v-else-if="node.data.id && !node.data.enabled" @dblclick="nodeClick(data,node,true)">{{ "(已禁用)" + node.data.knowledgeName }}</span>
  17. </el-tooltip>
  18. </template>
  19. <span class="knowledgeCode" v-else-if="node.data.isEdit && hasAuth('knowledge_points_system_edit')">
  20. <el-input v-model.trim="knowledgeCode" placeholder="请输入知识点code" v-focus />
  21. <el-button size="mini" type="primary" :disabled="!knowledgeCode" @click="addKnoeledgeCode(node,data)">确 定</el-button>
  22. <el-button size="mini" @click="nodeClick(data,node,false)">取 消</el-button>
  23. </span>
  24. <span class="operation" v-show="!node.data.isEdit">
  25. <el-button type="text" class="btn" :disabled="!canStatusChange || !node.data.id" @click="insertAfter(data, node)" style="color: #333">
  26. 添加同级
  27. </el-button>
  28. <span>|</span>
  29. <el-button type="text" class="btn" :disabled="!canStatusChange || !node.data.id" @click="append(data, node)" style="color: #333">
  30. 添加下级
  31. </el-button>
  32. <span>|</span>
  33. <el-button type="text" class="btn" :disabled="!node.data.id" @click="toDetail(data)" style="color: #333">
  34. 查看详情
  35. </el-button>
  36. <span>|</span>
  37. <el-button type="text" class="btn" :disabled="!node.data.id" @click="remove(node, data)" style="color: #333">
  38. 删除
  39. </el-button>
  40. </span>
  41. </span>
  42. </el-tree>
  43. <script>
  44. import { debounce } from '@/utils/comUtil'
  45. export default {
  46. name: 'systemTreeItem',
  47. data() {
  48. return {
  49. knowledgeCode: '',
  50. }
  51. },
  52. props: {
  53. treeData: Array,
  54. canStatusChange: Boolean
  55. },
  56. directives: {
  57. focus: {
  58. inserted: function(el) {
  59. el.querySelector("input").focus();
  60. }
  61. }
  62. },
  63. methods: {
  64. addKnoeledgeCode(node,data){
  65. this.$emit('addKnoeledgeCode',node,data,this.knowledgeCode)
  66. this.knowledgeCode = ""
  67. },
  68. // 拖拽成功完成时触发的事件
  69. handleDrop(draggingNode, dropNode, dropType, e) {
  70. this.$emit('handleDrop', draggingNode, dropNode, dropType, e)
  71. },
  72. // 获取总层级数
  73. getTotalLevel(node, arr) {
  74. if (node.childNodes && node.childNodes.length) {
  75. node.childNodes.forEach(item => {
  76. arr.push(item.level)
  77. if(item.childNodes && node.childNodes.length) {
  78. this.getTotalLevel(item, arr)
  79. }
  80. })
  81. }else{
  82. arr.push(node.level)
  83. }
  84. },
  85. // 拖拽进入其他节点时触发的事件
  86. nodeDragEnter(draggingNode, dropNode){
  87. // console.log("拖拽进入其他节点时触发的事件",draggingNode, dropNode)
  88. let arr = []
  89. this.getTotalLevel(draggingNode, arr)
  90. const totalLevel = Math.max(...arr) - draggingNode.level + 1 + dropNode.level
  91. if(totalLevel <= 8) return
  92. this.banMessag();
  93. arr = []
  94. },
  95. banMessag: debounce(function(){
  96. this.$message({
  97. type: 'warning',
  98. message: '节点层级已达最大值!',
  99. })
  100. },500),
  101. // 拖拽时判定目标节点能否被放置
  102. allowDrop(draggingNode, dropNode, type) {
  103. //draggingNode 被拖拽的节点
  104. //dropNode 目标节点
  105. //type 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
  106. // console.log(draggingNode.level, dropNode.level, type)
  107. // 获取被拖拽的节点层级
  108. let arr = []
  109. this.getTotalLevel(draggingNode, arr)
  110. const totalLevel = Math.max(...arr) - draggingNode.level + 1 + dropNode.level
  111. // 插入至目标节点内部 节点层级大于8级 不能被放置
  112. if(totalLevel > 8){
  113. this.banMessag();
  114. arr = []
  115. return false
  116. }else{
  117. return true;
  118. }
  119. },
  120. // 判断节点能否被拖拽
  121. allowDrag(draggingNode) {
  122. // console.log("allowDrag", draggingNode)
  123. // 节点处于编辑状态 或者 节点为空节点 不能拖拽
  124. if(draggingNode.data.isEdit || !draggingNode.data.id){
  125. return false
  126. }else{
  127. return true
  128. }
  129. },
  130. // 节点双击事件 节点变为可编辑状态
  131. nodeClick(data, node, isEdit) {
  132. if(isEdit === false){
  133. this.knowledgeCode = ""
  134. }
  135. this.$emit('nodeClick', data, node, isEdit)
  136. },
  137. // 添加同级
  138. insertAfter(data, refNode) {
  139. this.$emit('insertAfter', data, refNode)
  140. },
  141. // 添加下级
  142. append(data, parentNode) {
  143. this.$emit('append', data, parentNode)
  144. },
  145. toDetail(data) {
  146. this.$emit('toDetail', data)
  147. },
  148. remove(node, data) {
  149. this.$emit('remove', node, data)
  150. },
  151. },
  152. }
  153. </script>

2、SystemTree.vue

拖拽涉及代码是:handleDrop

  1. <system-tree-item
  2. :treeData="systemTreeList"
  3. :canStatusChange="canStatusChange"
  4. @handleDrop="handleDrop"
  5. @nodeClick="nodeClick"
  6. @insertAfter="insertAfter"
  7. @append="append"
  8. @toDetail="toDetail"
  9. @remove="remove"
  10. @addKnoeledgeCode="addKnoeledgeCode"
  11. />
  12. <script>
  13. import systemTreeService from '@/api/systemTreeService'
  14. import SystemTreeItem from './components/SystemTreeItem.vue'
  15. export default {
  16. name: 'SystemTree',
  17. components: { SystemTreeItem },
  18. data() {
  19. return {
  20. systemTreeList: [], // 体系树列表
  21. list: [], // 备份体系树列表数据
  22. canStatusChange: false //禁用/启用是否可切换 体系树无数据,节点处于编辑状态,节点无id 为false
  23. }
  24. },
  25. created() {
  26. this.getSystemTreeList()
  27. },
  28. methods: {
  29. // 体系树数据排序
  30. sortTreeData(arr){
  31. if(!arr.length) return
  32. arr.sort((a,b) => a.sort - b.sort)
  33. arr.forEach(item => {
  34. if(item.children){
  35. this.sortTreeData(item.children)
  36. }
  37. })
  38. },
  39. // 获取体系树列表
  40. async getSystemTreeList(type) {
  41. if(!this.systemCode) return
  42. if (type === 'add') {
  43. this.systemTreeList = [
  44. {
  45. id: '',
  46. knowledgeCode: '',
  47. knowledgeName: '',
  48. parentId: 'ROOT',
  49. level: 1,
  50. systemCode: this.systemCode,
  51. isEdit: true,
  52. enabled: true,
  53. children: []
  54. },
  55. ]
  56. } else {
  57. let res = await systemTreeService.getSystemTreeList({ systemCode: this.systemCode })
  58. if (res && res.errorCode === 0) {
  59. this.systemTreeList = res.result // 后端返回的数据为树状结构
  60. this.sortTreeData(this.systemTreeList)
  61. // 备份原数据 拖拽失败后还原
  62. this.list = JSON.parse(JSON.stringify(this.systemTreeList))
  63. if(this.systemTreeList.length){
  64. this.canStatusChange = true
  65. }else{
  66. this.systemTreeList = [
  67. {
  68. id: '',
  69. knowledgeCode: '',
  70. knowledgeName: '',
  71. parentId: 'ROOT',
  72. level: 1,
  73. systemCode: this.systemCode,
  74. isEdit: true,
  75. enabled: true,
  76. children: []
  77. },
  78. ]
  79. this.canStatusChange = false
  80. }
  81. } else {
  82. this.systemTreeList = []
  83. this.canStatusChange = false
  84. }
  85. }
  86. },
  87. // 添加知识点
  88. async addKnoeledgeCode(node, data, knowledgeCode) {
  89. // console.log("添加知识点", node, data)
  90. node.data.isEdit = false
  91. data.isEdit = false
  92. if (knowledgeCode) {
  93. if(data.id){
  94. // 替换
  95. // 如果knowledgeCode等于oldKnowledgeCode
  96. let oldKnowledgeCode = data.knowledgeCode
  97. if(knowledgeCode === oldKnowledgeCode){
  98. this.$message({
  99. type: 'warning',
  100. message: '当前knowledgeCode与旧knowledgeCode相同,不能替换!'
  101. })
  102. return
  103. }
  104. let params = {
  105. systemCode: this.systemCode,
  106. nodeId: data.id,
  107. oldKnowledgeCode,
  108. newKnowledgeCode: knowledgeCode,
  109. }
  110. let res = await systemTreeService.updateKnowledgePoint(params)
  111. if (res && res.errorCode === 0) {
  112. this.$message({
  113. type: 'success',
  114. message: res.errorInfo,
  115. })
  116. }
  117. }else{
  118. // 新增 添加同级 添加下级
  119. // 添加同级 若为一级节点 nodeParentId 为 "", 否则为node.parent.data.id
  120. let nodeParentId = node.level === 1 ? "" : node.parent.data.id
  121. let params = {
  122. systemCode: this.systemCode,
  123. knowledgeCode,
  124. nodeParentId,
  125. }
  126. let res = await systemTreeService.addKnowledgePoint(params)
  127. if (res && res.errorCode === 0) {
  128. this.$message({
  129. type: 'success',
  130. message: res.errorInfo,
  131. })
  132. }
  133. }
  134. this.getSystemTreeList()
  135. }
  136. },
  137. // 拖拽事件
  138. async handleDrop(draggingNode, dropNode, dropType,e) {
  139. //draggingNode 被拖拽的节点
  140. //dropNode 目标节点
  141. //dropType 类型 被拖拽的节点相对于目标节点的位置 inner before after
  142. // console.log('tree drop', draggingNode, dropNode, dropType)
  143. // 难点在于获取受影响的节点,然后遍历,后端根据节点ID修改父节点ID以及sort
  144. let paramData = [];
  145. // 当拖拽类型不为inner,同级排序,寻找目标节点的父ID,获取其对象以及所有的子节点
  146. // 当拖拽类型为inner,说明拖拽节点成为了目标节点的子节点,只需获取目标节点对象
  147. let data = dropType != "inner" ? dropNode.parent.data : dropNode.data;
  148. //目标节点为一级节点,并且拖拽类型不为inner即当前节点将成为与目标节点同一级的节点,也是一级节点
  149. //nodeData=dropNode.parent.data,但是因为目标节点已经是一级节点了,因此nodeData还是目标节点
  150. //目标节点为一级节点,并且拖拽类型为inner即当前节点将成为目标节点的子节点即二级节点
  151. //nodeDate=dropNode.parent.data.children,即为目标节点的父节点的子节点,即目标节点同一层级的节点
  152. //目标节点不是一级节点,并且拖拽类型不为inner即当前节点将成为与目标节点同一层级的节点
  153. //nodeDate=dropNode.parent.data.children,即为目标节点的父节点的子节点,即目标节点同一层级的节点
  154. //目标节点不是一级节点,并且拖拽类型为inner即当前节点将成为目标节的子节点
  155. //nodeDate=dropNode.data.children,即目标节点的子节点
  156. let nodeData = dropNode.level == 1 && dropType != "inner" ? data : data.children;
  157. let nodeParentId = ""
  158. nodeData.forEach((item, i) => {
  159. if(dropType != "inner"){
  160. if(draggingNode.data.parentId === dropNode.data.parentId){
  161. nodeParentId = item.parentId
  162. }else{
  163. nodeParentId = dropNode.data.parentId
  164. }
  165. }else{
  166. nodeParentId = data.id
  167. }
  168. let collection = {
  169. nodeId: item.id,
  170. nodeParentId,
  171. sort: i + 1
  172. };
  173. paramData.push(collection);
  174. });
  175. // console.log(paramData)
  176. let params = {
  177. systemCode: this.systemCode,
  178. nodeSortList: paramData
  179. }
  180. let res = await systemTreeService.dragTreeNode(params)
  181. if(res && res.errorCode === 0){
  182. this.$message({
  183. type: 'success',
  184. message: res.errorInfo,
  185. })
  186. this.getSystemTreeList()
  187. }else{
  188. // 接口报错之后,将数据恢复
  189. this.systemTreeList = this.list
  190. }
  191. },
  192. // 节点双击事件
  193. nodeClick(data, node, isEdit) {
  194. // console.log("nodeClick",data,node,isEdit)
  195. // 当节点处于编辑状态 或者 节点id不存在
  196. if(isEdit || !data.id){
  197. this.canStatusChange = false
  198. }else{
  199. this.canStatusChange = true
  200. }
  201. this.$set(data,'isEdit',isEdit)
  202. this.$set(node.data,'isEdit',isEdit)
  203. },
  204. // 添加同级
  205. insertAfter(data, refNode) {
  206. // console.log("添加同级", data, refNode)
  207. const newNode = {
  208. parentId: data.parentId,
  209. id: '',
  210. knowledgeCode: '',
  211. knowledgeName: '',
  212. level: data.level,
  213. systemCode: this.systemCode,
  214. isEdit: true,
  215. enabled: true,
  216. children: [],
  217. }
  218. this.canStatusChange = false
  219. if(data.parentId === 'ROOT'){
  220. refNode.parent.data.push(newNode)
  221. }else{
  222. refNode.parent.data.children.push(newNode)
  223. }
  224. },
  225. //添加下级
  226. append(data, parentNode) {
  227. // console.log('添加下级', data)
  228. if (data.level >= 8) {
  229. this.$message({
  230. type: 'warning',
  231. message: '节点层级已达最大值!',
  232. })
  233. return
  234. } else {
  235. const newChild = {
  236. parentId: data.id,
  237. id: '',
  238. knowledgeCode: '',
  239. knowledgeName: '',
  240. level: data.level + 1,
  241. systemCode: this.systemCode,
  242. isEdit: true,
  243. enabled: true,
  244. children: [],
  245. }
  246. this.canStatusChange = false
  247. if (!data.children) {
  248. this.$set(data, 'children', [])
  249. }
  250. data.children.push(newChild)
  251. }
  252. }
  253. }
  254. }
  255. </script>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/119213
推荐阅读
相关标签
  

闽ICP备14008679号