UNPKG

@logicflow/vue-node-registry

Version:

LogicFlow Vue Component Node Registry

265 lines 12 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.VueNodeView = void 0; var vue_demi_1 = require("vue-demi"); // Vue2/3 兼容 API;使用 vue-demi 保持两端一致 var lodash_es_1 = require("lodash-es"); var core_1 = require("@logicflow/core"); var registry_1 = require("./registry"); var teleport_1 = require("./teleport"); var container_1 = require("./components/container"); var VueNodeView = /** @class */ (function (_super) { __extends(VueNodeView, _super); function VueNodeView() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.__throttledUpdate = (0, lodash_es_1.throttle)(function () { return _this.measureAndUpdate(); }, 80); _this.measureAndUpdate = function () { try { // 读取子组件(或容器本身)的实际尺寸并更新模型属性 var root = _this.getComponentContainer(); if (!root) return; var target = root.firstElementChild || root; var rect = target.getBoundingClientRect(); var width = (0, lodash_es_1.round)(rect.width); var height = (0, lodash_es_1.round)(rect.height); if (width <= 0 || height <= 0) return; if (width === _this.__lastWidth && height === _this.__lastHeight) return; _this.__lastWidth = width; _this.__lastHeight = height; var props = _this.props.model.properties; var extra = (0, lodash_es_1.get)(props, '_showTitle') ? (0, lodash_es_1.isNumber)((0, lodash_es_1.get)(props, '_titleHeight')) ? (0, lodash_es_1.get)(props, '_titleHeight') : 28 : 0; // 去掉标题占用的高度,保证内容区域与模型高度一致 var baseHeight = (0, lodash_es_1.clamp)(height - extra, 1, Number.MAX_SAFE_INTEGER); _this.props.model.setProperties({ width: width, height: baseHeight }); } catch (err) { // swallow error } }; return _this; } // private isMounted: boolean = false VueNodeView.prototype.getComponentContainer = function () { return this.root; }; VueNodeView.prototype.targetId = function () { return "".concat(this.props.graphModel.flowId, ":").concat(this.props.model.id); }; VueNodeView.prototype.componentWillUnmount = function () { _super.prototype.componentWillUnmount.call(this); this.unmount(); }; VueNodeView.prototype.setHtml = function (rootEl) { // 创建节点内容容器并注入到 foreignObject(若已存在则复用) var existed = rootEl.querySelector('.custom-vue-node-content'); if (!existed) { var el = document.createElement('div'); el.className = 'custom-vue-node-content'; this.root = el; rootEl.appendChild(el); } // 渲染 Vue 组件并启用尺寸监听 this.renderVueComponent(); this.startResizeObserver(); }; // eslint-disable-next-line @typescript-eslint/no-unused-vars VueNodeView.prototype.confirmUpdate = function (_rootEl) { // TODO: 如有需要,可以先通过继承的方式,自定义该节点的更新逻辑;我们后续会根据实际需求,丰富该功能 var model = this.props.model; var _a = (model.properties || {})._showTitle, _showTitle = _a === void 0 ? false : _a; if (_showTitle) { this.setHtml(_rootEl); } }; VueNodeView.prototype.renderVueComponent = function () { var _a; this.unmountVueComponent(); var root = this.getComponentContainer(); var _b = this.props, model = _b.model, graphModel = _b.graphModel; var _c = (model.properties || {})._showTitle, _showTitle = _c === void 0 ? false : _c; var wrapWithContainer = function (child) { return (0, vue_demi_1.defineComponent)({ name: 'LFVueNodeContainerWrapper', props: { node: { type: Object, required: true }, graph: { type: Object, required: true }, }, render: function () { // 根据 _showTitle 决定是否用 Container 包裹,避免无标题时额外结构 if (!_showTitle) { return (0, vue_demi_1.h)(child, { node: this.node, graph: this.graph }); } return (0, vue_demi_1.h)(container_1.Container, { node: this.node, graph: this.graph }, [ (0, vue_demi_1.h)(child, { node: this.node, graph: this.graph }), ]); }, }); }; if (root) { var nodeConfig = (0, registry_1.getVueNodeConfig)(model.type, graphModel); var flowId = this.props.graphModel.flowId; if (!nodeConfig) { // No registered config for this node type; ensure any existing Teleport mount is cleaned up if (vue_demi_1.isVue3 && (0, teleport_1.isActive)() && flowId) { (0, teleport_1.disconnect)(this.targetId(), flowId); } return; } var component = nodeConfig.component; if (!component) { // Config exists but has no component; also clean up any existing Teleport mount if (vue_demi_1.isVue3 && (0, teleport_1.isActive)() && flowId) { (0, teleport_1.disconnect)(this.targetId(), flowId); } return; } if (component) { if (vue_demi_1.isVue2) { var Vue = vue_demi_1.Vue2; var Composed_1 = wrapWithContainer(component); this.vm = new Vue({ el: root, render: function (h) { return h(Composed_1, { props: { node: model, graph: graphModel, }, }); }, provide: function () { return { getNode: function () { return model; }, getGraph: function () { return graphModel; }, }; }, }); } else if (vue_demi_1.isVue3) { if ((0, teleport_1.isActive)()) { var Composed = wrapWithContainer(component); (0, teleport_1.connect)(this.targetId(), Composed, root, model, graphModel); } else { var Composed_2 = wrapWithContainer(component); this.vm = (0, vue_demi_1.createApp)({ render: function () { return (0, vue_demi_1.h)(Composed_2, { node: model, graph: graphModel, }); }, provide: function () { return { getNode: function () { return model; }, getGraph: function () { return graphModel; }, }; }, }); (_a = this.vm) === null || _a === void 0 ? void 0 : _a.mount(root); // this.isMounted = true } } } } }; VueNodeView.prototype.startResizeObserver = function () { var _this = this; var _a; // 启动尺寸监听:优先使用 ResizeObserver,退化到 window.resize var root = this.getComponentContainer(); if (!root) return; try { if ((0, lodash_es_1.isFunction)(window.ResizeObserver)) { this.__resizeObserver = new window.ResizeObserver(function (entries) { if (!(0, lodash_es_1.isArray)(entries) || !entries.length) return; if (_this.__resizeRafId) cancelAnimationFrame(_this.__resizeRafId); // 使用 RAF 对齐绘制帧,再用节流函数合并频繁变更 _this.__resizeRafId = requestAnimationFrame(_this.__throttledUpdate); }); var target = root.firstElementChild || root; (_a = this.__resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(target); } else { // 退化监听:在窗口尺寸变化时尝试更新 window.addEventListener('resize', function () { return _this.__throttledUpdate(); }); this.__fallbackUnlisten = function () { return window.removeEventListener('resize', function () { return _this.__throttledUpdate(); }); }; } } catch (err) { // swallow error } }; VueNodeView.prototype.stopResizeObserver = function () { try { // 停止所有监听与异步回调,避免内存泄漏 if (this.__resizeObserver) { this.__resizeObserver.disconnect(); this.__resizeObserver = undefined; } if (this.__resizeRafId) { cancelAnimationFrame(this.__resizeRafId); this.__resizeRafId = undefined; } if (this.__fallbackUnlisten) { this.__fallbackUnlisten(); this.__fallbackUnlisten = undefined; } } catch (err) { // swallow error } }; VueNodeView.prototype.unmountVueComponent = function () { var root = this.getComponentContainer(); // 在卸载 Vue 实例前先停止尺寸监听 this.stopResizeObserver(); if (this.vm) { vue_demi_1.isVue2 && this.vm.$destroy(); vue_demi_1.isVue3 && this.vm.unmount(); this.vm = null; } if (root && !(0, teleport_1.isActive)()) { root.innerHTML = ''; } return root; }; VueNodeView.prototype.unmount = function () { // Teleport 模式下断开连接,并清理视图与监听 if ((0, teleport_1.isActive)()) { (0, teleport_1.disconnect)(this.targetId(), this.props.graphModel.flowId); } this.unmountVueComponent(); }; return VueNodeView; }(core_1.HtmlNode)); exports.VueNodeView = VueNodeView; exports.default = VueNodeView; //# sourceMappingURL=view.js.map