import * as Component from "../types/component"; import BaseComponentRender from "../component/BaseComponentRender"; import { insertScript } from "../common/util"; import { Extension } from "../types/component"; import Context from "../common/context"; interface ComponentConstructor { new ( context: Context, options: Component.Options, index: number, parent: any ): BaseComponentRender; } type LoadedOptions = { key: string; extension?: Extension; // 组件的扩展配置参数 component: ComponentConstructor; // 组件实现类 }; class Factory { // 缓存已经加载了的远程地址组件, 1加载中 2加载完成 private $cache: Record = {}; // 缓存当前可实例化的组件类 private $components: Record = {}; private $extensions: Record = {}; // 加载队列 private $loading: Record> = {}; private genUrl(url: string): string { return url || "default"; } /** * 加载指定地址的组件 * @param url */ public load(url: string): Promise { url = this.genUrl(url); // 已经加载过了,直接返回 if (this.$cache[url] === 2) { return Promise.resolve(true); } // 正在加载,压入队列 if (this.$cache[url] === 1) { return new Promise((resolve) => { this.$loading[url].push(resolve); }); } // 未加载过,开始加载 this.$cache[url] = 1; return new Promise((resolve) => { this.$loading[url] = [resolve]; insertScript(url, () => { this.$cache[url] = 2; this.$loading[url].forEach((fn) => { fn(true); }); this.$loading[url] = []; }); }); } /** * 直接设置已加载的组件 * @param url * @param component */ public loaded(url: string, component: LoadedOptions | Array) { url = this.genUrl(url); this.$cache[url] = 2; if (Array.isArray(component)) { component.forEach((item) => { this.cache(url, item); }); } else { this.cache(url, component); } } /** * 创建组件实例 * @param context * @param options * @param index * @param parent */ createComponent(context: Context, options: Component.Options, parent: any, index?: number) { let url = this.genUrl(options.url); return this.load(url).then(() => { let Component = this.getComponent(url, options.key); if (Component) { return new Component(context, options, parent, index); } else { throw Error(`不存在匹配的组件类型: ${options.key}`); } }); } /** * 缓存指定的组件 * @param url * @param loaded */ cache(url: string, loaded: LoadedOptions) { this.$components[`${url}${loaded.key.toLowerCase()}`] = loaded.component; if (loaded.extension) { this.$extensions[`${url}${loaded.key.toLowerCase()}`] = loaded.extension; } } /** * 获取已经加载的组件 * @param url * @param key */ getComponent(url: string, key: string): ComponentConstructor | undefined { return this.$components[`${this.genUrl(url)}${key.toLowerCase()}`]; } /** * 获取扩展信息 * @param url * @param key */ getExtension(url: string, key: string, props: Record): Extension | undefined { let extension = this.$extensions[`${this.genUrl(url)}${key.toLowerCase()}`]; if (typeof extension === "function") { return extension.call(null, props); } return extension; } } const factory = new Factory(); // @ts-ignore if (typeof window.componentJsonp === "undefined") { // @ts-ignore window.componentJsonp = function (url: string, component: LoadedOptions | Array) { if (Array.isArray(component)) { component.forEach((item) => { factory.cache(url, item); }); } else { factory.cache(url, component); } }; } export default factory;