import {
Component,
Input,
OnInit,
Output,
EventEmitter,
OnChanges,
SimpleChanges,
ViewChild,
ViewContainerRef,
ComponentFactoryResolver, ElementRef
} from '@angular/core';
import {Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError, RoutesRecognized} from '@angular/router';
import * as _ from 'lodash';
@Component({
selector: 'dc-tree',
template: `
`,
styles: [`
.tree-box {
position: relative;
overflow-y: auto;
padding: 5px 0;
min-height: 100%;
}
`]
})
export class TreeComponent implements OnInit {
@ViewChild('treeBox') treeBox: ElementRef;
@Output() clickEvent = new EventEmitter();
@Output() extendEvent = new EventEmitter();
@Output() checkEvent = new EventEmitter();
@Input() options: any;
@Input() isOpen: boolean;
@Input() folderClick: boolean;
@Input() checkNoParents: boolean;
@Input() checkNoChildren: boolean;
@Input() defaultCheckedNodes: any[];
@Input() defaultSelectedNode: any;
@Input() defaultHalfCheckedNodes: any[];
treeNoData = false;
tempSearch: any = [];
selectedNode: any;
@Input() keyId: any;
@Input() keyName: any;
@Input() keyChild: any;
@Input() treeId: string;
_treeDatas: any;
@Input() set treeDatas(v) {
if (this.defaultCheckedNodes && !_.isEmpty(this.defaultCheckedNodes)) {
this.initCheckNodes(this.defaultCheckedNodes, v);
this.defaultCheckedNodes = null;
}
if (this.defaultSelectedNode && !_.isEmpty(this.defaultSelectedNode)) {
let selectNode = this.initSelectNode(this.defaultSelectedNode, v);
this.selectedNode = selectNode;
this.defaultSelectedNode = null;
}
if (this.defaultHalfCheckedNodes && !_.isEmpty(this.defaultHalfCheckedNodes)) {
this.initHalfCheckNodes(this.defaultHalfCheckedNodes, v);
this.defaultHalfCheckedNodes = null;
}
this._treeDatas = v;
}
get treeDatas() {
return this._treeDatas;
}
constructor(private resolver: ComponentFactoryResolver, private router: Router) {
}
ngOnInit(): void {
if (!this.keyId) {
this.keyId = 'id';
}
if (!this.keyName) {
this.keyName = 'title';
}
if (!this.keyChild) {
this.keyChild = 'subNode';
}
}
initHalfCheckNodes(checkedNodes: any[], source: any) {
for (let i = checkedNodes.length - 1; i >= 0; i--) {
this._initHalfCheckNodes(checkedNodes[i], source);
}
}
_initHalfCheckNodes(checkedNode: any, source: any) {
for (let j = 0; j < source.length; j++) {
if (source[j][this.keyId] == checkedNode) {
source[j].checked = 2;
return;
}
if (source[j][this.keyChild] && source[j][this.keyChild].length > 0) {
this._initHalfCheckNodes(checkedNode, source[j][this.keyChild]);
}
}
}
initCheckNodes(checkedNodes: any[], source: any) {
for (let i = checkedNodes.length - 1; i >= 0; i--) {
this._initCheckNodes(checkedNodes[i], source);
}
}
_initCheckNodes(checkedNode: any, source: any) {
for (let j = 0; j < source.length; j++) {
if (source[j][this.keyId] == checkedNode) {
source[j].checked = 1;
return;
}
if (source[j][this.keyChild] && source[j][this.keyChild].length > 0) {
this._initCheckNodes(checkedNode, source[j][this.keyChild]);
}
}
}
initSelectNode(selectNode: any, source: any): any {
for (let j = 0; j < source.length; j++) {
if (source[j][this.keyId] == selectNode[this.keyId]) {
source[j].selected = true;
return source[j];
}
if (source[j][this.keyChild] && source[j][this.keyChild].length > 0) {
let res: any = this.initSelectNode(selectNode, source[j][this.keyChild]);
if (res) {
return res;
}
}
}
}
clickNode(event: any) {
this.selectTreeNode(event);
setTimeout(() => {
this.defaultSelectedNode = null;
}, 10);
if (this.options.unSelect && !event.selected) {
this.clickEvent.emit(null);
} else {
this.clickEvent.emit(event);
}
}
extendNode(event: any) {
this.extendEvent.emit(event);
}
checkNode(event: any) {
if (this.options && this.options.unLinkage) {
this.checkEvent.emit(event);
return false;
}
const childs = event[this.keyChild];
const parents = this.findParentsNodeById(event[this.keyId]);
if (event.checked) {
/**
* 复选框选中该节点
* 1/所有子节点选中
* 2/父节点判断
* 2.1/父节点为false
* 2.1.1/父节点下的所有兄弟节点全部checked > 父节点为true(继续判断父)
*/
if (!this.checkNoChildren) {
childs && this._checkChildrenNode(childs, true);
this._checkParentNode(parents);
}
} else {
/**
* 复选框移除该选中状态
* 1/所有子节点移除选中状态
* 2/父节点判断
* 2.1/父节点为true
* 2.1.1/父节点改为false(继续判断父)
* 2.2/父节点为false
* 2.2.1/不做处理
*/
if (!this.checkNoChildren) {
childs && this._checkChildrenNode(childs, false);
this._unCheckParentNode(parents);
}
}
this.checkEvent.emit(event);
}
// 移除父节点选中状态
private _unCheckParentNode(parents: any[]) {
if (parents.length > 1) { // 非根节点
let parent = parents[1];
if (parent.checked) {
let brothers = parent[this.keyChild];
let broChecked = false;
for (let bro of brothers) {
if (bro.checked === 1 || bro.checked === true || bro.checked === 2) {
broChecked = true;
break;
}
}
if (broChecked) {
parent.checked = 2;
} else {
parent.checked = 0;
}
this._unCheckParentNode(parents.slice(1, parents.length));
}
}
}
// 判断父节点状态并确认是否选中
private _checkParentNode(parents: any[]) {
if (parents.length > 1) { // 非根节点
let parent = parents[1];
let brothers = parent[this.keyChild];
let flag = true; // 兄弟节点有一个没有选中,则为false
let broChecked = false; // 兄弟节点是否有选中的
let half = false;
for (let bro of brothers) {
if (bro.checked === undefined || bro.checked === false || bro.checked === 2) {
if (bro.checked === 2) {
half = true;
}
flag = false;
} else {
broChecked = true;
}
}
if (!this.checkNoParents) {
if (flag) {
parents[1].checked = 1;
this._checkParentNode(parents.splice(1, parents.length));
} else {
if (broChecked || half) {
parents[1].checked = 2;
this._checkParentNode(parents.splice(1, parents.length));
}
}
}
}
}
// 选中/取消选中子节点
private _checkChildrenNode(children: any[], checkType: boolean) {
for (let child of children) {
child.checked = (checkType && 1);
if (!checkType && this.defaultCheckedNodes) {
const theIndex = _.findIndex(this.defaultCheckedNodes, (o) => {
return o == child[this.keyId];
});
if (theIndex != -1) {
child.checked = 0;
this.defaultCheckedNodes.splice(theIndex, 1);
}
}
if (child[this.keyChild]) {
this._checkChildrenNode(child[this.keyChild], checkType);
}
}
}
// 根据keyId查找节点
private _findNodeById(id: any, source: any) {
for (let i = 0; i < source.length; i++) {
const theI = source[i];
if (theI[this.keyId] == id) {
return theI;
}
if (theI[this.keyChild]) {
let res: any = this._findNodeById(id, theI[this.keyChild]);
if (res) {
return res;
}
}
}
}
// 根据名称keyName全匹配查找节点
private _findNodeByAllName(result: any, name: any, source: any) {
for (let i = 0; i < source.length; i++) {
const theI = source[i];
if (theI[this.keyName] == name) {
result.push(theI);
}
if (theI[this.keyChild]) {
this._findNodeByAllName(result, name, theI[this.keyChild]);
}
}
}
// 根据名称keyName模糊查找节点
private _findNodeByName(result: any, name: any, source: any) {
for (let i = 0; i < source.length; i++) {
let theI = source[i];
if (theI[this.keyName].toLowerCase().indexOf(name.toLowerCase()) != -1) {
result.push(theI);
}
if (theI[this.keyChild]) {
this._findNodeByName(result, name, theI[this.keyChild]);
}
}
}
// 获取选中的节点列表
private _getCheckedNodes(result: any[], source: any[]) {
for (let item of source) {
if (item.checked === 1 || item.checked === true) {
result.push(item);
}
if (item[this.keyChild]) {
this._getCheckedNodes(result, item[this.keyChild]);
}
}
}
// 获半选中的节点列表
private _getHalfCheckedNodes(result: any[], source: any[]) {
for (let item of source) {
if (item.checked === 2) {
result.push(item);
}
if (item[this.keyChild]) {
this._getHalfCheckedNodes(result, item[this.keyChild]);
}
}
}
private _getSelectedNodes(source: any[]): any {
for (let item of source) {
if (item.selected) {
return item;
}
if (item[this.keyChild]) {
let res: any = this._getSelectedNodes(item[this.keyChild]);
if (res) {
return res;
}
}
}
}
// 获取父节点
private _findParentNodeById(id: any, source: any, parent?: any) {
for (let i = 0; i < source.length; i++) {
let theI = source[i];
if (theI[this.keyId] == id) {
return parent;
}
if (theI[this.keyChild]) {
let res: any = this._findParentNodeById(id, theI[this.keyChild], theI);
if (res) {
return res;
}
}
}
}
// 获取父节点链,当前节点为第一个
private _findParentsNodeById(result: any, id: any, source: any) {
for (let i = 0; i < source.length; i++) {
let theI = source[i];
if (theI[this.keyId] == id) {
result.push(theI);
return theI;
}
if (theI[this.keyChild]) {
let res: any = this._findParentsNodeById(result, id, theI[this.keyChild]);
if (res) {
result.push(theI);
return res;
}
}
}
}
// 获取子节点列表格式
private _findChildrensNodeByNode(result: any, source: any) {
result.push(source);
if (source[this.keyChild]) {
for (let i = 0; i < source[this.keyChild].length; i++) {
this._findChildrensNodeByNode(result, source[this.keyChild][i]);
}
}
}
// 匹配搜索
private _matchSearchNodesByKey(result: any, val: any, key: any, source: any) {
for (let i = 0; i < source.length; i++) {
let theI = source[i];
if (theI[key] == val) {
result.push(source[i]);
}
if (theI[this.keyChild]) {
this._matchSearchNodesByKey(result, val, key, theI[this.keyChild]);
}
}
}
// 模糊搜索
private _fuzzySearchNodesByKey(result: any, val: any, key: any, source: any, findFlag?: any) {
let hasFlag = false;
for (let i = 0; i < source.length; i++) {
let theI = source[i];
if (theI[key].toLowerCase().indexOf(val.toLowerCase()) != -1) {
result.push(source[i]);
theI.isHide = false;
hasFlag = true;
}
if (theI[this.keyChild]) {
const flag: any = {
hasFlag: true
};
this._fuzzySearchNodesByKey(result, val, key, theI[this.keyChild], flag);
if (!flag.hasFlag && theI.isHide === undefined) {
theI.isHide = true;
} else {
hasFlag = true;
theI.show = true;
}
}
}
if (findFlag) {
findFlag.hasFlag = hasFlag;
}
}
// 根据ID的数组checked节点
private _checkNodesByIds(ids: any[], source: any) {
if (!ids || ids.length == 0) {
return;
}
for (let item of source) {
const index = _.indexOf(ids, item[this.keyId]);
if (index != -1) {
item.checked = 1;
ids.splice(index, 1);
}
if (item[this.keyChild] && item[this.keyChild].length > 0) {
this._checkNodesByIds(ids, item[this.keyChild]);
}
}
}
// 根据ID查询节点
findNodeById(id: any) {
return this._findNodeById(id, this.treeDatas);
}
// 根据名称查询全匹配节点
findNodeByName(name: any) {
let result: any[] = [];
this._findNodeByName(result, name, this.treeDatas);
return result;
}
// 根据名称模糊查询节点
findNodeByAllName(name: any) {
let result: any[] = [];
this._findNodeByAllName(result, name, this.treeDatas);
return result;
}
// 获取父节点
findParentNodeById(id: any) {
return this._findParentNodeById(id, this.treeDatas);
}
//获取父节点链
findParentsNodeById(id: any) {
let result: any = [];
this._findParentsNodeById(result, id, this.treeDatas);
return result;
}
findChildrensNodeByNode(node: any) {
let result: any = [];
this._findChildrensNodeByNode(result, node);
return result;
}
// 插入单个节点
insertNode(child: any, parent?: any) {
let targetData: any;
let parents: any;
if (parent) {
parents = this.findParentsNodeById(parent[this.keyId]);
if (parents && parents.length > 0) {
if (!parents[0][this.keyChild]) {
parents[0][this.keyChild] = [];
}
targetData = parents[0][this.keyChild];
for (let i = 0; i < parents.length; i++) {
parents[i].show = true;
}
if (this.options.checkbox && parents[0].checked) {
child.checked = 1;
}
}
} else { // 在根节点下插入
targetData = this.treeDatas;
}
targetData.push(child);
return child;
}
// 插入多个节点
insertNodes(children: any[], parent?: any) {
let targetData: any;
let parents: any;
if (parent) {
parents = this.findParentsNodeById(parent[this.keyId]);
if (parents && parents.length > 0) {
if (!parents[0][this.keyChild]) {
parents[0][this.keyChild] = [];
}
targetData = parents[0][this.keyChild];
for (let i = 0; i < parents.length; i++) {
parents[i].show = true;
}
if (this.options.checkbox && parents[0].checked) {
for (let item of children) {
item.checked = 1;
}
}
}
} else { // 在根节点下插入
targetData = this.treeDatas;
}
for (let item of children) {
targetData.push(item);
}
return children;
}
//更新节点数据
updateNodeData(data: any, keys: any) {
if (!keys) {
return;
}
let targetNode = this.findNodeById(data[this.keyId]);
for (let i = 0; i < keys.length; i++) {
if (keys[i] == this.keyChild) {
continue;
}
targetNode[keys[i]] = data[keys[i]];
}
}
//删除节点
deleteNodeById(id: any) {
let parentNode = this.findParentNodeById(id);
if (!parentNode) {
parentNode = this.treeDatas;
} else {
parentNode = parentNode[this.keyChild];
}
for (let i = 0; i < parentNode.length; i++) {
if (parentNode[i][this.keyId] == id) {
parentNode.splice(i, 1);
break;
}
}
}
// 匹配搜索
matchSearchNodesByKey(val: any, key: any) {
let result: any = [];
this._matchSearchNodesByKey(result, val, key, this.treeDatas);
return result;
}
removeHideNodes(nodes: any) {
for (let i = 0; i < nodes.length; i++) {
delete nodes[i].isHide;
if (nodes[i][this.keyChild]) {
this.removeHideNodes(nodes[i][this.keyChild]);
}
}
}
// 模糊搜索
fuzzySearchNodesByKey(val: any, key: any) {
// this.removeLighthightNodes(this.treeDatas);
this.treeNoData = false;
this.removeHideNodes(this.treeDatas);
let result: any = [];
if (val == '') {
result = [];
this.collspanAllNodes();
} else {
this._fuzzySearchNodesByKey(result, val, key, this.treeDatas);
if (!result || result.length == 0) {
this.treeNoData = true;
}
// this.expandNodes(result);
// this.lighthightNodes(result);
}
this.treeBox.nativeElement.scrollTop = 0;
/*if (result && result.length > 0) {
setTimeout(() => {
const domOffsetTop = result[0].treeDom.nativeElement.offsetTop;
this.treeBox.nativeElement.scrollTop = domOffsetTop;
}, 100);
} else {
this.treeBox.nativeElement.scrollTop = 0;
}*/
return result;
}
//展开节点
expandNode(node: any) {
let parents = this.findParentsNodeById(node[this.keyId]);
if (parents && parents.length > 0) {
if (!parents[0][this.keyChild]) {
parents[0][this.keyChild] = [];
}
for (let i = 0; i < parents.length; i++) {
parents[i].show = true;
}
}
}
// 展开节点s
expandNodes(nodes: any) {
for (let i = 0; i < nodes.length; i++) {
this.expandNode(nodes[i]);
}
}
collspanAllNodes(node?: any) {
const temp = node || this.treeDatas;
if (Array.isArray(temp)) {
// temp为数组,则递归
for (let i = 0; i < temp.length; i++) {
temp[i].show = false;
if (temp[i].children && temp[i].children.length > 0) {
this.collspanAllNodes(temp[i].children);
}
}
} else {
temp.show = false;
if (temp.children && temp.children.length > 0) {
this.collspanAllNodes(temp.children);
}
}
}
expandAllNodes(node?: any) {
const temp = node || this.treeDatas;
if (Array.isArray(temp)) {
// temp为数组,则递归
for (let i = 0; i < temp.length; i++) {
temp[i].show = true;
if (temp[i].children && temp[i].children.length > 0) {
this.expandAllNodes(temp[i].children);
}
}
} else {
temp.show = true;
if (temp.children && temp.children.length > 0) {
this.expandAllNodes(temp.children);
}
}
}
// 高亮节点s
lighthightNodes(nodes: any) {
for (let i = 0; i < nodes.length; i++) {
nodes[i].lighthight = true;
}
}
// 移除高亮s
removeLighthightNodes(nodes: any) {
for (let i = 0; i < nodes.length; i++) {
delete nodes[i].lighthight;
if (nodes[i][this.keyChild]) {
this.removeLighthightNodes(nodes[i][this.keyChild]);
}
}
}
// 选中节点
selectTreeNode(node: any) {
if (this.selectedNode && this.selectedNode == node && this.options.unSelect) {
this.deSelectTreeNode(this.selectedNode);
return;
}
this.selectedNode && this.deSelectTreeNode(this.selectedNode);
let item = this.findNodeById(node[this.keyId]);
if (item) {
item.selected = true;
this.selectedNode = item;
}
}
// 移除选中
deSelectTreeNode(node: any) {
let item = this.findNodeById(node[this.keyId]);
if (item) {
delete item.selected;
}
this.selectedNode = null;
}
// 获取选中节点 check
getCheckedNodes() {
let result: any[] = [];
this._getCheckedNodes(result, this.treeDatas);
return result;
}
// 获取半选节点 halfcheck
getHalfCheckedNodes() {
let result: any[] = [];
this._getHalfCheckedNodes(result, this.treeDatas);
return result;
}
// 获取选中节点 select
getSelectedNodes() {
return this._getSelectedNodes(this.treeDatas);
}
// 节点上移,顶层不可移动
moveUpwardsNode(node: any) {
let brothers: Array;
let parent = this.findParentNodeById(node[this.keyId]);
if (!parent) {
parent = this.treeDatas;
brothers = parent;
} else {
brothers = parent[this.keyChild];
}
const theIndex = _.findIndex(brothers, (o) => {
return o[this.keyId] == node[this.keyId];
});
if (theIndex == 0) {
return;
}
brothers.splice(theIndex, 1);
brothers.splice(theIndex - 1, 0, node);
}
// 节点下移,底层不可移动
moveDownNode(node: any) {
let brothers: Array;
let parent = this.findParentNodeById(node[this.keyId]);
if (!parent) {
parent = this.treeDatas;
brothers = parent;
} else {
brothers = parent[this.keyChild];
}
const theIndex = _.findIndex(brothers, (o) => {
return o[this.keyId] == node[this.keyId];
});
if (theIndex == (brothers.length - 1)) {
return;
}
brothers.splice(theIndex, 1);
brothers.splice(theIndex + 1, 0, node);
}
// 根据id数组check节点
checkNodesByIds(ids: any[]) {
this._checkNodesByIds(ids, this.treeDatas);
}
// 设置节点半选或全选
halfOrAllCheckNodesByIds(source: any, allIds?: any[], halfIds?: any[]) {
if (allIds && allIds.length > 0 && halfIds && halfIds.length > 0) { // 全选和半选数组都有值
for (const item of source) {
const allIndex = _.indexOf(allIds, item[this.keyId]);
const halfIndex = _.indexOf(halfIds, item[this.keyId]);
if (allIndex != -1) {
item.checked = 1;
allIds.splice(allIndex, 1);
} else if (halfIndex != -1) {
item.checked = 2;
halfIds.splice(halfIndex, 1);
} else {
item.checked = 0;
}
if (item[this.keyChild] && item[this.keyChild].length > 0) {
this.halfOrAllCheckNodesByIds(item[this.keyChild], allIds, halfIds);
}
}
} else if (allIds && allIds.length > 0 && (!halfIds || halfIds.length < 1)) { // 全选数组有值,半选数组没有
for (const item of source) {
const index = _.indexOf(allIds, item[this.keyId]);
if (index != -1) {
item.checked = 1;
allIds.splice(index, 1);
} else {
item.checked = 0;
}
if (item[this.keyChild] && item[this.keyChild].length > 0) {
this.halfOrAllCheckNodesByIds(item[this.keyChild], allIds);
}
}
} else if ((!allIds || allIds.length < 1) && halfIds && halfIds.length > 0) { // 全选数组没有值,半选数组有值
for (const item of source) {
const index = _.indexOf(halfIds, item[this.keyId]);
if (index != -1) {
item.checked = 2;
halfIds.splice(index, 1);
} else {
item.checked = 0;
}
if (item[this.keyChild] && item[this.keyChild].length > 0) {
this.halfOrAllCheckNodesByIds(item[this.keyChild], null, halfIds);
}
}
} else { // 全选和半选数组都没有值
for (const item of source) {
item.checked = 0;
if (item[this.keyChild] && item[this.keyChild].length > 0) {
this.halfOrAllCheckNodesByIds(item[this.keyChild]);
}
}
}
}
// 根据node查找前面的兄弟节点 type = after || prev
findBrotherNodeByNode(node: any, type?: string): any {
let brothers: Array;
const parent: any = this._findParentNodeById(node[this.keyId], this.treeDatas);
if (!parent) {
brothers = this.treeDatas;
} else {
brothers = parent[this.keyChild];
}
const index = _.findIndex(brothers, (o) => {
return o[this.keyId] == node[this.keyId];
});
if (type == 'after') {
if (index != (brothers.length - 1)) {
return brothers[index - 0 + 1];
} else {
return null;
}
} else {
if (index != 0) {
return brothers[index - 1];
} else {
return null;
}
}
}
}