kui-vue
Version:
A high quality UI Toolkit built on Vue.js 2.0
309 lines (292 loc) • 10.3 kB
JSX
import Icon from '../icon'
import { Checkbox } from '../checkbox'
import { Button } from '../button'
import Node from './node.jsx'
import { getTranstionProp } from '../base/transition'
import { getChild } from '../_tool/utils'
import cloneVNode from '../_tool/clone.js'
import { Sync, RemoveCircleOutline, AddCircleOutline, ChevronForward } from 'kui-icons'
export default {
name: 'TreeNode',
props: {
data: Object,
isLeaf: Object,
disabled: Boolean,
icon: [String, Array],
title: String,
},
provide() {
return {
VNode: this,
}
},
data() {
return {
defaultData: this.data || {},
loading: false,
draged: false,
droped: false,
reload: true,
level: 0
}
},
watch: {
data(val, Oval) {
this.defaultData = val || {}
}
},
inject: {
Tree: { default: {} },
VNode: { default: null },
},
created() {
let { defaultCheckedKeys = [], draggable, checkStrictly } = this.Tree
let checked = defaultCheckedKeys.indexOf(this.$vnode.key) > -1
if (checked && !checkStrictly) {
this.updateChildCheck(this.defaultData, checked)
if (this.VNode) {
this.updateParentCheck(this.VNode)
}
}
if (this.VNode) {
this.level = this.VNode.level + 1
}
},
beforeDestroy() {
/* let { defaultSelectedKeys = [],
defaultExpandedKeys = [],
defaultCheckedKeys = [],
halfCheckedKeys = [],
} = this.Tree
let key = this.$vnode.key
let s = defaultSelectedKeys.indexOf(key),
e = defaultExpandedKeys.indexOf(key),
c = defaultCheckedKeys.indexOf(key),
h = halfCheckedKeys.indexOf(key);
s > -1 && defaultSelectedKeys.splice(s, 1);
e > -1 && defaultExpandedKeys.splice(e, 1);
c > -1 && defaultCheckedKeys.splice(c, 1);
h > -1 && halfCheckedKeys.splice(h, 1); */
},
methods: {
updateChildCheck({ children = [], disabled }, checked) {
!disabled && children.forEach(item => {
if (!item.disabled) {
let { defaultCheckedKeys } = this.Tree
const key = item.key
if (key !== undefined) {
let index = defaultCheckedKeys.indexOf(key)
checked ? index < 0 && defaultCheckedKeys.push(key) : index > -1 && defaultCheckedKeys.splice(index, 1)
this.Tree.defaultCheckedKeys = defaultCheckedKeys
this.updateChildCheck(item, checked)
}
}
})
},
updateParentCheck({ defaultData, VNode }) {
if (!defaultData || defaultData.disabled) return;
let { children = [], key } = defaultData
let { defaultCheckedKeys, halfCheckedKeys } = this.Tree
const normal = children.filter(({ disabled }) => !disabled)
let checkedLength = normal.filter(({ key }) => defaultCheckedKeys.indexOf(key) > -1).length
let halfcheckedLength = normal.filter(({ key }) => halfCheckedKeys.indexOf(key) > -1).length
// let key = defaultData.key,
let isCheckAll = checkedLength == normal.length;
let halfIndex = halfCheckedKeys.indexOf(key)
let checkIndex = defaultCheckedKeys.indexOf(key)
isCheckAll ? defaultCheckedKeys.push(key) : (checkIndex > -1 && defaultCheckedKeys.splice(checkIndex, 1))
if ((halfcheckedLength > 0 || checkedLength > 0) && !isCheckAll)
halfIndex < 0 && halfCheckedKeys.push(key)
else
halfIndex > -1 && halfCheckedKeys.splice(halfIndex, 1);
VNode && this.updateParentCheck(VNode)
},
handleCheck(e) {
if (!this.defaultData.disabled) {
const checked = e.target.checked
let { Tree } = this
let key = this.$vnode.key
let { defaultCheckedKeys, halfCheckedKeys, checkStrictly } = this.Tree
let index = defaultCheckedKeys.indexOf(key)
checked && index < 0 ? defaultCheckedKeys.push(key) : defaultCheckedKeys.splice(index, 1)
this.Tree.defaultCheckedKeys = defaultCheckedKeys
let halfIndex = halfCheckedKeys.indexOf(key)
if (checked && halfIndex > -1) {
halfCheckedKeys.splice(halfIndex, 1)
}
if (!checkStrictly) {
// update child
this.updateChildCheck(this.defaultData, checked)
// update parent
this.VNode && this.updateParentCheck(this.VNode)
}
Tree.onCheck(e.target.checked, key, this.defaultData, this)
}
},
handleSelect(e) {
let { disabled, key } = this.defaultData
if (!disabled) {
let { Tree, multiple } = this
if (Tree.directory) {
this.handleExpand(e)
}
Tree.onSelect(key, this.defaultData, this)
}
},
handleExpand(e) {
e.stopPropagation()
let { Tree, VNode } = this
if ((VNode && VNode.$slots.default) || this.$slots.default) {
let data = {
...this.$props,
children: this.$children
}
Tree.onExpand(this.$vnode.key, data, this)
} else {
Tree.onExpand(this.$vnode.key, this.defaultData, this)
}
},
onDragStart(e) {
this.draged = true
this.Tree.onDragStart(e, this)
},
onDragEnd(e) {
this.draged = false
this.Tree.onDragEnd(e, { node: this.defaultData, parent: this.getParent() })
this.$forceUpdate()
},
onDragEnter(e) {
this.droped = true
this.Tree.onDragEnter(e, { node: this.defaultData, parent: this.getParent() })
},
onDragLeave(e) {
this.droped = false
this.Tree.onDragLeave(e, { node: this.defaultData, parent: this.getParent() })
},
onDrop(e) {
this.droped = false
if (!this.defaultData.disabled) {
this.Tree.onDrop(e, { node: this.defaultData })
}
},
onDragOver(e) {
e.preventDefault()
},
getParent() {
return this.VNode ? this.VNode.defaultData : { children: this.Tree.defaultData }
}
},
render(h) {
// return <div/>
let p = { ...this.$props }
delete p.data
let data = Object.assign(p, this.defaultData)
let { isLeaf, disabled, icon, title, children = [] } = data
let slotChilds = getChild(this.$slots.default)
let itemNode = [], { Tree, loading, reload } = this;
let key = this.$vnode.key
let { defaultSelectedKeys = [], defaultExpandedKeys = [], defaultCheckedKeys = [], halfCheckedKeys = [],
checkable, showLine, directory, draggable, showIcon, showExtra, expandedAll } = Tree
const expand = expandedAll || defaultExpandedKeys.indexOf(key) > - 1,
selected = defaultSelectedKeys.indexOf(key) > - 1,
checked = defaultCheckedKeys.indexOf(key) > - 1,
indeterminate = halfCheckedKeys.indexOf(key) > - 1;
let hasChilds = slotChilds.length > 0 || children.length > 0
let hasLoad = 'loadData' in Tree.$listeners || 'load-data' in Tree.$listeners
if ((hasChilds || hasLoad) && isLeaf !== true) {
let arrowCls = ['k-tree-arrow', { 'k-tree-arrow-open': expand }]
let arrowNode = <span class={arrowCls} onClick={this.handleExpand}>
<Button size="small" theme="normal" loading={loading} icon={loading ? Sync : (showLine ? (expand ? RemoveCircleOutline : AddCircleOutline) : ChevronForward)} spin={loading} />
</span>
itemNode.push(arrowNode)
} else {
itemNode.push(<span class="k-tree-commes"></span>)
}
// console.log(checked,checked, disabled, indeterminate)
if (checkable) {
let props = {
props: { checked, disabled, indeterminate },
on: { change: this.handleCheck }
}
itemNode.push(<Checkbox {...props} />)
}
let iconNode = null
if (icon && showIcon) {
iconNode = <Icon type={icon} class="k-tree-icon" />;
}
let titleCls = ['k-tree-title', { 'k-tree-title-selected': selected }]
if (Tree && Tree.$scopedSlots.title) {
title = Tree.$scopedSlots.title({ node: this.defaultData, parent: this.getParent() })
}
let innerNode = [iconNode, title]
const titleProps = {
class: titleCls,
attrs: {
tabIndex: "-1",
draggable: draggable && !disabled
},
on: {}
}
if (!directory) {
titleProps.on.click = this.handleSelect;
}
if (draggable) {
titleProps.on.dragstart = this.onDragStart
titleProps.on.dragend = this.onDragEnd
titleProps.on.drop = this.onDrop
titleProps.on.dragenter = this.onDragEnter
titleProps.on.dragleave = this.onDragLeave
titleProps.on.dragover = this.onDragOver
}
itemNode.push(<span {...titleProps}>{innerNode}</span>)
let childs = null
if (expand && hasChilds && reload) {
if (slotChilds.length) {
// childs = slotChilds
childs = slotChilds.map((vnode, i) => {
vnode.data.key = vnode.data.key || `${key}_${i}`
let ele = cloneVNode(vnode)
return ele;
})
} else {
childs = children.map((item, i) => {
const k = item.key || `${key}_${i}`
item.key = k
// console.log(k)
return <Node data={item} key={k} />
})
}
}
let onProps = getTranstionProp('k-tree-slide')
const itemProps = {
attrs: {},
class: ['k-tree-item', {
'k-tree-item-disabled': disabled,
'k-tree-item-drag': this.draged,
'k-tree-item-drop': this.droped && !disabled,
'k-tree-item-extra-hidden': !showExtra,
'k-tree-item-selected': directory && selected
}],
on: {},
style: {
paddingLeft: `${(this.level || 0) * 24}px`
}
}
if (directory) {
itemProps.on.click = this.handleSelect
}
let extraNode;
if (Tree.$scopedSlots.extra) {
let extra = Tree.$scopedSlots.extra({ node: this.defaultData, parent: this.getParent() })
extraNode = <span class='k-tree-item-extra'>{extra}</span>
}
childs && childs.unshift(<span class="k-tree-line" style={{ left: `${(this.level || 0) * 24 + 12}px` }} key="line"></span>)
return (
<div class="k-tree-children">
<div {...itemProps}>{itemNode}{extraNode}</div>
{
<transition-group class="k-tree-item-children" tag="div" {...onProps}>{childs}</transition-group>
}
</div>)
}
}