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;
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM