add vc-tree
parent
dc5482f9c9
commit
659aff5e57
|
@ -0,0 +1,72 @@
|
||||||
|
<script>
|
||||||
|
/* eslint no-console:0 */
|
||||||
|
import Tree, { TreeNode } from '../index'
|
||||||
|
import '../assets/index.less'
|
||||||
|
import cssAnimation from 'css-animation'
|
||||||
|
|
||||||
|
function animate (node, show, done) {
|
||||||
|
let height = node.offsetHeight
|
||||||
|
return cssAnimation(node, 'collapse', {
|
||||||
|
start () {
|
||||||
|
if (!show) {
|
||||||
|
node.style.height = `${node.offsetHeight}px`
|
||||||
|
} else {
|
||||||
|
height = node.offsetHeight
|
||||||
|
node.style.height = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
active () {
|
||||||
|
node.style.height = `${show ? height : 0}px`
|
||||||
|
},
|
||||||
|
end () {
|
||||||
|
node.style.height = ''
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const animation = {
|
||||||
|
enter (node, done) {
|
||||||
|
return animate(node, true, done)
|
||||||
|
},
|
||||||
|
leave (node, done) {
|
||||||
|
return animate(node, false, done)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>expanded</h2>
|
||||||
|
<Tree
|
||||||
|
defaultExpandAll={false}
|
||||||
|
defaultExpandedKeys={['p1']}
|
||||||
|
openAnimation={{ on: animation, props: { appear: true }}}
|
||||||
|
>
|
||||||
|
<TreeNode title='parent 1' key='p1'>
|
||||||
|
<TreeNode key='p10' title='leaf'/>
|
||||||
|
<TreeNode title='parent 1-1' key='p11'>
|
||||||
|
<TreeNode title='parent 2-1' key='p21'>
|
||||||
|
<TreeNode title='leaf'/>
|
||||||
|
<TreeNode title='leaf'/>
|
||||||
|
</TreeNode>
|
||||||
|
<TreeNode key='p22' title='leaf'/>
|
||||||
|
</TreeNode>
|
||||||
|
</TreeNode>
|
||||||
|
</Tree>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.collapse {
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-active {
|
||||||
|
transition: height 0.3s ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,173 @@
|
||||||
|
<script>
|
||||||
|
/* eslint no-console:0 */
|
||||||
|
import Tree, { TreeNode } from '../index'
|
||||||
|
import '../assets/index.less'
|
||||||
|
import { gData,
|
||||||
|
/* filterParentPosition, getFilterExpandedKeys,*/ getRadioSelectKeys } from './util'
|
||||||
|
import '../../vc-dialog/assets/index.less'
|
||||||
|
import Modal from '../../vc-dialog'
|
||||||
|
import BaseMixin from '../../_util/BaseMixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
// expandedKeys: getFilterExpandedKeys(gData, ['0-0-0-key']),
|
||||||
|
expandedKeys: ['0-0-0-key'],
|
||||||
|
autoExpandParent: true,
|
||||||
|
// checkedKeys: ['0-0-0-0-key', '0-0-1-0-key', '0-1-0-0-key'],
|
||||||
|
checkedKeys: ['0-0-0-key'],
|
||||||
|
checkStrictlyKeys: { checked: ['0-0-1-key'], halfChecked: [] },
|
||||||
|
selectedKeys: [],
|
||||||
|
treeData: [],
|
||||||
|
visible: false,
|
||||||
|
multiple: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onExpand (expandedKeys) {
|
||||||
|
console.log('onExpand', arguments)
|
||||||
|
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
|
||||||
|
// or, you can remove all expanded chilren keys.
|
||||||
|
this.setState({
|
||||||
|
expandedKeys,
|
||||||
|
autoExpandParent: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCheck (checkedKeys) {
|
||||||
|
this.setState({
|
||||||
|
checkedKeys,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCheckStrictly (checkedKeys, /* extra*/) {
|
||||||
|
console.log(arguments)
|
||||||
|
// const { checkedNodesPositions } = extra;
|
||||||
|
// const pps = filterParentPosition(checkedNodesPositions.map(i => i.pos));
|
||||||
|
// console.log(checkedNodesPositions.filter(i => pps.indexOf(i.pos) > -1).map(i => i.node.key));
|
||||||
|
const cks = {
|
||||||
|
checked: checkedKeys.checked || checkedKeys,
|
||||||
|
halfChecked: [`0-0-${parseInt(Math.random() * 3, 10)}-key`],
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
// checkedKeys,
|
||||||
|
checkStrictlyKeys: cks,
|
||||||
|
// checkStrictlyKeys: checkedKeys,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSelect (selectedKeys, info) {
|
||||||
|
console.log('onSelect', selectedKeys, info)
|
||||||
|
this.setState({
|
||||||
|
selectedKeys,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRbSelect (selectedKeys, info) {
|
||||||
|
let _selectedKeys = selectedKeys
|
||||||
|
if (info.selected) {
|
||||||
|
_selectedKeys = getRadioSelectKeys(gData, selectedKeys, info.node.props.eventKey)
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selectedKeys: _selectedKeys,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onClose () {
|
||||||
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleOk () {
|
||||||
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showModal () {
|
||||||
|
this.setState({
|
||||||
|
expandedKeys: ['0-0-0-key', '0-0-1-key'],
|
||||||
|
checkedKeys: ['0-0-0-key'],
|
||||||
|
visible: true,
|
||||||
|
})
|
||||||
|
// simulate Ajax
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setState({
|
||||||
|
treeData: [...gData],
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
},
|
||||||
|
triggerChecked () {
|
||||||
|
this.setState({
|
||||||
|
checkedKeys: [`0-0-${parseInt(Math.random() * 3, 10)}-key`],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const loop = data => {
|
||||||
|
return data.map((item) => {
|
||||||
|
if (item.children) {
|
||||||
|
return (
|
||||||
|
<TreeNode
|
||||||
|
key={item.key} title={item.title}
|
||||||
|
disableCheckbox={item.key === '0-0-0-key'}
|
||||||
|
>
|
||||||
|
{loop(item.children)}
|
||||||
|
</TreeNode>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <TreeNode key={item.key} title={item.title} />
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// console.log(getRadioSelectKeys(gData, this.selectedKeys));
|
||||||
|
return (<div style={{ padding: '0 20px' }}>
|
||||||
|
<h2>dialog</h2>
|
||||||
|
<button class='btn btn-primary' onClick={this.showModal}>show dialog</button>
|
||||||
|
<Modal
|
||||||
|
title='TestDemo' visible={this.visible}
|
||||||
|
onOk={this.handleOk} onClose={this.onClose}
|
||||||
|
>
|
||||||
|
{this.treeData.length ? (
|
||||||
|
<Tree
|
||||||
|
checkable class='dialog-tree'
|
||||||
|
onExpand={this.onExpand} expandedKeys={this.expandedKeys}
|
||||||
|
autoExpandParent={this.autoExpandParent}
|
||||||
|
onCheck={this.onCheck} checkedKeys={this.checkedKeys}
|
||||||
|
>
|
||||||
|
{loop(this.treeData)}
|
||||||
|
</Tree>
|
||||||
|
) : 'loading...'}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<h2>controlled</h2>
|
||||||
|
<Tree
|
||||||
|
checkable
|
||||||
|
onExpand={this.onExpand} expandedKeys={this.expandedKeys}
|
||||||
|
autoExpandParent={this.autoExpandParent}
|
||||||
|
onCheck={this.onCheck} checkedKeys={this.checkedKeys}
|
||||||
|
onSelect={this.onSelect} selectedKeys={this.selectedKeys}
|
||||||
|
>
|
||||||
|
{loop(gData)}
|
||||||
|
</Tree>
|
||||||
|
<button onClick={this.triggerChecked}>trigger checked</button>
|
||||||
|
|
||||||
|
<h2>checkStrictly</h2>
|
||||||
|
<Tree
|
||||||
|
checkable multiple={this.multiple} defaultExpandAll
|
||||||
|
onExpand={this.onExpand} expandedKeys={this.expandedKeys}
|
||||||
|
onCheck={this.onCheckStrictly}
|
||||||
|
checkedKeys={this.checkStrictlyKeys}
|
||||||
|
|
||||||
|
>
|
||||||
|
{loop(gData)}
|
||||||
|
</Tree>
|
||||||
|
|
||||||
|
<h2>radio's behavior select (in the same level)</h2>
|
||||||
|
<Tree
|
||||||
|
multiple defaultExpandAll
|
||||||
|
onSelect={this.onRbSelect}
|
||||||
|
selectedKeys={getRadioSelectKeys(gData, this.selectedKeys) }
|
||||||
|
>
|
||||||
|
{loop(gData)}
|
||||||
|
</Tree>
|
||||||
|
</div>)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -16,7 +16,6 @@ export default {
|
||||||
defaultSelectedKeys: keys,
|
defaultSelectedKeys: keys,
|
||||||
defaultCheckedKeys: keys,
|
defaultCheckedKeys: keys,
|
||||||
switchIt: true,
|
switchIt: true,
|
||||||
showMore: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -55,7 +54,7 @@ export default {
|
||||||
</span>)
|
</span>)
|
||||||
return (<div style={{ margin: '0 20px' }}>
|
return (<div style={{ margin: '0 20px' }}>
|
||||||
<h2>simple</h2>
|
<h2>simple</h2>
|
||||||
{/* <Tree
|
<Tree
|
||||||
class='myCls' showLine checkable defaultExpandAll
|
class='myCls' showLine checkable defaultExpandAll
|
||||||
defaultExpandedKeys={this.defaultExpandedKeys}
|
defaultExpandedKeys={this.defaultExpandedKeys}
|
||||||
onExpand={this.onExpand}
|
onExpand={this.onExpand}
|
||||||
|
@ -77,10 +76,9 @@ export default {
|
||||||
<TreeNode title='parent 1-2-1' key='0-0-2-1' />
|
<TreeNode title='parent 1-2-1' key='0-0-2-1' />
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
</Tree> */}
|
</Tree>
|
||||||
|
|
||||||
<h2>Check on Click TreeNode</h2>
|
<h2>Check on Click TreeNode</h2>
|
||||||
<button onClick={this.toggleChildren}>toggle children</button>
|
|
||||||
<Tree
|
<Tree
|
||||||
class='myCls'
|
class='myCls'
|
||||||
showLine
|
showLine
|
||||||
|
@ -98,10 +96,6 @@ export default {
|
||||||
<TreeNode title='parent 1-1-0' key='0-0-1-0' disableCheckbox />
|
<TreeNode title='parent 1-1-0' key='0-0-1-0' disableCheckbox />
|
||||||
<TreeNode title='parent 1-1-1' key='0-0-1-1' />
|
<TreeNode title='parent 1-1-1' key='0-0-1-1' />
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
{this.showMore ? <TreeNode title='parent 2-1' key='0-0-2'>
|
|
||||||
<TreeNode title='parent 2-1-0' key='0-0-2-0' disableCheckbox />
|
|
||||||
<TreeNode title='parent 2-1-1' key='0-0-2-1' />
|
|
||||||
</TreeNode> : null}
|
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
</Tree>
|
</Tree>
|
||||||
</div>)
|
</div>)
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* eslint no-loop-func: 0*/
|
||||||
|
/* eslint no-console:0 */
|
||||||
|
|
||||||
|
export function generateData (x = 3, y = 2, z = 1, gData = []) {
|
||||||
|
// x:每一级下的节点总数。y:每级节点里有y个节点、存在子节点。z:树的level层级数(0表示一级)
|
||||||
|
function _loop (_level, _preKey, _tns) {
|
||||||
|
const preKey = _preKey || '0'
|
||||||
|
const tns = _tns || gData
|
||||||
|
|
||||||
|
const children = []
|
||||||
|
for (let i = 0; i < x; i++) {
|
||||||
|
const key = `${preKey}-${i}`
|
||||||
|
tns.push({ title: `${key}-label`, key: `${key}-key` })
|
||||||
|
if (i < y) {
|
||||||
|
children.push(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_level < 0) {
|
||||||
|
return tns
|
||||||
|
}
|
||||||
|
const __level = _level - 1
|
||||||
|
children.forEach((key, index) => {
|
||||||
|
tns[index].children = []
|
||||||
|
return _loop(__level, key, tns[index].children)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_loop(z)
|
||||||
|
return gData
|
||||||
|
}
|
||||||
|
export function calcTotal (x = 3, y = 2, z = 1) {
|
||||||
|
/* eslint no-param-reassign:0*/
|
||||||
|
const rec = (n) => n >= 0 ? x * Math.pow(y, n--) + rec(n) : 0
|
||||||
|
return rec(z + 1)
|
||||||
|
}
|
||||||
|
console.log('总节点数(单个tree):', calcTotal())
|
||||||
|
// 性能测试:总节点数超过 2000(z要小)明显感觉慢。z 变大时,递归多,会卡死。
|
||||||
|
|
||||||
|
export const gData = generateData()
|
||||||
|
|
||||||
|
function isPositionPrefix (smallPos, bigPos) {
|
||||||
|
if (bigPos.length < smallPos.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// attention: "0-0-1" "0-0-10"
|
||||||
|
if ((bigPos.length > smallPos.length) && (bigPos.charAt(smallPos.length) !== '-')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bigPos.substr(0, smallPos.length) === smallPos
|
||||||
|
}
|
||||||
|
// console.log(isPositionPrefix("0-1", "0-10-1"));
|
||||||
|
|
||||||
|
// arr.length === 628, use time: ~20ms
|
||||||
|
export function filterParentPosition (arr) {
|
||||||
|
const levelObj = {}
|
||||||
|
arr.forEach((item) => {
|
||||||
|
const posLen = item.split('-').length
|
||||||
|
if (!levelObj[posLen]) {
|
||||||
|
levelObj[posLen] = []
|
||||||
|
}
|
||||||
|
levelObj[posLen].push(item)
|
||||||
|
})
|
||||||
|
const levelArr = Object.keys(levelObj).sort()
|
||||||
|
for (let i = 0; i < levelArr.length; i++) {
|
||||||
|
if (levelArr[i + 1]) {
|
||||||
|
levelObj[levelArr[i]].forEach(ii => {
|
||||||
|
for (let j = i + 1; j < levelArr.length; j++) {
|
||||||
|
levelObj[levelArr[j]].forEach((_i, index) => {
|
||||||
|
if (isPositionPrefix(ii, _i)) {
|
||||||
|
levelObj[levelArr[j]][index] = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
levelObj[levelArr[j]] = levelObj[levelArr[j]].filter(p => p)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let nArr = []
|
||||||
|
levelArr.forEach(i => {
|
||||||
|
nArr = nArr.concat(levelObj[i])
|
||||||
|
})
|
||||||
|
return nArr
|
||||||
|
}
|
||||||
|
// console.log(filterParentPosition(
|
||||||
|
// ['0-2', '0-3-3', '0-10', '0-10-0', '0-0-1', '0-0', '0-1-1', '0-1']
|
||||||
|
// ));
|
||||||
|
|
||||||
|
function loopData (data, callback) {
|
||||||
|
const loop = (d, level = 0) => {
|
||||||
|
d.forEach((item, index) => {
|
||||||
|
const pos = `${level}-${index}`
|
||||||
|
if (item.children) {
|
||||||
|
loop(item.children, pos)
|
||||||
|
}
|
||||||
|
callback(item, index, pos)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loop(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function spl (str) {
|
||||||
|
return str.split('-')
|
||||||
|
}
|
||||||
|
function splitLen (str) {
|
||||||
|
return str.split('-').length
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFilterExpandedKeys (data, expandedKeys) {
|
||||||
|
const expandedPosArr = []
|
||||||
|
loopData(data, (item, index, pos) => {
|
||||||
|
if (expandedKeys.indexOf(item.key) > -1) {
|
||||||
|
expandedPosArr.push(pos)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const filterExpandedKeys = []
|
||||||
|
loopData(data, (item, index, pos) => {
|
||||||
|
expandedPosArr.forEach(p => {
|
||||||
|
if ((splitLen(pos) < splitLen(p) &&
|
||||||
|
p.indexOf(pos) === 0 || pos === p) &&
|
||||||
|
filterExpandedKeys.indexOf(item.key) === -1) {
|
||||||
|
filterExpandedKeys.push(item.key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return filterExpandedKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSibling (pos, pos1) {
|
||||||
|
pos.pop()
|
||||||
|
pos1.pop()
|
||||||
|
return pos.join(',') === pos1.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRadioSelectKeys (data, selectedKeys, key) {
|
||||||
|
const res = []
|
||||||
|
const pkObjArr = []
|
||||||
|
const selPkObjArr = []
|
||||||
|
loopData(data, (item, index, pos) => {
|
||||||
|
if (selectedKeys.indexOf(item.key) > -1) {
|
||||||
|
pkObjArr.push([pos, item.key])
|
||||||
|
}
|
||||||
|
if (key && key === item.key) {
|
||||||
|
selPkObjArr.push(pos, item.key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const lenObj = {}
|
||||||
|
const getPosKey = (pos, k) => {
|
||||||
|
const posLen = splitLen(pos)
|
||||||
|
if (!lenObj[posLen]) {
|
||||||
|
lenObj[posLen] = [[pos, k]]
|
||||||
|
} else {
|
||||||
|
lenObj[posLen].forEach((pkArr, i) => {
|
||||||
|
if (isSibling(spl(pkArr[0]), spl(pos))) {
|
||||||
|
// 后来覆盖前者
|
||||||
|
lenObj[posLen][i] = [pos, k]
|
||||||
|
} else if (spl(pkArr[0]) !== spl(pos)) {
|
||||||
|
lenObj[posLen].push([pos, k])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkObjArr.forEach((pk) => {
|
||||||
|
getPosKey(pk[0], pk[1])
|
||||||
|
})
|
||||||
|
if (key) {
|
||||||
|
getPosKey(selPkObjArr[0], selPkObjArr[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(lenObj).forEach((item) => {
|
||||||
|
lenObj[item].forEach((i) => {
|
||||||
|
if (res.indexOf(i[1]) === -1) {
|
||||||
|
res.push(i[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ export const contextTypes = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
selectable: PropTypes.bool,
|
selectable: PropTypes.bool,
|
||||||
showIcon: PropTypes.bool,
|
showIcon: PropTypes.bool,
|
||||||
|
icon: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
draggable: PropTypes.bool,
|
draggable: PropTypes.bool,
|
||||||
checkable: PropTypes.oneOfType([
|
checkable: PropTypes.oneOfType([
|
||||||
PropTypes.bool,
|
PropTypes.bool,
|
||||||
|
@ -62,6 +63,7 @@ const Tree = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
showLine: PropTypes.bool,
|
showLine: PropTypes.bool,
|
||||||
showIcon: PropTypes.bool,
|
showIcon: PropTypes.bool,
|
||||||
|
icon: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||||
focusable: PropTypes.bool,
|
focusable: PropTypes.bool,
|
||||||
selectable: PropTypes.bool,
|
selectable: PropTypes.bool,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
|
@ -72,6 +74,7 @@ const Tree = {
|
||||||
]),
|
]),
|
||||||
checkStrictly: PropTypes.bool,
|
checkStrictly: PropTypes.bool,
|
||||||
draggable: PropTypes.bool,
|
draggable: PropTypes.bool,
|
||||||
|
defaultExpandParent: PropTypes.bool,
|
||||||
autoExpandParent: PropTypes.bool,
|
autoExpandParent: PropTypes.bool,
|
||||||
defaultExpandAll: PropTypes.bool,
|
defaultExpandAll: PropTypes.bool,
|
||||||
defaultExpandedKeys: PropTypes.arrayOf(PropTypes.string),
|
defaultExpandedKeys: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
@ -110,6 +113,7 @@ const Tree = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
checkStrictly: false,
|
checkStrictly: false,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
|
defaultExpandParent: true,
|
||||||
autoExpandParent: true,
|
autoExpandParent: true,
|
||||||
defaultExpandAll: false,
|
defaultExpandAll: false,
|
||||||
defaultExpandedKeys: [],
|
defaultExpandedKeys: [],
|
||||||
|
@ -123,15 +127,31 @@ const Tree = {
|
||||||
const props = getOptionProps(this)
|
const props = getOptionProps(this)
|
||||||
const {
|
const {
|
||||||
defaultExpandAll,
|
defaultExpandAll,
|
||||||
|
defaultExpandParent,
|
||||||
defaultExpandedKeys,
|
defaultExpandedKeys,
|
||||||
defaultCheckedKeys,
|
defaultCheckedKeys,
|
||||||
defaultSelectedKeys,
|
defaultSelectedKeys,
|
||||||
|
expandedKeys,
|
||||||
} = props
|
} = props
|
||||||
const children = this.$slots.default
|
const children = this.$slots.default
|
||||||
// Sync state with props
|
// Sync state with props
|
||||||
const { checkedKeys = [], halfCheckedKeys = [] } =
|
const { checkedKeys = [], halfCheckedKeys = [] } =
|
||||||
calcCheckedKeys(defaultCheckedKeys, props, children) || {}
|
calcCheckedKeys(defaultCheckedKeys, props, children) || {}
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
sSelectedKeys: calcSelectedKeys(defaultSelectedKeys, props),
|
||||||
|
sCheckedKeys: checkedKeys,
|
||||||
|
sHalfCheckedKeys: halfCheckedKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultExpandAll) {
|
||||||
|
state.sExpandedKeys = getFullKeyList(children)
|
||||||
|
} else if (defaultExpandParent) {
|
||||||
|
state.sExpandedKeys = calcExpandedKeys(expandedKeys || defaultExpandedKeys, props, children)
|
||||||
|
} else {
|
||||||
|
state.sExpandedKeys = defaultExpandedKeys
|
||||||
|
}
|
||||||
|
|
||||||
// Cache for check status to optimize
|
// Cache for check status to optimize
|
||||||
this.checkedBatch = null
|
this.checkedBatch = null
|
||||||
this.propsToStateMap = {
|
this.propsToStateMap = {
|
||||||
|
@ -141,13 +161,7 @@ const Tree = {
|
||||||
halfCheckedKeys: 'sHalfCheckedKeys',
|
halfCheckedKeys: 'sHalfCheckedKeys',
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
sExpandedKeys: defaultExpandAll
|
...state,
|
||||||
? getFullKeyList(children)
|
|
||||||
: calcExpandedKeys(defaultExpandedKeys, props, children),
|
|
||||||
sSelectedKeys: calcSelectedKeys(defaultSelectedKeys, props, children),
|
|
||||||
sCheckedKeys: checkedKeys,
|
|
||||||
sHalfCheckedKeys: halfCheckedKeys,
|
|
||||||
|
|
||||||
...(this.getSyncProps(props) || {}),
|
...(this.getSyncProps(props) || {}),
|
||||||
dragOverNodeKey: '',
|
dragOverNodeKey: '',
|
||||||
dropPosition: null,
|
dropPosition: null,
|
||||||
|
@ -161,18 +175,21 @@ const Tree = {
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
children (val) {
|
children (val) {
|
||||||
const { checkedKeys = [], halfCheckedKeys = [] } = calcCheckedKeys(this.checkedKeys || this.sCheckedKeys, this.$props, this.$slots.default) || {}
|
const { checkedKeys = [], halfCheckedKeys = [] } = calcCheckedKeys(this.checkedKeys || this.sCheckedKeys, this.$props, val) || {}
|
||||||
this.sCheckedKeys = checkedKeys
|
this.sCheckedKeys = checkedKeys
|
||||||
this.sHalfCheckedKeys = halfCheckedKeys
|
this.sHalfCheckedKeys = halfCheckedKeys
|
||||||
},
|
},
|
||||||
|
autoExpandParent (val) {
|
||||||
|
this.sExpandedKeys = val ? calcExpandedKeys(this.expandedKeys, this.$props, this.$slots.default) : this.expandedKeys
|
||||||
|
},
|
||||||
expandedKeys (val) {
|
expandedKeys (val) {
|
||||||
this.sExpandedKeys = calcExpandedKeys(this.expandedKeys, this.$props, this.$slots.default)
|
this.sExpandedKeys = this.autoExpandParent ? calcExpandedKeys(val, this.$props, this.$slots.default) : val
|
||||||
},
|
},
|
||||||
selectedKeys (val) {
|
selectedKeys (val) {
|
||||||
this.sSelectedKeys = calcSelectedKeys(this.selectedKeys, this.$props, this.$slots.default)
|
this.sSelectedKeys = calcSelectedKeys(val, this.$props, this.$slots.default)
|
||||||
},
|
},
|
||||||
checkedKeys (val) {
|
checkedKeys (val) {
|
||||||
const { checkedKeys = [], halfCheckedKeys = [] } = calcCheckedKeys(this.checkedKeys, this.$props, this.$slots.default) || {}
|
const { checkedKeys = [], halfCheckedKeys = [] } = calcCheckedKeys(val, this.$props, this.$slots.default) || {}
|
||||||
this.sCheckedKeys = checkedKeys
|
this.sCheckedKeys = checkedKeys
|
||||||
this.sHalfCheckedKeys = halfCheckedKeys
|
this.sHalfCheckedKeys = halfCheckedKeys
|
||||||
},
|
},
|
||||||
|
@ -251,6 +268,18 @@ const Tree = {
|
||||||
}, 0)
|
}, 0)
|
||||||
},
|
},
|
||||||
onNodeDragOver (event, node) {
|
onNodeDragOver (event, node) {
|
||||||
|
const { eventKey } = node.props
|
||||||
|
|
||||||
|
// Update drag position
|
||||||
|
if (this.dragNode && eventKey === this.dragOverNodeKey) {
|
||||||
|
const dropPosition = calcDropPosition(event, node)
|
||||||
|
|
||||||
|
if (dropPosition === this.dropPosition) return
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
dropPosition,
|
||||||
|
})
|
||||||
|
}
|
||||||
this.__emit('dragover', { event, node })
|
this.__emit('dragover', { event, node })
|
||||||
},
|
},
|
||||||
onNodeDragLeave (event, node) {
|
onNodeDragLeave (event, node) {
|
||||||
|
@ -502,8 +531,10 @@ const Tree = {
|
||||||
newState.sHalfCheckedKeys = halfCheckedKeys
|
newState.sHalfCheckedKeys = halfCheckedKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkSync('expandedKeys')) {
|
// Re-calculate when autoExpandParent or expandedKeys changed
|
||||||
newState.sExpandedKeys = calcExpandedKeys(props.expandedKeys, props, children)
|
if (prevProps && (checkSync('autoExpandParent') || checkSync('expandedKeys'))) {
|
||||||
|
newState.sExpandedKeys = props.autoExpandParent
|
||||||
|
? calcExpandedKeys(props.expandedKeys, props, children) : props.expandedKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkSync('selectedKeys')) {
|
if (checkSync('selectedKeys')) {
|
||||||
|
|
|
@ -65,10 +65,10 @@ const TreeNode = {
|
||||||
},
|
},
|
||||||
inject: {
|
inject: {
|
||||||
vcTree: { default: {}},
|
vcTree: { default: {}},
|
||||||
|
vcTreeNode: { default: {}},
|
||||||
},
|
},
|
||||||
provide () {
|
provide () {
|
||||||
return {
|
return {
|
||||||
vcTree: this.vcTree,
|
|
||||||
vcTreeNode: this,
|
vcTreeNode: this,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -358,19 +358,37 @@ const TreeNode = {
|
||||||
|
|
||||||
// Load data to avoid default expanded tree without data
|
// Load data to avoid default expanded tree without data
|
||||||
syncLoadData (props) {
|
syncLoadData (props) {
|
||||||
const { loadStatus } = this
|
const { expanded } = this
|
||||||
const { expanded } = props
|
|
||||||
const { vcTree: { loadData }} = this
|
const { vcTree: { loadData }} = this
|
||||||
|
|
||||||
if (loadData && loadStatus === LOAD_STATUS_NONE && expanded && !this.isLeaf2()) {
|
// read from state to avoid loadData at same time
|
||||||
this.setState({ loadStatus: LOAD_STATUS_LOADING })
|
this.setState(({ loadStatus }) => {
|
||||||
|
if (loadData && loadStatus === LOAD_STATUS_NONE && expanded && !this.isLeaf()) {
|
||||||
|
loadData(this).then(() => {
|
||||||
|
this.setState({ loadStatus: LOAD_STATUS_LOADED })
|
||||||
|
}).catch(() => {
|
||||||
|
this.setState({ loadStatus: LOAD_STATUS_FAILED })
|
||||||
|
})
|
||||||
|
|
||||||
loadData(this).then(() => {
|
return { loadStatus: LOAD_STATUS_LOADING }
|
||||||
this.setState({ loadStatus: LOAD_STATUS_LOADED })
|
}
|
||||||
}).catch(() => {
|
|
||||||
this.setState({ loadStatus: LOAD_STATUS_FAILED })
|
return null
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
// const { loadStatus } = this
|
||||||
|
// const { expanded } = props
|
||||||
|
// const { vcTree: { loadData }} = this
|
||||||
|
|
||||||
|
// if (loadData && loadStatus === LOAD_STATUS_NONE && expanded && !this.isLeaf2()) {
|
||||||
|
// this.setState({ loadStatus: LOAD_STATUS_LOADING })
|
||||||
|
|
||||||
|
// loadData(this).then(() => {
|
||||||
|
// this.setState({ loadStatus: LOAD_STATUS_LOADED })
|
||||||
|
// }).catch(() => {
|
||||||
|
// this.setState({ loadStatus: LOAD_STATUS_FAILED })
|
||||||
|
// })
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
// Switcher
|
// Switcher
|
||||||
|
@ -437,7 +455,7 @@ const TreeNode = {
|
||||||
// Icon + Title
|
// Icon + Title
|
||||||
renderSelector () {
|
renderSelector () {
|
||||||
const { title, selected, icon, loadStatus, dragNodeHighlight } = this
|
const { title, selected, icon, loadStatus, dragNodeHighlight } = this
|
||||||
const { vcTree: { prefixCls, showIcon, draggable, loadData }} = this
|
const { vcTree: { prefixCls, showIcon, icon: treeIcon, draggable, loadData }} = this
|
||||||
const disabled = this.isDisabled()
|
const disabled = this.isDisabled()
|
||||||
|
|
||||||
const wrapClass = `${prefixCls}-node-content-wrapper`
|
const wrapClass = `${prefixCls}-node-content-wrapper`
|
||||||
|
@ -446,15 +464,18 @@ const TreeNode = {
|
||||||
let $icon
|
let $icon
|
||||||
|
|
||||||
if (showIcon) {
|
if (showIcon) {
|
||||||
$icon = icon ? (
|
const currentIcon = icon || treeIcon
|
||||||
|
$icon = currentIcon ? (
|
||||||
<span
|
<span
|
||||||
class={classNames(
|
class={classNames(
|
||||||
`${prefixCls}-iconEle`,
|
`${prefixCls}-iconEle`,
|
||||||
`${prefixCls}-icon__customize`,
|
`${prefixCls}-icon__customize`,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{typeof icon === 'function'
|
{typeof currentIcon === 'function'
|
||||||
? icon(this.$props) : icon}
|
? currentIcon(
|
||||||
|
{ props: this.$props, on: this.$listeners }
|
||||||
|
) : currentIcon}
|
||||||
</span>
|
</span>
|
||||||
) : this.renderIcon()
|
) : this.renderIcon()
|
||||||
} else if (loadData && loadStatus === LOAD_STATUS_LOADING) {
|
} else if (loadData && loadStatus === LOAD_STATUS_LOADING) {
|
||||||
|
@ -510,6 +531,7 @@ const TreeNode = {
|
||||||
animProps = getTransitionProps(openTransitionName, { appear: transitionAppear })
|
animProps = getTransitionProps(openTransitionName, { appear: transitionAppear })
|
||||||
} else if (typeof openAnimation === 'object') {
|
} else if (typeof openAnimation === 'object') {
|
||||||
animProps = { ...openAnimation }
|
animProps = { ...openAnimation }
|
||||||
|
animProps.props = { css: false, ...animProps.props }
|
||||||
if (!transitionAppear) {
|
if (!transitionAppear) {
|
||||||
delete animProps.props.appear
|
delete animProps.props.appear
|
||||||
}
|
}
|
||||||
|
@ -526,7 +548,6 @@ const TreeNode = {
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
$children = (
|
$children = (
|
||||||
<ul
|
<ul
|
||||||
v-show={expanded}
|
|
||||||
class={classNames(
|
class={classNames(
|
||||||
`${prefixCls}-child-tree`,
|
`${prefixCls}-child-tree`,
|
||||||
expanded && `${prefixCls}-child-tree-open`,
|
expanded && `${prefixCls}-child-tree-open`,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* eslint no-loop-func: 0*/
|
/* eslint no-loop-func: 0*/
|
||||||
import warning from 'warning'
|
import warning from 'warning'
|
||||||
import { getSlotOptions, getOptionProps } from '../../_util/props-util'
|
import { getSlotOptions, getOptionProps } from '../../_util/props-util'
|
||||||
|
const DRAG_SIDE_RANGE = 0.25
|
||||||
|
const DRAG_MIN_GAP = 2
|
||||||
|
|
||||||
export function arrDel (list, value) {
|
export function arrDel (list, value) {
|
||||||
const clone = list.slice()
|
const clone = list.slice()
|
||||||
|
@ -23,27 +25,6 @@ export function posToArr (pos) {
|
||||||
return pos.split('-')
|
return pos.split('-')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only used when drag, not affect SSR.
|
|
||||||
export function getOffset (ele) {
|
|
||||||
if (!ele.getClientRects().length) {
|
|
||||||
return { top: 0, left: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
const rect = ele.getBoundingClientRect()
|
|
||||||
if (rect.width || rect.height) {
|
|
||||||
const doc = ele.ownerDocument
|
|
||||||
const win = doc.defaultView
|
|
||||||
const docElem = doc.documentElement
|
|
||||||
|
|
||||||
return {
|
|
||||||
top: rect.top + win.pageYOffset - docElem.clientTop,
|
|
||||||
left: rect.left + win.pageXOffset - docElem.clientLeft,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rect
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPosition (level, index) {
|
export function getPosition (level, index) {
|
||||||
return `${level}-${index}`
|
return `${level}-${index}`
|
||||||
}
|
}
|
||||||
|
@ -194,15 +175,14 @@ export function getDragNodesKeys (treeNodes, node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calcDropPosition (event, treeNode) {
|
export function calcDropPosition (event, treeNode) {
|
||||||
const offsetTop = getOffset(treeNode.selectHandle).top
|
const { clientY } = event
|
||||||
const offsetHeight = treeNode.selectHandle.offsetHeight
|
const { top, bottom, height } = treeNode.selectHandle.getBoundingClientRect()
|
||||||
const pageY = event.pageY
|
const des = Math.max(height * DRAG_SIDE_RANGE, DRAG_MIN_GAP)
|
||||||
const gapHeight = 2 // [Legacy] TODO: remove hard code
|
|
||||||
if (pageY > offsetTop + offsetHeight - gapHeight) {
|
if (clientY <= top + des) {
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if (pageY < offsetTop + gapHeight) {
|
|
||||||
return -1
|
return -1
|
||||||
|
} else if (clientY >= bottom - des) {
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -218,13 +198,6 @@ export function calcExpandedKeys (keyList, props, children = []) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const { autoExpandParent } = props
|
|
||||||
|
|
||||||
// Do nothing if not auto expand parent
|
|
||||||
if (!autoExpandParent) {
|
|
||||||
return keyList
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill parent expanded keys
|
// Fill parent expanded keys
|
||||||
const { keyNodes, nodeList } = getNodesStatistic(children)
|
const { keyNodes, nodeList } = getNodesStatistic(children)
|
||||||
const needExpandKeys = {}
|
const needExpandKeys = {}
|
||||||
|
@ -330,10 +303,11 @@ export function calcCheckStateConduct (treeNodes, checkedKeys) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { subNodes = [], parentPos, node } = keyNodes[key]
|
const { subNodes = [], parentPos, node } = keyNodes[key]
|
||||||
if (isCheckDisabled(node)) return
|
|
||||||
|
|
||||||
tgtCheckedKeys[key] = true
|
tgtCheckedKeys[key] = true
|
||||||
|
|
||||||
|
if (isCheckDisabled(node)) return
|
||||||
|
|
||||||
// Conduct down
|
// Conduct down
|
||||||
subNodes
|
subNodes
|
||||||
.filter(sub => !isCheckDisabled(sub.node))
|
.filter(sub => !isCheckDisabled(sub.node))
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Layout from './components/layout.vue'
|
||||||
const AsyncTestComp = () => {
|
const AsyncTestComp = () => {
|
||||||
const d = window.location.hash.replace('#', '')
|
const d = window.location.hash.replace('#', '')
|
||||||
return {
|
return {
|
||||||
component: import(`../components/transfer/demo/${d}`),
|
component: import(`../components/vc-tree/demo/${d}`),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue