From a9c249216567d8cccd79587f35c77c2cbb7787cd Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Thu, 6 Feb 2025 20:18:48 +0800 Subject: [PATCH] feat: support stopPropagation while text edit --- .../src/interface/graphic/richText.ts | 1 + .../builtin-plugin/richtext-edit-plugin.ts | 72 +++++++++++-------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/packages/vrender-core/src/interface/graphic/richText.ts b/packages/vrender-core/src/interface/graphic/richText.ts index 29fde09ef..f14049752 100644 --- a/packages/vrender-core/src/interface/graphic/richText.ts +++ b/packages/vrender-core/src/interface/graphic/richText.ts @@ -15,6 +15,7 @@ export type IRichTextEditOptionsType = { keepHeightWhileEmpty?: boolean; // 是否在输入的时候展示包围框,不传默认是false,可以传入颜色 boundsStrokeWhenInput?: string; + stopPropagation?: boolean; }; export type IRichTextAttribute = { diff --git a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts index 9c290b473..b74799732 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts @@ -295,11 +295,11 @@ export class RichTextEditPlugin implements IPlugin { this.pluginService = context; this.editModule = new EditModule(); // context.stage.on('click', this.handleClick); - context.stage.on('pointermove', this.handleMove); - context.stage.on('pointerdown', this.handlePointerDown); - context.stage.on('pointerup', this.handlePointerUp); - context.stage.on('pointerleave', this.handlePointerUp); - context.stage.on('dblclick', this.handleDBLClick); + context.stage.on('pointermove', this.handleMove, { capture: true }); + context.stage.on('pointerdown', this.handlePointerDown, { capture: true }); + context.stage.on('pointerup', this.handlePointerUp, { capture: true }); + context.stage.on('pointerleave', this.handlePointerUp, { capture: true }); + context.stage.on('dblclick', this.handleDBLClick, { capture: true }); application.global.addEventListener('keydown', this.handleKeyDown); this.editModule.onInput(this.handleInput); @@ -359,30 +359,33 @@ export class RichTextEditPlugin implements IPlugin { this._tryShowSelection(pos, cache); } - fullSelection(e: KeyboardEvent) { + fullSelection() { + const currRt = this.currRt; + if (!currRt) { + return; + } + const cache = currRt.getFrameCache(); + if (!cache) { + return; + } + const { lines } = cache; + const totalCursorCount = lines.reduce((total, line) => total + line.paragraphs.length, 0) - 1; + this.selectionRange(-0.1, totalCursorCount + 0.1); + } + + protected fullSelectionKeyHandler(e: KeyboardEvent) { if ( (application.global.isMacOS() && e.metaKey && e.key === 'a') || (!application.global.isMacOS() && e.ctrlKey && e.key === 'a') ) { - const currRt = this.currRt; - if (!currRt) { - return; - } - const cache = currRt.getFrameCache(); - if (!cache) { - return; - } - const { lines } = cache; - const totalCursorCount = lines.reduce((total, line) => total + line.paragraphs.length, 0) - 1; - this.selectionRange(-0.1, totalCursorCount + 0.1); - + this.fullSelection(); e.preventDefault(); return true; } return false; } - directKey(e: KeyboardEvent) { + directKeyHandler(e: KeyboardEvent) { if (!(e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight')) { return false; } @@ -486,12 +489,12 @@ export class RichTextEditPlugin implements IPlugin { } // 全选 // cmd/ctl + A - if (this.fullSelection(e)) { + if (this.fullSelectionKeyHandler(e)) { return; } // 方向键 // 上、下、左、右 - if (this.directKey(e)) { + if (this.directKeyHandler(e)) { return; } }; @@ -538,7 +541,7 @@ export class RichTextEditPlugin implements IPlugin { const placeholder = shadowRoot.getElementsByType('richtext')[0]; placeholder && shadowRoot.removeChild(placeholder); } - const { textConfig, editOptions } = this.currRt.attribute; + const { textConfig, editOptions = {} } = this.currRt.attribute; if (textConfig && textConfig.length) { return; } @@ -647,11 +650,11 @@ export class RichTextEditPlugin implements IPlugin { deactivate(context: IPluginService): void { // context.stage.off('pointerdown', this.handleClick); - context.stage.off('pointermove', this.handleMove); - context.stage.off('pointerdown', this.handlePointerDown); - context.stage.off('pointerup', this.handlePointerUp); - context.stage.off('pointerleave', this.handlePointerUp); - context.stage.off('dblclick', this.handleDBLClick); + context.stage.off('pointermove', this.handleMove, { capture: true }); + context.stage.off('pointerdown', this.handlePointerDown, { capture: true }); + context.stage.off('pointerup', this.handlePointerUp, { capture: true }); + context.stage.off('pointerleave', this.handlePointerUp, { capture: true }); + context.stage.off('dblclick', this.handleDBLClick, { capture: true }); application.global.addEventListener('keydown', this.handleKeyDown); } @@ -662,7 +665,7 @@ export class RichTextEditPlugin implements IPlugin { } this.currRt = e.target as IRichText; this.handleEnter(e); - (e.target as any).once('pointerleave', this.handleLeave); + (e.target as any).once('pointerleave', this.handleLeave, { capture: true }); this.tryShowSelection(e, false); }; @@ -700,6 +703,10 @@ export class RichTextEditPlugin implements IPlugin { this.tryShowSelection(e, true); }; + protected stopPropagation(e: Event) { + e.stopPropagation(); + } + onFocus(e: PointerEvent, data?: any) { this.updateCbs && this.updateCbs.forEach(cb => cb('beforeOnfocus', this)); this.deFocus(false); @@ -711,13 +718,16 @@ export class RichTextEditPlugin implements IPlugin { this.currRt = target as IRichText; // 创建shadowGraphic - RichTextEditPlugin.tryUpdateRichtext(target); const shadowRoot = this.getShadow(target); const cache = target.getFrameCache(); if (!cache) { return; } + const { editOptions = {} } = this.currRt.attribute; + if (editOptions.stopPropagation) { + target.addEventListener('*', this.stopPropagation); + } // 计算全局偏移 this.computeGlobalDelta(cache); @@ -793,6 +803,10 @@ export class RichTextEditPlugin implements IPlugin { if (!target) { return; } + const { editOptions = {} } = target.attribute; + if (editOptions.stopPropagation) { + target.removeEventListener('*', this.stopPropagation); + } if (trulyDeFocus) { this.trySyncPlaceholderToTextConfig(); target.detachShadow();