# 如何禁止文本组件长按弹出菜单选项

#### 问题现象

文本组件（例如TextInput、TextArea）长按输入框会弹出粘贴/全选/拍摄输入等菜单选项，如何禁止文本组件长按弹出菜单选项？

问题效果预览：

#### 背景知识

TextInput、TextArea等文本输入组件，在长按时会自动弹出系统文本选择菜单，包括粘贴、全选、拍摄输入等。

*   如果想要隐藏系统文本选择菜单，有以下两种方法：
    *   使用selectionMenuHidden属性进行隐藏。
    *   使用自定义菜单bindContextMenu替代系统文本选择菜单。弹出菜单项需要自定义。
*   如果不想隐藏系统文本选择菜单，而是仅仅想禁用菜单中的某项功能，可以通过使用editMenuOptions设置自定义菜单的扩展项实现。

#### 解决方案

*   方案一：利用selectionMenuHidden属性隐藏系统文本选择菜单，示例代码如下：
    
    ```
    @Entry
    @Component
    struct ProhibitLongPressPopupMenuOne {
      @State message: string = '';
    
      build() {
        Column() {
          Text(`输入的内容: ${this.message}`).margin({ top: 100, bottom: 30 });
          TextInput({ placeholder: '请输入内容' })
            .margin({ left: 16, right: 16 })
            .borderRadius(10)
            .onChange((value: string) => {
              this.message = value;
            })
            .selectionMenuHidden(true);
        }
        .height('100%')
        .width('100%');
      }
    }
    ```
    
*   方案二：拦截整个默认菜单并使用自定义bindContextMenu代替。
    
    1.  令Array返回空数组，从而拦截整个editMenu。
    2.  定义bindContextMenu，实际内容和功能需要自定义。
    3.  设置editMenuOptions自定义菜单扩展项，允许用户设置扩展项的文本内容、图标、回调方法。
    
    示例代码如下：
    
    ```
    @Entry
    @Component
    struct ProhibitLongPressPopupMenuTwo {
      @State start: number = 0;
      @State end: number = 0;
      @State text: string = '请选择此文字';
      @State isShown: boolean = true;
    
      getContentLength() {
        return this.text.length;
      }
    
      setSelection(start: number, end: number) {
        this.start = start;
        this.end = end;
      }
    
      setAllSelect() {
        this.setSelection(0, this.getContentLength());
      }
    
      build() {
        Column() {
          Column() {
            TextArea({ text: this.text })
              .fontSize(16)
              .copyOption(CopyOptions.InApp)
              .bindContextMenu(this.isShown, selectionMenu(),
                {
                  onDisappear: () => {
                    this.isShown = false;
                  }
                })
              .editMenuOptions({
                onCreateMenu: () => {
                  console.info(`Text onCreateMenu`);
                  this.isShown = true;
                  return []; // 拦截默认菜单项，显示自定义contextmenu
                }, onMenuItemClick: () => {
                  return true;
                }
              })
              .onTextSelectionChange((start, end) => {
                console.info(`TextSelection ${start.toString()} - ${end.toString()}`);
                if (start < 0 || end < 0) {
                  this.setSelection(0, 0);
                  this.isShown = false;
                } else {
                  this.start = start;
                  this.end = end;
                }
              })
              .parallelGesture(
                LongPressGesture()
                  .onAction(() => {
                    this.setAllSelect();
                  })
              );
          }
          .padding(50)
          .justifyContent(FlexAlign.Center)
          .backgroundColor('#fff3f2f2')
          .parallelGesture(
            LongPressGesture()
              .onAction(() => {
                this.setAllSelect();
              })
          );
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center);
      }
    }
    
    @Builder
    function selectionMenu() {
      Column() {
        Text('CustomMenu');
      };
    }
    ```
    

*   方案三：禁用editMenuOptions的参数editMenu的菜单选项。
    
    1.  以禁止粘贴为例，定义onCreateMenu方法，使用filter函数切除Array中的粘贴选项。
    2.  在editMenuOptions属性中使用onCreateMenu方法初始化editMenu。
    
    示例代码如下：
    
    ```
    @Entry
    @Component
    struct ProhibitLongPressPopupMenuThree {
      @State text: string = 'TextArea editMenuOptions';
    
      onCreateMenu(menuItems: Array<TextMenuItem>) {
        menuItems = menuItems.filter((item) => item.content !== '粘贴'); // 也可选择禁止输入/全选等其它菜单选项
        return menuItems;
      }
    
      build() {
        Column() {
          TextArea({ text: this.text })
            .width('95%')
            .height(56)
            .editMenuOptions({
              onCreateMenu: this.onCreateMenu, onMenuItemClick: () => {
                return false; // 返回为false，先执行自定义逻辑，再执行系统逻辑
              }
            })
            .margin({ top: 100 });
        }
        .width('90%')
        .margin('5%');
      }
    }
    ```
    

三种方案效果和特点如下：

| selectionMenuHidden属性隐藏文本选择菜单 | 拦截整个默认菜单并使用自定义bindContextMenu代替 | 禁用editMenu的菜单选项 |
| --- | --- | --- |
|  |  |  |
| 实现简单直接，只需设置selectionMenuHidden属性即可，但是过于粗暴，移除了所有文本操作功能，适用于安全性要求极高，不允许任何文本操作的场景。 | 实现最复杂，需要处理菜单显示，交互性等问题，可能会增加性能开销。优势在于功能灵活且完全可控，能够适配不同业务场景。 | 性能和稳定性优异，在选择禁止某项菜单功能的同时保留了其他文本菜单功能。 |