UNPKG

veui

Version:

Baidu Enterprise UI for Vue.js.

254 lines (229 loc) 5.54 kB
import { find as _find } from 'lodash' const DEFAULT_CHILDREN_KEY = 'children' export function walk ( array, callback, alias = DEFAULT_CHILDREN_KEY, context = {} ) { return _walk( array, callback, { ...context, depth: 0, parents: [], parentIndices: [] }, alias ) } function _walk (array, callback, context, alias = DEFAULT_CHILDREN_KEY) { if (!array || !callback) { return } let enter let exit if (typeof callback === 'function') { enter = callback } else { enter = callback.enter exit = callback.exit } if (!enter && !exit) { return } if (!Array.isArray(array)) { array = getChildrenByAlias(array, alias) if (!array) { return } } let { depth, parents, parentIndices } = context let result = [] array.forEach((item, index) => { let skip = false let replaced = item let settedContext = null let selfContext = { ...context, index, skip: (...args) => { skip = args.length ? !!args[0] : true }, // 如果被 walk 的对象是可以修改的,可以直接修改 // 但是比如是 datasource prop,就只能用 replace 了 replace: (newItem) => { replaced = newItem }, setContext: (context) => { settedContext = context } } if (typeof enter === 'function') { enter(item, selfContext) } let children = skip ? null : getChildrenByAlias(replaced, alias) if (children) { selfContext.childrenResult = _walk( children, callback, { ...context, ...settedContext, parents: [...parents, replaced], parentIndices: [...parentIndices, index], depth: depth + 1 }, alias ) } if (typeof exit === 'function') { // 此时 exit 可以拿到 selfContext.childrenResult result.push(exit(replaced, selfContext)) } }) return result } export function find ( array, predicate, alias = DEFAULT_CHILDREN_KEY, parents = [] ) { if (!array || typeof predicate !== 'function') { return null } let result = null array.some((item) => { if (predicate(item, parents)) { result = item return true } let children = getChildrenByAlias(item, alias) if (!children) { return false } let inner = find(children, predicate, alias, [...parents, item]) if (inner !== null) { result = inner return true } }) return result } export function findParents ( array, predicate, { alias = DEFAULT_CHILDREN_KEY, includeSelf = false } = {} ) { let parents = [] let self = find( array, (item, pts) => { let match = !!predicate(item) if (match) { parents = pts } return match }, alias ) return self == null ? null : includeSelf ? parents.concat(self) : parents } function getChildrenByAlias (obj, alias) { let keys = typeof alias === 'string' ? [alias] : alias let key = _find(keys, (key) => { return Array.isArray(obj[key]) }) return key ? obj[key] : null } export function mapDatasource ( datasource, callback, childrenKey = DEFAULT_CHILDREN_KEY ) { const isExit = typeof callback === 'function' const enter = isExit ? null : callback.enter const exit = isExit ? callback : callback.exit return walk( datasource, { ...(enter ? { enter } : null), exit: (item, context) => { return { ...exit(item, context), ...(hasChildren(item, childrenKey) ? { [childrenKey]: context.childrenResult } : {}) } } }, childrenKey ) } export function hasChildren (item, childrenKey = DEFAULT_CHILDREN_KEY) { return !!item[childrenKey] && item[childrenKey].length !== 0 } export function getLeaves (root, childrenKey) { return getDescendants( root, (descendant) => { return { keep: hasChildren(descendant, childrenKey) ? false : 'value' } }, childrenKey ) } export function getGroupDescendants (root, childrenKey) { return getDescendants( root, (descendant) => { return { keep: hasChildren(descendant, childrenKey) ? 'value' : false } }, childrenKey ) } export function getEnabledDescendants (root, childrenKey) { return getDescendants( root, ({ disabled }) => { return { keep: disabled ? false : 'value', skipChildren: disabled } }, childrenKey ) } /** * 获取后代节点的值 * @param {object} root 父节点 * @param {Function} visit 控制如何获取后代节点的值,签名: (root, context) => ({keep, skipChildren}) * keep 为 false 表示不获取该节点的值,为 string 表示值对应的字段名 * skipChildren 为 boolean,表示是否跳过该节点之下的后代 * @param {string} childrenKey 子项的字段名 * @return {Array} 获取到的后代节点的值 */ export function getDescendants ( root, visit, childrenKey = DEFAULT_CHILDREN_KEY ) { let result = [] if (typeof visit === 'string') { childrenKey = visit visit = null } walk( root, (child, context) => { let { keep = 'value', skipChildren } = typeof visit === 'function' ? visit(child, context) : {} if (keep && child[keep] !== undefined) { result.push(child[keep]) } context.skip(!!skipChildren) }, childrenKey ) return result }