React自定义右键菜单Demo

案例样式

React 代码

import React from 'react'
import c from 'classnames'
import s from './test.module.styl'

class Test extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      visible: false,
    }
  }  

  componentDidMount() {
    document.addEventListener('contextmenu', this._handleContextMenu)
    document.addEventListener('click', this._handleClick)
    document.addEventListener('scroll', this._handleScroll)
  }

  componentWillUnmount() {
    document.removeEventListener('contextmenu', this._handleContextMenu)
    document.removeEventListener('click', this._handleClick)
    document.removeEventListener('scroll', this._handleScroll)
  }


  _handleContextMenu = event => {
    event.preventDefault()

    this.setState({visible: true})
    
    const clickX = event.clientX
    const clickY = event.clientY
    const screenW = window.innerWidth
    const screenH = window.innerHeight
    const rootW = this.root.offsetWidth
    const rootH = this.root.offsetHeight

    const right = (screenW - clickX) > rootW
    const left = !right
    const top = (screenH - clickY) > rootH
    const bottom = !top

    if (right) {
      this.root.style.left = `${clickX + 5}px`
    }

    if (left) {
      this.root.style.left = `${clickX - rootW - 5}px`
    }

    if (top) {
      this.root.style.top = `${clickY + 5}px`
    }

    if (bottom) {
      this.root.style.top = `${clickY - rootH - 5}px`
    }
  };

  _handleClick = event => {
    const {visible} = this.state
    const wasOutside = !(event.target.contains === this.root)

    if (wasOutside && visible) this.setState({visible: false})
  };

  _handleScroll = () => {
    const {visible} = this.state

    if (visible) this.setState({visible: false})
  };

  render() {
    const {visible} = this.state

    return (visible || null) 
          && (
            <div ref={ref => { this.root = ref }} className={c('hand', s.continer)}>
              <div className={c('fbh', s.option)}><div className={c('fb1')}>前进</div><div>➡️</div></div>
              <div className={s.option}>后退</div>
              <div className={s.option}>重新加载</div>
              <div className={s.group}>
                <div className={c('opcity10', s.option, s.disable)}>删除</div>
                <div className={s.option}>复制</div>
                <div className={s.option}>移动(Space Bar)</div>
                <div className={s.option}>缩放(⌥)</div>
              </div>
              <div className={s.option}>基本配置</div>
              <div className={s.option}>属性</div>
            </div>
          )
  }
}

export default Test


stylus代码

.continer
  position  fixed
  background  rgba(45,45,45,.9)
  border-radius 3px
  padding 8px 0
  box-shadow  0 0 15px rgba(0,0,0,.1)
  .option
    min-width 200px
    padding 4px 14px
    &:hover
      background  rgb(20,20,20)
  .disable
    color #999
    cursor default
    &:hover
      background  none
.group
  border-bottom 1px solid rgb(60,60,60)
  border-top 1px solid rgb(60,60,60)

posted @ 2020-03-20 10:22  南风S  阅读(337)  评论(0)    收藏  举报