mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-30 12:52:43 +08:00
feat(tree): add base tree
This commit is contained in:
parent
28642ea502
commit
6d4b50bf37
@ -5,10 +5,10 @@
|
||||
</div>
|
||||
<div
|
||||
class="n-doc-section__view"
|
||||
style="flex-wrap: nowrap;"
|
||||
style="display: block;"
|
||||
>
|
||||
<!--EXAMPLE_START-->
|
||||
Write some demo here
|
||||
<n-tree :data="data" />
|
||||
<!--EXAMPLE_END-->
|
||||
</div>
|
||||
<pre class="n-doc-section__inspect">Inspect some value here</pre>
|
||||
@ -19,9 +19,25 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
function genData (layer = 4, depth = 0, prefix = '') {
|
||||
if (layer === depth) return
|
||||
const data = []
|
||||
const count = 4
|
||||
for (let i = 0; i < count; ++i) {
|
||||
data.push({
|
||||
label: `${prefix}_${i}`,
|
||||
value: `${prefix}_${i}`,
|
||||
children: genData(layer, depth + 1, `${prefix}_${i}`)
|
||||
})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
data: genData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ import datePickerDebug from './debugComponents/datePickerDebug'
|
||||
import backTopDebug from './debugComponents/backTopDebug'
|
||||
import cancelMarkDebug from './debugComponents/cancelMarkDebug'
|
||||
import cascaderDebug from './debugComponents/cascaderDebug'
|
||||
import verticalAlignDebug from './debugComponents/verticalAlignDebug'
|
||||
|
||||
Vue.use(NaiveUI)
|
||||
Vue.use(VueRouter)
|
||||
@ -152,7 +153,8 @@ const routes = [
|
||||
{ path: '/n-loading-bar', component: loadingBarDemo },
|
||||
{ path: '/n-time', component: timeDemo },
|
||||
{ path: '/n-slider', component: sliderDemo },
|
||||
{ path: '/n-tree', component: treeDemo }
|
||||
{ path: '/n-tree', component: treeDemo },
|
||||
{ path: '/n-vertical-align-debug', component: verticalAlignDebug }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
import Scaffold from './src/main.vue'
|
||||
import Tree from './src/main.js'
|
||||
|
||||
Scaffold.install = function (Vue) {
|
||||
Vue.component(Scaffold.name, Scaffold)
|
||||
Tree.install = function (Vue) {
|
||||
Vue.component(Tree.name, Tree)
|
||||
}
|
||||
|
||||
export default Scaffold
|
||||
export default Tree
|
||||
|
180
packages/common/Tree/src/main.js
Normal file
180
packages/common/Tree/src/main.js
Normal file
@ -0,0 +1,180 @@
|
||||
import {
|
||||
rootedOptions,
|
||||
patchedOptions,
|
||||
linkedCascaderOptions,
|
||||
menuOptions
|
||||
} from '../../../utils/data/menuModel'
|
||||
|
||||
const NTreeNodeExpandWrapper = {
|
||||
methods: {
|
||||
handleBeforeLeave () {
|
||||
this.$el.style.maxHeight = this.$el.offsetHeight + 'px'
|
||||
this.$el.style.height = this.$el.offsetHeight + 'px'
|
||||
this.$el.getBoundingClientRect()
|
||||
},
|
||||
handleLeave () {
|
||||
this.$el.style.maxHeight = 0
|
||||
this.$el.getBoundingClientRect()
|
||||
},
|
||||
handleEnter () {
|
||||
this.$nextTick().then(() => {
|
||||
this.$el.style.height = this.$el.offsetHeight + 'px'
|
||||
this.$el.style.maxHeight = 0
|
||||
this.$el.getBoundingClientRect()
|
||||
this.$el.style.maxHeight = this.$el.style.height
|
||||
})
|
||||
},
|
||||
handleAfterEnter () {
|
||||
this.$el.style.height = null
|
||||
this.$el.style.maxHeight = null
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('transition', {
|
||||
props: {
|
||||
name: 'n-height-seamlessly-expand'
|
||||
},
|
||||
on: {
|
||||
beforeLeave: this.handleBeforeLeave,
|
||||
leave: this.handleLeave,
|
||||
enter: this.handleEnter,
|
||||
afterEnter: this.handleAfterEnter
|
||||
}
|
||||
}, this.$slots.default)
|
||||
}
|
||||
}
|
||||
|
||||
const NTreeNode = {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
expand: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick () {
|
||||
this.$emit('click', this.data)
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('span', {
|
||||
on: {
|
||||
click: this.handleClick
|
||||
}
|
||||
}, [
|
||||
this.data.isLeaf ? null : this.expand ? 'v ' : '> ',
|
||||
this.data.label
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
function genSingleNode (node, h, self) {
|
||||
if (node.isLeaf) {
|
||||
return h('li', {
|
||||
staticClass: 'n-tree-node'
|
||||
}, [
|
||||
h(NTreeNode, {
|
||||
props: {
|
||||
data: node,
|
||||
expand: self.expandNodesId.includes(node.id)
|
||||
},
|
||||
on: {
|
||||
click: self.handleNodeClick
|
||||
}
|
||||
})
|
||||
])
|
||||
} else if (node.children) {
|
||||
return h('li', {
|
||||
staticClass: 'n-tree-node'
|
||||
}, [
|
||||
h(NTreeNode, {
|
||||
props: {
|
||||
data: node,
|
||||
expand: self.expandNodesId.includes(node.id)
|
||||
},
|
||||
on: {
|
||||
click: self.handleNodeClick
|
||||
}
|
||||
}),
|
||||
h(NTreeNodeExpandWrapper, {},
|
||||
[self.expandNodesId.includes(node.id)
|
||||
? h('ul', {
|
||||
staticClass: 'n-tree-children-wrapper'
|
||||
}, node.children.map(child => genSingleNode(child, h, self)))
|
||||
: null]
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
function convertRootedOptionsToVNodeTree (root, h, self) {
|
||||
return root.children.map(child => genSingleNode(child, h, self))
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'NTree',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
checkable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
patches: new Map(),
|
||||
expandNodesId: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data () {
|
||||
this.patches = new Map()
|
||||
this.expandNodesId = []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rootedOptions () {
|
||||
return rootedOptions(this.data)
|
||||
},
|
||||
patchedOptions () {
|
||||
return patchedOptions(this.rootedOptions, this.patches)
|
||||
},
|
||||
linkedCascaderOptions () {
|
||||
return linkedCascaderOptions(this.patchedOptions, 'multiple-all-options')
|
||||
},
|
||||
menuOptions () {
|
||||
return menuOptions(this.linkedCascaderOptions)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// console.log(this.menuOptions)
|
||||
},
|
||||
methods: {
|
||||
toggleExpand (node) {
|
||||
const index = this.expandNodesId.findIndex(expandNodeId => expandNodeId === node.id)
|
||||
if (~index) {
|
||||
this.expandNodesId.splice(index, 1)
|
||||
} else {
|
||||
if (!node.isLeaf) {
|
||||
this.expandNodesId.push(node.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
handleNodeClick (node) {
|
||||
this.toggleExpand(node)
|
||||
// console.log(this.expandNodesId)
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('div', {
|
||||
staticClass: 'n-tree'
|
||||
}, convertRootedOptionsToVNodeTree(this.menuOptions[0], h, this))
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<div>example</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NScaffold'
|
||||
}
|
||||
</script>
|
@ -1,6 +1,17 @@
|
||||
@import './mixins/mixins.scss';
|
||||
@import './theme/default.scss';
|
||||
|
||||
@include b(scaffold) {
|
||||
position: relative;
|
||||
@include b(tree) {
|
||||
ul, li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
@include b(tree-children-wrapper) {
|
||||
@include height-seamlessly-expand-transition();
|
||||
margin-left: 16px;
|
||||
}
|
||||
@include b(tree-node) {
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user