html树形结构主从命名,VUE实战7:树形结构,文件树,节点树共用一套代码 NodeTree,admin后台...

本文介绍如何使用Vue构建一个可编辑的树形结构组件,包括展示及编辑功能。通过递归和v-model实现数据双向绑定,支持节点的增删改。组件命名为NodeTree,分为FileTree和TreeNode两个部分,具备单选且排他的特性。文章提供代码示例,并指出可通过事件传播实现节点选择。完整代码可在GitHub获取。
摘要由CSDN通过智能技术生成

本次介绍的内容,稍稍复杂了一点,用 VUE 实现树形结构。目前这个属性结构还没有编辑功能,仅仅是展示。明天再开一篇文章,介绍如何增加编辑功能,标题都想好了。先看今天的展示效果:

bVbEdOa

构建树必须用到递归,使用 slot 这种直观明了的方式,已经行不通了。只能通过属性参数,传递一个树形的数据结构给组件,传入的数据结构大致是这个样子:

[

{

title:‘页面 ’

selected:false,

opened:false,

isFolder:true,

children:[

{

title:'index.html',

selected:false,

opened:false,

icon:"far fa-file-code",

},

{

title:'product.html',

selected:false,

opened:false,

icon:"far fa-file-code",

},

],

},

{

title:‘样式’

selected:false,

opened:false,

isFolder:true,

children:[

{

title:'style.css',

selected:false,

opened:false,

icon:"far fa-file-code",

},

],

},

]

每个节点通过 children 嵌套子节点。需要注意的是,我们希望这颗树是可以被编辑的,可以增加、删除、编辑其节点,所以需要数据的双向绑定,不能通过普通属性 props 传递给组件,而是通过 v-model 传递。

RXEditor 项目中,只有两个地方用到了树形结构,要制作的组件满足这两处需求就可以,因为不是构建一个通用类库,就可以相对简单些。这两处地方一处用于展示并编辑文件目录结构,一处是节点树,纯显示,没有编辑功能。文件树只有叶子节点可以被选中,节点树所有节点都可以被选中。都是单选,无复选需求。

给这个控件取个大气的名字,叫 NodeTree 吧,先看如何使用 NodeTree。

第一处调用:

第二处调用:

通过 v-model 传递树形数据结构,openIcon 是节点展开时的图标,closeIcion 是节点闭合时的图标,leafIcon 是没有子节点时的图标。这些图标如果不设置,会有缺省值,是文件夹跟文件的样子。为了增加可扩展性,树形数据结构也可以放置图标,数据结构里的图标设置优先级高,可以覆盖控件的设置。明白个原理,想做成什么样子,看自己的项目需求。folderCanbeSelected 参数是指含有子节点的节点(比如文件夹)是否可以被选中。

在 src 目录下新建 tree 目录,放两个文件:

bVbEdOj

NodeTree 是树形控件,TreeNode 是树形控件内部的节点,名字稍微优点绕,但是是我喜欢的命名方式。

NodeTree.vue 的代码(省略 CSS):

>

name: 'FileTree',

props: {

value: { default: []},

openIcon:{ default: 'fas fa-folder-open'},

closeIcon:{ default: 'fas fa-folder'},

leafIcon:{ default: 'fas fa-file' },

folderCanbeSelected:{ default:false }

},

components:{

TreeNode

},

data() { return {

};

},

computed:{

inputValue: {

get:function() { return this.value;

},

set:function(val) { this.$emit('input', val);

},

},

},

methods: {

nodeSelected(selectedNode){ this.inputValue.forEach(child=>{ this.resetSelected(selectedNode, child)

}) this.$emit('nodeSelected', selectedNode)

}, //递归充置选择状态

resetSelected(selectedNode, node){

node.selected = (node === selectedNode) if(node.children){

node.children.forEach(child=>{ this.resetSelected(selectedNode, child)

})

}

}

},

}

这个代码逻辑很简单,就是接收外面参数,循环调用 TreeNode。要自定义 v-model 的话,需要用到属性 (props) value,计算属性 inputValue 用于修改 value,具体原理,可以参考 VUE 官方文档。

需要特殊注意的是 nodeSelected 事件,这个事件在子节点产生,通过冒泡的方式层层往父节点发送,最后到达 NodeTree 组件。NodeTree 组件再通过 $emit 方法,分发到外层调用组件。

这次实现的控件是单选,排他的,需要递归调用 resetSelected 方法消除其它节点的选中状态。

TreeNode 组件的代码如下(省略 CSS,如需要,请到 GIthub 获取):

>

>

name: 'TreeNode',

props: {

value: { default: {}},

openIcon:{ default: 'fas fa-folder-open'},

closeIcon:{ default: 'fas fa-folder'},

leafIcon:{ default: 'fas fa-file' },

folderCanbeSelected:{default: false},

},

data() { return {

}

},

computed:{

inputValue: {

get:function() { return this.value;

},

set:function(val) { this.$emit('input', val);

},

},

icon(){ if(this.hasChildren){ return this.inputValue.opened ? this.openIcon : this.closeIcon

} return this.inputValue.icon !== undefined ? this.inputValue.icon : this.leafIcon

},

showChild(){ return this.hasChildren && this.inputValue.opened

},

hasChildren(){ return this.inputValue.children &&this.inputValue.children.length > 0 },

},

methods: {

click(){ if((this.hasChildren && this.folderCanbeSelected) || !this.hasChildren){ this.inputValue.selected = true

this.$emit('nodeSelected', this.inputValue)

} else { this.inputValue.opened = !this.inputValue.opened

}

},

iconClick(event){ if(this.hasChildren && this.folderCanbeSelected){

event.stopPropagation() this.inputValue.opened = !this.inputValue.opened

}

},

nodeSelected(node){ this.$emit('nodeSelected', node)

},

onContextMenu(event){

console.log(event)

}

},

}

父组件调用时通过 v-mode,把整个节点的数据传入该控件。该组件递归调用自身,从而形成树形结构。三个状态:opened(展开),closed(闭合),selected(选中)存于 model 数据中,这样在控件外部,通过修改 model,也可以控制节点状态。

本功能介绍完毕,代码请自行到 github 获取相应历史版本:

https://github.com/vularsoft/studio-ui

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值