UNPKG

veui

Version:

Baidu Enterprise UI for Vue.js.

148 lines (134 loc) 4.29 kB
import { isString, isObject, includes, every, findIndex } from 'lodash' import { getTypedAncestor } from './helper' function isVnode (vnode) { return isObject(vnode) && vnode.componentOptions } /** * 判断是否指定值是否能够传入 getNodes 以获取 DOM nodes 。 * * @param {string|Vue|Node|Array<string>|Array<Vue>|Array<Node>} v 待判断的值 * @return {boolean} */ export function isValidNodesResolver (v) { function isValid (item) { return ( isString(item) || item.$vnode || includes([1, 3], item.nodeType) || isVnode(item) ) } return isValid(v) || (Array.isArray(v) && every(v, isValid)) } /** * 根据ref拿到指定的DOM节点,主要有一下情况: * 1、如果ref是字符串,就需要从context下面找指定ref的组件实例或者DOM元素; * 2、如果ref直接就是组件实例,那就取ref.$el; * 3、如果ref直接就是文本节点或者元素节点,就返回ref。 * 4、否则返回空数组 * * @param {string|Vue|Node|Array<string>|Array<Vue>|Array<Node>} ref 目标节点标识 * @param {VueContext=} context 组件上下文,在ref为字符串的时候必传 * @return {Node} */ export function getNodes (ref, context) { let vnodes = getVnodes(ref, context) return vnodes.map((item) => { if (isVnode(item)) { return item.elm } return item }) } export function getVnodes (ref, context) { if (!ref) { return [] } let vnodes if (isString(ref)) { vnodes = context.$refs[ref] if (!vnodes) { vnodes = [] } else { vnodes = Array.isArray(vnodes) ? vnodes : [vnodes] } vnodes = vnodes.filter(Boolean).map((item) => item.$vnode || item) } else { ref = Array.isArray(ref) ? ref : [ref] vnodes = ref.map((item) => { if (item.$vnode) { return item.$vnode } else if (isVnode(item) || item.nodeType === 1 || item.nodeType === 3) { // vnode节点、dom元素节点和文本节点 return item } }) } return vnodes } /** * 获取与当前组件最接近的给定类型的祖先组件中,当前组件在其第几个直接子节点的位置 * @param {Vue} current 查找的组件实例 * @param {string|Vue} parentType 父级类型 * @returns {number} 该实例所在位置的索引,找不到返回 -1 */ export function getIndexOfType (current, parentType) { let parent = parentType ? typeof parentType === 'string' ? getTypedAncestor(current, parentType) : parentType : current.$parent if (parentType && !parent) { throw new Error(`No ancestor typed as [${parentType}] found.`) } let parentVnodes = parent.$slots.default if (parentVnodes) { parentVnodes = ( Array.isArray(parentVnodes) ? parentVnodes : [parentVnodes] ).filter(({ tag }) => !!tag) } while (current.$parent !== parent) { current = current.$parent } let currentVnode = getVnodes(current)[0] // 只是用于每次渲染时插入到当前位置的顺序 return findIndex(parentVnodes, (vnode) => vnode === currentVnode) } /** * 查找该组件的子孙组件中第一个有某个方法的组件实例,深度优先 * @param {Vue} context 查找的组件实例,即从 context.$children 开始查找 * @param {function(Vue): boolean} predicate 判断这个组件是否匹配 * @returns {?Vue} 找到的组件 */ export function findComponent (context, predicate) { let comp = null function walkChildren (children) { return children.some((i) => { let match = predicate(i) if (match) { comp = i } else if (i.$children && i.$children.length) { return walkChildren(i.$children) } return !!match }) } walkChildren(context.$children || []) return comp } /** * 给 targets 中的每个函数的第一个参数绑定为 vm,一般用于给 mixin 传递依赖时使用 * * @param {object} targets 需要被绑定的对象 * @param {Vue} vm vm实例 * @return object 绑定后的新对象 */ export function bindVm (targets, vm) { return Object.keys(targets).reduce((acc, depName) => { acc[depName] = typeof targets[depName] === 'function' ? (...args) => targets[depName](vm, ...args) : targets[depName] return acc }, {}) }