feat(tree): add base tree

This commit is contained in:
07akioni 2019-09-12 11:58:46 +08:00
parent 28642ea502
commit 6d4b50bf37
6 changed files with 218 additions and 18 deletions

View File

@ -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()
}
}
}

View File

@ -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 }
]
},
{

View File

@ -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

View 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))
}
}

View File

@ -1,9 +0,0 @@
<template>
<div>example</div>
</template>
<script>
export default {
name: 'NScaffold'
}
</script>

View File

@ -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) {
}
}