UNPKG

hc-components

Version:

基于react的通用组件库

159 lines (152 loc) 5.9 kB
import forEach from 'lodash/forEach'; import {getComponent} from '../../layouts/getComponent'; export class Cascader { // #! 维护所有组件实例的配置 _cascadesMap = {}; // #! 维护所有践实例引用 _refs = {}; // # 获取组件实例 getInstance(name) { return this._refs[name]; } /** * # 装饰一个组件,并加入级联配置信息 * @param {String} name -指定实例的名称 * @param {Object} option - 组件的级联配置 * * + getFieldDecorator函数定义 * ``` * getFieldDecorator = function (name, option) { * // Field当前组件的定义 * return function(Field) { * return Hoc组件; * } * } * * // getFieldDecorator(a, b)(Input) * ``` * * + option的示例结构 * ``` * option = { * rely, // 级联的来源组件实例名称 * event, // 来源组件监听的事件,该事件触发后,会驱动当前组件的触发动作 * getVallueFormEvent, // 触发动作调用时,会传入来源组件触发事件后带进来的值 * trigger, // 当前组件的触发动作 * props // 装饰组件的额外props * } * ``` * * + this._cascadesMap示例结构 * ``` * cascadesMap = { * a: { * onChange: [{name, getValueFromEvent, trigger}, ...], * onClick: [] * } * } * ``` */ getFieldDecorator = (name, {rely, event = 'onChange', argIndex = 2, getValueFromEvent, trigger, props = {}}) => Field => { /** * + 初始化步骤 * 1. rely有值表示当前组件和来源组件有级联关系,rely指向来源组件的实例名 * 2. this._cascadesMap[rely]存入当前级联的配置信息,来源组件的事件作为key,值是数组 * * 示例: * A(来源)和B有级联,通过A的onClick;当前装饰C,需要和A有级联,通过onChange;当前装饰C,需要和A有级联,通过onChange;当装饰D,D和A也做级联,而且也是通过onChange。 * * A(来源)和B有级联onClick, A本身有onClick事件,alert(1); B本身onChange值介绍1个参数是不行的,必须要接受2个参数,A传给B的值放在第二个参数,同时这个参数值会存起来。 */ if (rely) { this._cascadesMap[rely] = this._cascadesMap[rely] || {}; const events = this._cascadesMap[rely][event] = this._cascadesMap[rely][event] || []; const item = events.find(item => item.name === name); // 是否有重复的级联配置存在 if (!item) { events.push({ name: name, getValueFromEvent: getValueFromEvent, trigger: trigger }); } } // 1. 外部变量,统一在函数内部一个地方可以管理到 // 2. 外部变量很大,存在内部变量来使用,效率更高 const cascadesMap = this._cascadesMap; const refs = this._refs; /** * Hoc所需的getProps方法 * @param {object} props -外部传入的props * @param {object} context -父级挂载的组件 * @param {func} setState -方法 */ const _getProps = props.getProps; const getProps = function (props, context, setState) { const newProps = _getProps ? _getProps(props, context, setState) : {}; // 拿到ref实例 newProps.ref = inst => { // 判断是否是Hoc组件 if (inst && inst.getRealInstance) { refs[name] = inst.getRealInstance(); } else { refs[name] = inst; } }; const cascadeEvents = cascadesMap[name]; if (cascadeEvents) { // 遍历级联事件 forEach(cascadeEvents, (cascades, eventName) => { const eventCb = newProps[eventName] || props[eventName]; // 拦截事件 newProps[eventName] = (e) => { // 之前的事情触发掉。 const ret = eventCb && eventCb(e); const promise = ret && ret.then ? ret : Promise.resolve(); // 在之前的事件触发完成之后再执行后续的动作 promise.then(() => { cascades.forEach(instObj => { const value = e.target ? e.target.value : e; // 组件的实例 const instance = refs[instObj.name]; if (instance) { // if (argIndex !== 1 && instance._triggerParams === undefined) { // 我们给B组件传入值到第二个参数 if (!instance._args) { instance._args = []; for (let i = 1; i < argIndex; i++) { instance._args.push(undefined); } } const method = instance[instObj.trigger]; instance[instObj.trigger] = function () { return method.apply(this, instance._args.concat(instance._triggerParams)); }; } // 约定把值传入给_triggerParams instance._triggerParams = instObj.getValueFromEvent ? instObj.getValueFromEvent(value) : null; instance[instObj.trigger](); } }); }); return ret; }; }); } return newProps; }; /** * Hoc的通用逻辑:B -> Hoc * 1. 新定义组件Hoc,传入的所有的prop存在state * 2. render函数把state的值,以props的形式传入到A * 3. Hoc组件,可以通过getRealInstance获取B的实例 */ const HocField = getComponent(props, getProps)(Field); HocField.prototype.getRealInstance = () => { return refs[name]; }; // 装饰当前组件,会生成一个新的Hoc组件返回。 return HocField; } }