rendering

The implementation requirements are as follows:

Right-click on the contact profile picture to display a custom right-click menu component. It has the following functions: Set unread, mute, remove, and clear history. Right click on the chat message to bring up different functional components. If yes: Withdraw, delete, etc.Copy the code

thinking

Browsers have default right-click menus. We need to block it. Add right-click menu components that our business needs. Contacts and chat right-click menus are different. You can’t add right-click menus to every div because there’s too much content. So you need to customize a right menu and the right menu function does not affect the global

Ideas:

  • Disables the default browser right-click event
  • Get the right click location
  • Get the click
  • Assign right-click menu location and content
  • Render right menu
  • Listen for click and scroll events to close the menu

Complete code: detailed comments package look package will

Import React, {useEffect, useState, useRef} from 'React '; // style interface iStyle {position: any, left: number, top: Number} const PublicRightClick = () => {// Show/hide const [show, setShow] = useState< Boolean >(false); // Change position const [style, setStyle] = useState<iStyle>({position: 'fixed', left: 300, top: 200}); Const showRef = useRef(); // const rightClickRef = useRef<any>(); // Right-click on const handleContextMenu = (event: any) => {// Disable default event. PreventDefault (); // Otherwise, rightClickRef will be undefined setShow(true); Let {clientX, clientY} = event; // The width of the document display area const screenW: number = window.innerWidth; const screenH: number = window.innerHeight; / / the width of the right-click menu const rightClickRefW: number = rightClickRef. Current. The offsetWidth; const rightClickRefH: number = rightClickRef.current.offsetHeight; // Right is true, indicating that the mouse click is width from the right edge of the browser to drop the ContextMenu. // Otherwise, place the menu on the left. const right = (screenW - clientX) > rightClickRefW; const top = (screenH - clientY) > rightClickRefH; ClientX = right? clientX + 6 : clientX - rightClickRefW - 6; clientY = top ? clientY + 6 : clientY - rightClickRefH - 6; setStyle({ ... style, left: clientX, top: clientY }); }; Const handleClick = (event: any) => {// The chat page will listen for left-click events until they are destroyed. showRef.current) return; If (event.target.parentNode! == rightClickRef.current){ setShow(false) } }; // slide to disable the useless-return function const setShowFalse = () => {// eslint-disable-next-line no-useless-return if(! showRef.current) return; // scroll directly to close setShow(false)}; / / life cycle to monitor useEffect (() = > {document. AddEventListener (' contextmenu 'handleContextMenu); document.addEventListener('click', handleClick,true); document.addEventListener('scroll', setShowFalse, true); return () => { document.removeEventListener('contextmenu', handleContextMenu); document.removeEventListener('click', handleClick,true); document.removeEventListener('scroll', setShowFalse, true); }} []); // Side effect: assign new state to showRef as soon as show changes. // Because the listening event does not get the latest state // use ref to get it. UseEffect (() => {showref.current = show; }, [show]); / / render right const renderContentMenu = () = > (< div ref = {rightClickRef as any} the className = "WeChatContactsAvatarTools" style={style} > <div className="rightClickItems"> Mark as unread </div> <div className="rightClickItems"> Mute Notifications </div> <div className="rightClickItems"> Remove </div> <div className="rightClickItems"> Clear Chat History </div> </div> ); // Total render return show? renderContentMenu() : null; }; export default React.memo(PublicRightClick);Copy the code

Thanks for reading

  • If there are any mistakes in this article, please correct them in the comments section
  • Guidance is welcome if there is a better solution
  • If you have helped you, click a “like” and then go ~😊