如何向 <TextInput 对象发送上下文菜单事件并通过在 Typescript React 中单击按钮来选择菜单项



在我们的聊天组件中,许多人不知道他们可以通过右键单击文本区域并从菜单中选择表情符号来找到表情符号菜单。我想把一个按钮在UI,将打开表情符号菜单直接。这样,那些不知道右键和上下文菜单的人可以直接点击表情符号按钮,获得内置的表情符号。

我试着在文本输入旁边添加一个按钮(所以不是TextInput的孩子),并像这样发送上下文菜单:

const showCtxMenu = () => {
var element = document.getElementById("chatti");
var ev2 = new MouseEvent("contextmenu", {
bubbles: true,
cancelable: false,
view: window,
button: 2,
buttons: 0,
clientX: element.getBoundingClientRect().x,
clientY: element.getBoundingClientRect().y
});
element.dispatchEvent(ev2);
}

和TextInput对象在同一个功能组件中是这样的:

return (
<View
style={[
style.inputView,
{borderColor: primaryColor, height: 40}
]}>
<div id="chatti">
<TextInput
value={message}
// onContentSizeChange={(event) => {
// causes infinite react state update on ctrl+A -> delete
// setHeight(event.nativeEvent.contentSize.height);
// }}
onChangeText={(text) => onChangeMessage(text)}
style={{

当按钮单击时,我将事件发送到父div,所以什么也没有发生。我不知道如何将事件直接发送给TextInput,因为我不知道如何找到它。

我在React中设置了一个代码示例,如何从单击按钮调用contextmenu事件。您将需要对TextInput和包含上下文菜单的上下文菜单容器的DOM引用。

工作示例:https://stackblitz.com/edit/react-727dpd?file=src/App.js

在我的示例中,当您右键单击文本区域或按钮时,会显示上下文菜单。您需要关注的重点是我如何将ref添加到textarea。

import React, { useRef, useEffect } from 'react';
import './style.css';
export default function App() {
const contextMenuRef = useRef();
const chatBoxRef = useRef();
useEffect(() => {
const contextMenu = contextMenuRef.current;
const scope = chatBoxRef.current;
const normalizePozition = (mouseX, mouseY) => {
// ? compute what is the mouse position relative to the container element (scope)
let { left: scopeOffsetX, top: scopeOffsetY } =
scope.getBoundingClientRect();
scopeOffsetX = scopeOffsetX < 0 ? 0 : scopeOffsetX;
scopeOffsetY = scopeOffsetY < 0 ? 0 : scopeOffsetY;
const scopeX = mouseX - scopeOffsetX;
const scopeY = mouseY - scopeOffsetY;
// ? check if the element will go out of bounds
const outOfBoundsOnX =
scopeX + contextMenu.clientWidth > scope.clientWidth;
const outOfBoundsOnY =
scopeY + contextMenu.clientHeight > scope.clientHeight;
let normalizedX = mouseX;
let normalizedY = mouseY;
// ? normalize on X
if (outOfBoundsOnX) {
normalizedX =
scopeOffsetX + scope.clientWidth - contextMenu.clientWidth;
}
// ? normalize on Y
if (outOfBoundsOnY) {
normalizedY =
scopeOffsetY + scope.clientHeight - contextMenu.clientHeight;
}
return { normalizedX, normalizedY };
};
scope.addEventListener('contextmenu', (event) => {
console.log(event);
event.preventDefault();
const { clientX: mouseX, clientY: mouseY } = event;
const { normalizedX, normalizedY } = normalizePozition(mouseX, mouseY);
contextMenu.classList.remove('visible');
contextMenu.style.top = `${normalizedY}px`;
contextMenu.style.left = `${normalizedX}px`;
setTimeout(() => {
contextMenu.classList.add('visible');
});
});
scope.addEventListener('click', (e) => {
// ? close the menu if the user clicks outside of it
if (e.target.offsetParent != contextMenu) {
contextMenu.classList.remove('visible');
}
});
}, []);
const showCtxMenu = (e) => {
//e.preventDefault();
var element = chatBoxRef.current;
var ev2 = new MouseEvent('contextmenu', {
bubbles: true,
cancelable: false,
view: window,
button: 2,
buttons: 0,
clientX: element.getBoundingClientRect().x,
clientY: element.getBoundingClientRect().y,
});
element.dispatchEvent(ev2);
};
return (
<>
<div style={{ height: '300px' }}></div>
<textarea ref={chatBoxRef} col={10}></textarea>
<div ref={contextMenuRef} id="context-menu">
<div class="item">Option 1</div>
<div class="item">Option 2</div>
<div class="item">Option 3</div>
<div class="item">Option 4</div>
<div class="item">Option 5</div>
</div>
<button onClick={showCtxMenu}>Press Context</button>
</>
);
}

相关内容

  • 没有找到相关文章

最新更新