React项目中实现右键自定义菜单
最近在react项目中需要实现一个,右键自定义菜单功能。找了找发现纯react项目里没有什么工具可以实现这样的功能,所以在网上搜了搜相关资料。下面我会附上完整的组件代码。
(注:以下代码非本人原创,具体详情请参考 https://blog.csdn.net/anyicheng2015/article/details/78581064)
import React, { Component } from 'react' import PropTypes from 'prop-types' import assign from 'object-assign' import './index.less' import _ from 'lodash' class RightClickContextMenu extends Component { static propTypes = { style: PropTypes.object, onClickVideoAudioSpeedBtn: PropTypes.func, } static defaultProps = { style: {}, onClickVideoAudioSpeedBtn: _.noop, } state = { visible: false, } componentDidMount() { // 添加右键点击、点击事件监听 document.addEventListener('contextmenu', this.handleContextMenu) document.addEventListener('click', this.handleClick) } componentWillUnmount() { // 移除事件监听 document.removeEventListener('contextmenu', this.handleContextMenu) document.removeEventListener('click', this.handleClick) } // 右键菜单事件 handleContextMenu = (event) => { event.preventDefault() this.setState({ visible: true }) // clientX/Y 获取到的是触发点相对于浏览器可视区域左上角距离 const clickX = event.clientX const clickY = event.clientY // window.innerWidth/innerHeight 获取的是当前浏览器窗口的视口宽度/高度 const screenW = window.innerWidth const screenH = window.innerHeight // 获取自定义菜单的宽度/高度 const rootW = this.root.offsetWidth const rootH = this.root.offsetHeight // right为true,说明鼠标点击的位置到浏览器的右边界的宽度可以放下菜单。否则,菜单放到左边。 // bottom为true,说明鼠标点击位置到浏览器的下边界的高度可以放下菜单。否则,菜单放到上边。 const right = (screenW - clickX) > rootW const left = !right const bottom = (screenH - clickY) > rootH const top = !bottom if (right) { this.root.style.left = `${clickX}px` } if (left) { this.root.style.left = `${clickX - rootW}px` } if (bottom) { this.root.style.top = `${clickY}px` } if (top) { this.root.style.top = `${clickY - rootH}px` } }; // 鼠标单击事件,当鼠标在任何地方单击时,设置菜单不显示 handleClick = () => { const { visible } = this.state if (visible) { this.setState({ visible: false }) } }; render() { const wrapStyles = assign({}, this.props.style) const { visible } = this.state return ( visible && ( <div ref={(ref) => { this.root = ref }} className="contextMenu-wrap" style={wrapStyles}> <div className="contextMenu-option">输入文字</div> <div className="contextMenu-option">网络连接监控</div> <div className="contextMenu-option" role="button" onClick={this.props.onClickVideoAudioSpeedBtn}>音视频流监控</div> <div className="contextMenu-option">教室权限控制</div> <div className="contextMenu-separator" /> <div className="contextMenu-option">设置...</div> <div className="contextMenu-option">全局设置...</div> </div> ) ) } } export default RightClickContextMenu
样式部分如下:
.contextMenu-wrap{ z-index: 100; position: fixed; background: linear-gradient(to right, #c6c7cf, #f0f0f0); box-shadow: 0px 2px 5px #999999; border-radius: 4px; padding-top: 5px; .contextMenu-option{ padding: 0px 50px 2px 15px; min-width: 160px; cursor: default; font-size: 14px; &:hover { background: #388bfe; color: white; } &:active { color: #b5b7be; background: linear-gradient(to top, #555, #444); } } .contextMenu-separator{ width: 100%; height: 1px; background: #b5b7be; margin: 2px 0; } }