UNPKG

@logicflow/vue-node-registry

Version:

LogicFlow Vue Component Node Registry

262 lines 11.5 kB
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 __()); }; })(); import { isVue2, isVue3, createApp, h, Vue2, defineComponent } from 'vue-demi'; // Vue2/3 兼容 API;使用 vue-demi 保持两端一致 import { throttle, round, get, isFunction, isArray, clamp, isNumber, } from 'lodash-es'; import { HtmlNode } from '@logicflow/core'; import { getVueNodeConfig } from './registry'; import { isActive, connect, disconnect } from './teleport'; import { Container } from './components/container'; var VueNodeView = /** @class */ (function (_super) { __extends(VueNodeView, _super); function VueNodeView() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.__throttledUpdate = 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 = round(rect.width); var height = 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 = get(props, '_showTitle') ? isNumber(get(props, '_titleHeight')) ? get(props, '_titleHeight') : 28 : 0; // 去掉标题占用的高度,保证内容区域与模型高度一致 var baseHeight = 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 defineComponent({ name: 'LFVueNodeContainerWrapper', props: { node: { type: Object, required: true }, graph: { type: Object, required: true }, }, render: function () { // 根据 _showTitle 决定是否用 Container 包裹,避免无标题时额外结构 if (!_showTitle) { return h(child, { node: this.node, graph: this.graph }); } return h(Container, { node: this.node, graph: this.graph }, [ h(child, { node: this.node, graph: this.graph }), ]); }, }); }; if (root) { var nodeConfig = 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 (isVue3 && isActive() && flowId) { 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 (isVue3 && isActive() && flowId) { disconnect(this.targetId(), flowId); } return; } if (component) { if (isVue2) { var Vue = 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 (isVue3) { if (isActive()) { var Composed = wrapWithContainer(component); connect(this.targetId(), Composed, root, model, graphModel); } else { var Composed_2 = wrapWithContainer(component); this.vm = createApp({ render: function () { return 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 (isFunction(window.ResizeObserver)) { this.__resizeObserver = new window.ResizeObserver(function (entries) { if (!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) { isVue2 && this.vm.$destroy(); isVue3 && this.vm.unmount(); this.vm = null; } if (root && !isActive()) { root.innerHTML = ''; } return root; }; VueNodeView.prototype.unmount = function () { // Teleport 模式下断开连接,并清理视图与监听 if (isActive()) { disconnect(this.targetId(), this.props.graphModel.flowId); } this.unmountVueComponent(); }; return VueNodeView; }(HtmlNode)); export { VueNodeView }; export default VueNodeView; //# sourceMappingURL=view.js.map