You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中<Text/>/<HtmlView/>自定义文本选择菜单及点击事件

嘿,这个需求我刚好折腾过,给你分享两种组件的实现思路,亲测可行!

在React Native中自定义文本选择菜单的实现方案

不管是用<Text>还是<HtmlView>(或者更推荐的react-native-render-html),都能实现自定义文本选择菜单并触发保存到数据库的逻辑,下面分情况给你拆解:

一、针对<Text>组件的实现

如果是原生<Text>组件,我们可以利用它的onSelectionChange事件监听文本选中状态,再结合自定义弹窗或者原生上下文菜单来实现需求。

方案1:自定义弹窗菜单(灵活可控)

这种方式可以完全自定义菜单的样式和位置,适合需要定制UI的场景:

import React, { useState, useRef } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

const CustomTextSelection = () => {
  const [selectedText, setSelectedText] = useState('');
  const [menuVisible, setMenuVisible] = useState(false);
  const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
  const textRef = useRef(null);

  // 监听文本选择变化
  const handleSelectionChange = (event) => {
    const { selection, text } = event.nativeEvent;
    // 只有选中范围不为空时才触发
    if (selection.start !== selection.end) {
      const pickedText = text.substring(selection.start, selection.end);
      setSelectedText(pickedText);
      // 计算菜单弹出位置(这里只是简单示例,实际可以根据选中位置更精准计算)
      textRef.current.measure((x, y, width, height, pageX, pageY) => {
        setMenuPosition({ x: pageX + 20, y: pageY - 50 });
        setMenuVisible(true);
      });
    } else {
      // 取消选中就隐藏菜单
      setMenuVisible(false);
    }
  };

  // 保存到数据库的逻辑
  const saveToDatabase = () => {
    // 这里替换成你的数据库操作,比如用Realm、AsyncStorage或者后端接口
    console.log('已选中文本并保存:', selectedText);
    setMenuVisible(false);
  };

  return (
    <View style={styles.container}>
      <Text
        ref={textRef}
        style={styles.text}
        selectable
        onSelectionChange={handleSelectionChange}
      >
        试试选中这段文本,看看自定义菜单会不会弹出来~选中后点击保存就能把文本存到数据库啦!
      </Text>
      {/* 自定义菜单弹窗 */}
      {menuVisible && (
        <View style={[styles.menuBox, { left: menuPosition.x, top: menuPosition.y }]}>
          <TouchableOpacity style={styles.menuItem} onPress={saveToDatabase}>
            <Text style={styles.menuText}>保存到数据库</Text>
          </TouchableOpacity>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 20,
  },
  text: {
    fontSize: 18,
    lineHeight: 26,
    color: '#333',
  },
  menuBox: {
    position: 'absolute',
    backgroundColor: '#fff',
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.2,
    shadowRadius: 4,
    elevation: 5, // Android阴影
  },
  menuItem: {
    paddingHorizontal: 18,
    paddingVertical: 10,
  },
  menuText: {
    fontSize: 16,
    color: '#1890ff',
    fontWeight: '500',
  },
});

export default CustomTextSelection;

方案2:原生上下文菜单(贴合系统风格)

如果想让菜单和系统自带的选择菜单风格统一,可以用第三方库react-native-context-menu-view来实现:

首先安装依赖:

npm install react-native-context-menu-view
# 或者 yarn add react-native-context-menu-view

然后实现代码:

import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ContextMenu from 'react-native-context-menu-view';

const NativeStyleSelection = () => {
  const [selectedText, setSelectedText] = useState('');

  const handleSelectionChange = (event) => {
    const { selection, text } = event.nativeEvent;
    if (selection.start !== selection.end) {
      setSelectedText(text.substring(selection.start, selection.end));
    }
  };

  const saveToDatabase = () => {
    console.log('通过原生菜单保存文本:', selectedText);
    // 这里写你的数据库逻辑
  };

  return (
    <View style={styles.container}>
      <ContextMenu
        actions={[{ title: '保存到数据库', id: 'save' }]}
        onPress={(event) => {
          if (event.nativeEvent.action.id === 'save') {
            saveToDatabase();
          }
        }}
      >
        <Text
          style={styles.text}
          selectable
          onSelectionChange={handleSelectionChange}
        >
          长按选中这段文本,会弹出和系统风格一致的菜单,点击保存即可存到数据库~
        </Text>
      </ContextMenu>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 20,
  },
  text: {
    fontSize: 18,
    lineHeight: 26,
    color: '#333',
  },
});

export default NativeStyleSelection;

二、针对<HtmlView>/HTML渲染内容的实现

如果是渲染HTML内容,原生<HtmlView>的事件监听比较有限,更推荐用react-native-render-html或者WebView来实现:

方案1:用WebView渲染HTML并监听选择事件

通过WebView注入JS代码来监听网页内的文本选择,再通过postMessage和RN通信:

import React from 'react';
import { View, WebView, StyleSheet } from 'react-native';

const HtmlTextSelection = () => {
  // 保存到数据库的逻辑
  const saveToDatabase = (selectedText) => {
    console.log('保存HTML中的文本:', selectedText);
    // 替换成你的数据库操作
  };

  // 注入到WebView的JS代码,监听文本选择
  const injectedJS = `
    document.addEventListener('selectionchange', function() {
      const selection = window.getSelection();
      const pickedText = selection.toString().trim();
      if (pickedText) {
        // 把选中的文本发送给RN
        window.ReactNativeWebView.postMessage(pickedText);
      }
    });
    true;
  `;

  // 你要渲染的HTML内容
  const htmlContent = `
    <div style="font-size: 18px; line-height: 26px; padding: 20px;">
      <p>这是HTML渲染的内容,选中这段文本试试~</p>
      <p>选中后会自动触发保存逻辑,或者你也可以在RN端弹出自定义菜单再保存~</p>
    </div>
  `;

  return (
    <View style={styles.container}>
      <WebView
        style={styles.webView}
        source={{ html: htmlContent }}
        injectedJavaScript={injectedJS}
        onMessage={(event) => {
          const selectedText = event.nativeEvent.data;
          saveToDatabase(selectedText);
        }}
        javaScriptEnabled={true}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  webView: {
    flex: 1,
  },
});

export default HtmlTextSelection;

方案2:用react-native-render-html自定义Text渲染

如果不想用WebView,可以用react-native-render-html,自定义Text组件的渲染逻辑,把前面<Text>组件的选择逻辑套进去:

首先安装依赖:

npm install react-native-render-html

然后实现代码:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import RenderHtml from 'react-native-render-html';
import CustomSelectableText from './CustomTextSelection'; // 就是前面写的自定义Text组件

const HtmlWithCustomSelection = () => {
  const htmlContent = `
    <div style="font-size: 18px; line-height: 26px;">
      <p>这是用react-native-render-html渲染的内容,支持自定义文本选择菜单~</p>
      <p>选中任意文本,就能看到我们自定义的保存菜单啦!</p>
    </div>
  `;

  // 自定义Text渲染器,替换默认的Text组件
  const customRenderers = {
    text: (props) => <CustomSelectableText {...props} />,
  };

  return (
    <View style={styles.container}>
      <RenderHtml
        contentWidth={350}
        source={{ html: htmlContent }}
        renderers={customRenderers}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingHorizontal: 20,
    paddingTop: 20,
  },
});

export default HtmlWithCustomSelection;

内容的提问来源于stack exchange,提问作者Aashutosh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:01:26