update the master branch to the latest

This commit is contained in:
梁灏 2019-08-27 09:42:40 +08:00
parent 67d534df27
commit 23a0ba9831
611 changed files with 122648 additions and 0 deletions

View file

@ -0,0 +1,2 @@
import Tree from './tree.vue';
export default Tree;

View file

@ -0,0 +1,220 @@
<template>
<collapse-transition :appear="appear">
<ul :class="classes">
<li>
<span :class="arrowClasses" @click="handleExpand">
<Icon v-if="showArrow" :type="arrowType" :custom="customArrowType" :size="arrowSize" />
<Icon v-if="showLoading" type="ios-loading" class="ivu-load-loop" />
</span>
<Checkbox
v-if="showCheckbox"
:value="data.checked"
:indeterminate="data.indeterminate"
:disabled="data.disabled || data.disableCheckbox"
@click.native.prevent="handleCheck"></Checkbox>
<Render v-if="data.render" :render="data.render" :data="data" :node="node"></Render>
<Render v-else-if="isParentRender" :render="parentRender" :data="data" :node="node"></Render>
<span v-else :class="titleClasses" @click="handleSelect">{{ data.title }}</span>
<Tree-node
v-if="data.expand"
:appear="appearByClickArrow"
v-for="(item, i) in children"
:key="i"
:data="item"
:multiple="multiple"
:show-checkbox="showCheckbox"
:children-key="childrenKey">
</Tree-node>
</li>
</ul>
</collapse-transition>
</template>
<script>
import Checkbox from '../checkbox/checkbox.vue';
import Icon from '../icon/icon.vue';
import Render from './render';
import CollapseTransition from '../base/collapse-transition';
import Emitter from '../../mixins/emitter';
import { findComponentUpward } from '../../utils/assist';
const prefixCls = 'ivu-tree';
export default {
name: 'TreeNode',
mixins: [ Emitter ],
inject: ['TreeInstance'],
components: { Checkbox, Icon, CollapseTransition, Render },
props: {
data: {
type: Object,
default () {
return {};
}
},
multiple: {
type: Boolean,
default: false
},
childrenKey: {
type: String,
default: 'children'
},
showCheckbox: {
type: Boolean,
default: false
},
appear: {
type: Boolean,
default: false
}
},
data () {
return {
prefixCls: prefixCls,
appearByClickArrow: false
};
},
computed: {
classes () {
return [
`${prefixCls}-children`
];
},
selectedCls () {
return [
{
[`${prefixCls}-node-selected`]: this.data.selected
}
];
},
arrowClasses () {
return [
`${prefixCls}-arrow`,
{
[`${prefixCls}-arrow-disabled`]: this.data.disabled,
[`${prefixCls}-arrow-open`]: this.data.expand
}
];
},
titleClasses () {
return [
`${prefixCls}-title`,
{
[`${prefixCls}-title-selected`]: this.data.selected
}
];
},
showArrow () {
return (this.data[this.childrenKey] && this.data[this.childrenKey].length) || ('loading' in this.data && !this.data.loading);
},
showLoading () {
return 'loading' in this.data && this.data.loading;
},
isParentRender () {
const Tree = findComponentUpward(this, 'Tree');
return Tree && Tree.render;
},
parentRender () {
const Tree = findComponentUpward(this, 'Tree');
if (Tree && Tree.render) {
return Tree.render;
} else {
return null;
}
},
node () {
const Tree = findComponentUpward(this, 'Tree');
if (Tree) {
// nodeflatState node
return [Tree.flatState, Tree.flatState.find(item => item.nodeKey === this.data.nodeKey)];
} else {
return [];
}
},
children () {
return this.data[this.childrenKey];
},
// 3.4.0, global setting customArrow arrow
arrowType () {
let type = 'ios-arrow-forward';
if (this.$IVIEW) {
if (this.$IVIEW.tree.customArrow) {
type = '';
} else if (this.$IVIEW.tree.arrow) {
type = this.$IVIEW.tree.arrow;
}
}
return type;
},
// 3.4.0, global setting
customArrowType () {
let type = '';
if (this.$IVIEW) {
if (this.$IVIEW.tree.customArrow) {
type = this.$IVIEW.tree.customArrow;
}
}
return type;
},
// 3.4.0, global setting
arrowSize () {
let size = '';
if (this.$IVIEW) {
if (this.$IVIEW.tree.arrowSize) {
size = this.$IVIEW.tree.arrowSize;
}
}
return size;
}
},
methods: {
handleExpand () {
const item = this.data;
if (item.disabled) return;
// Vue.js 2.6.9 transition appear iView appear appear false
this.appearByClickArrow = true;
// async loading
if (item[this.childrenKey].length === 0) {
const tree = findComponentUpward(this, 'Tree');
if (tree && tree.loadData) {
this.$set(this.data, 'loading', true);
tree.loadData(item, children => {
this.$set(this.data, 'loading', false);
if (children.length) {
this.$set(this.data, this.childrenKey, children);
this.$nextTick(() => this.handleExpand());
}
});
return;
}
}
if (item[this.childrenKey] && item[this.childrenKey].length) {
this.$set(this.data, 'expand', !this.data.expand);
this.dispatch('Tree', 'toggle-expand', this.data);
}
},
handleSelect () {
if (this.data.disabled) return;
if (this.TreeInstance.showCheckbox && this.TreeInstance.checkDirectly) {
this.handleCheck();
} else {
this.dispatch('Tree', 'on-selected', this.data.nodeKey);
}
},
handleCheck () {
if (this.data.disabled) return;
const changes = {
checked: !this.data.checked && !this.data.indeterminate,
nodeKey: this.data.nodeKey
};
this.dispatch('Tree', 'on-check', changes);
}
}
};
</script>

View file

@ -0,0 +1,17 @@
export default {
name: 'RenderCell',
functional: true,
props: {
render: Function,
data: Object,
node: Array
},
render: (h, ctx) => {
const params = {
root: ctx.props.node[0],
node: ctx.props.node[1],
data: ctx.props.data
};
return ctx.props.render(h, params);
}
};

View file

@ -0,0 +1,204 @@
<template>
<div :class="prefixCls">
<Tree-node
v-for="(item, i) in stateTree"
:key="i"
:data="item"
visible
:multiple="multiple"
:show-checkbox="showCheckbox"
:children-key="childrenKey">
</Tree-node>
<div :class="[prefixCls + '-empty']" v-if="!stateTree.length">{{ localeEmptyText }}</div>
</div>
</template>
<script>
import TreeNode from './node.vue';
import Emitter from '../../mixins/emitter';
import Locale from '../../mixins/locale';
const prefixCls = 'ivu-tree';
export default {
name: 'Tree',
mixins: [ Emitter, Locale ],
components: { TreeNode },
provide () {
return { TreeInstance: this };
},
props: {
data: {
type: Array,
default () {
return [];
}
},
multiple: {
type: Boolean,
default: false
},
showCheckbox: {
type: Boolean,
default: false
},
checkStrictly: {
type: Boolean,
default: false
},
// showCheckbox checkDirectlyselect check
checkDirectly: {
type: Boolean,
default: false
},
emptyText: {
type: String
},
childrenKey: {
type: String,
default: 'children'
},
loadData: {
type: Function
},
render: {
type: Function
},
},
data () {
return {
prefixCls: prefixCls,
stateTree: this.data,
flatState: [],
};
},
watch: {
data: {
deep: true,
handler () {
this.stateTree = this.data;
this.flatState = this.compileFlatState();
this.rebuildTree();
}
}
},
computed: {
localeEmptyText () {
if (typeof this.emptyText === 'undefined') {
return this.t('i.tree.emptyText');
} else {
return this.emptyText;
}
},
},
methods: {
compileFlatState () { // so we have always a relation parent/children of each node
let keyCounter = 0;
let childrenKey = this.childrenKey;
const flatTree = [];
function flattenChildren(node, parent) {
node.nodeKey = keyCounter++;
flatTree[node.nodeKey] = { node: node, nodeKey: node.nodeKey };
if (typeof parent != 'undefined') {
flatTree[node.nodeKey].parent = parent.nodeKey;
flatTree[parent.nodeKey][childrenKey].push(node.nodeKey);
}
if (node[childrenKey]) {
flatTree[node.nodeKey][childrenKey] = [];
node[childrenKey].forEach(child => flattenChildren(child, node));
}
}
this.stateTree.forEach(rootNode => {
flattenChildren(rootNode);
});
return flatTree;
},
updateTreeUp(nodeKey){
const parentKey = this.flatState[nodeKey].parent;
if (typeof parentKey == 'undefined' || this.checkStrictly) return;
const node = this.flatState[nodeKey].node;
const parent = this.flatState[parentKey].node;
if (node.checked == parent.checked && node.indeterminate == parent.indeterminate) return; // no need to update upwards
if (node.checked == true) {
this.$set(parent, 'checked', parent[this.childrenKey].every(node => node.checked));
this.$set(parent, 'indeterminate', !parent.checked);
} else {
this.$set(parent, 'checked', false);
this.$set(parent, 'indeterminate', parent[this.childrenKey].some(node => node.checked || node.indeterminate));
}
this.updateTreeUp(parentKey);
},
rebuildTree () { // only called when `data` prop changes
const checkedNodes = this.getCheckedNodes();
checkedNodes.forEach(node => {
this.updateTreeDown(node, {checked: true});
// propagate upwards
const parentKey = this.flatState[node.nodeKey].parent;
if (!parentKey && parentKey !== 0) return;
const parent = this.flatState[parentKey].node;
const childHasCheckSetter = typeof node.checked != 'undefined' && node.checked;
if (childHasCheckSetter && parent.checked != node.checked) {
this.updateTreeUp(node.nodeKey); // update tree upwards
}
});
},
getSelectedNodes () {
/* public API */
return this.flatState.filter(obj => obj.node.selected).map(obj => obj.node);
},
getCheckedNodes () {
/* public API */
return this.flatState.filter(obj => obj.node.checked).map(obj => obj.node);
},
getCheckedAndIndeterminateNodes () {
/* public API */
return this.flatState.filter(obj => (obj.node.checked || obj.node.indeterminate)).map(obj => obj.node);
},
updateTreeDown(node, changes = {}) {
if (this.checkStrictly) return;
for (let key in changes) {
this.$set(node, key, changes[key]);
}
if (node[this.childrenKey]) {
node[this.childrenKey].forEach(child => {
this.updateTreeDown(child, changes);
});
}
},
handleSelect (nodeKey) {
const node = this.flatState[nodeKey].node;
if (!this.multiple){ // reset previously selected node
const currentSelectedKey = this.flatState.findIndex(obj => obj.node.selected);
if (currentSelectedKey >= 0 && currentSelectedKey !== nodeKey) this.$set(this.flatState[currentSelectedKey].node, 'selected', false);
}
this.$set(node, 'selected', !node.selected);
this.$emit('on-select-change', this.getSelectedNodes(), node);
},
handleCheck({ checked, nodeKey }) {
const node = this.flatState[nodeKey].node;
this.$set(node, 'checked', checked);
this.$set(node, 'indeterminate', false);
this.updateTreeUp(nodeKey); // propagate up
this.updateTreeDown(node, {checked, indeterminate: false}); // reset `indeterminate` when going down
this.$emit('on-check-change', this.getCheckedNodes(), node);
}
},
created(){
this.flatState = this.compileFlatState();
this.rebuildTree();
},
mounted () {
this.$on('on-check', this.handleCheck);
this.$on('on-selected', this.handleSelect);
this.$on('toggle-expand', node => this.$emit('on-toggle-expand', node));
}
};
</script>