react中解决下拉时,多个tooltip包裹的列表中,hover时,tooltip快速触发,闪烁问题

闪烁问题,是由于没有用div包裹元素

下拉时不让hover到的元素触发,停止下拉时才触发tooltip显示

这里就涉及到如何判断滚动中和滚动结束

只需要在滚动时记录下top1,而滚动时节流1000调用另一函数,此函数中再获取当前滚动条值记录为top2,如此进行比较,就可以知道当前滚动是否停止

而为何需要1000ms的间隔再判断了,试想一下,如果每次都是秒判断,那么必定一直相等,因为top1,top2两者都是取得滚动条的值,自然是要有些间隔来取,

值得一提的是,react绑定滚动条事件本不该有问题,但是试了许久,只能如代码中此种方式绑定方可,不知为何

import React, { Component } from "react";
import PropTypes from "prop-types";
import { findDOMNode } from "react-dom";
import { DragSource, DropTarget } from "react-dnd";
import ItemTypes from "./ItemTypes";
import { Row, Col, Icon, Tag, Tooltip, Badge } from "antd";
import { Language } from "Utils";
import { Divider } from "edspUI";

const i18n = Language.getLanguage("group");
const style = {
  //   border: '1px solid #eee',
  //   padding: '0.6rem 1rem',
  // marginBottom: '.5rem',
  backgroundColor: "white",
  cursor: "move",
};

const cardSource = {
  beginDrag(props) {
    return {
      id: props.id,
      index: props.index,
      groupInf: props.groupInf,
      data: props.itemData,
    };
  },
};

const cardTarget = {
  hover(props, monitor, component) {
    if (!component) return null;
    const dragIndex = monitor.getItem().index;
    const hoverIndex = props.index;
    const data = monitor.getItem().data;
    // Don't replace items with themselves
    if (dragIndex === hoverIndex) {
      return;
    }

    // Determine rectangle on screen
    const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();

    // Get vertical middle
    const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

    // Determine mouse position
    const clientOffset = monitor.getClientOffset();

    // Get pixels to the top
    const hoverClientY = clientOffset.y - hoverBoundingRect.top;

    // Only perform the move when the mouse has crossed half of the items height
    // When dragging downwards, only move when the cursor is below 50%
    // When dragging upwards, only move when the cursor is above 50%

    // Dragging downwards
    if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
      return;
    }

    // Dragging upwards
    if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
      return;
    }
    // Time to actually perform the action
    props.moveCard(dragIndex, hoverIndex, data);

    // Note: we're mutating the monitor item here!
    // Generally it's better to avoid mutations,
    // but it's good here for the sake of performance
    // to avoid expensive index searches.
    monitor.getItem().index = hoverIndex;
  },
};

@DropTarget(ItemTypes.CARD, cardTarget, (connect) => ({
  connectDropTarget: connect.dropTarget(),
}))
@DragSource(ItemTypes.CARD, cardSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  isDragging: monitor.isDragging(),
}))
export default class Card extends Component {
  static propTypes = {
    connectDragSource: PropTypes.func.isRequired,
    connectDropTarget: PropTypes.func.isRequired,
    index: PropTypes.number.isRequired,
    isDragging: PropTypes.bool.isRequired,
    groupInf: PropTypes.string.isRequired,
    id: PropTypes.any.isRequired,
    moveCard: PropTypes.func.isRequired,
    itemData: PropTypes.string.isRequired,
    locations: PropTypes.string.isRequired,
    operateType: PropTypes.string.isRequired,
  };
  constructor(props) {
    super(props);
    this.onScrollStopTooltip = this.onScrollStopTooltip.bind(this);
  }
  state = {
    top1: 0, //滚动时的滚动条高度,
    top2: 0, //滚动结束时的滚动条高度,
    timer: null, //滚动停止1s后执行比较,看看是否停止了
    isScrolling: true, //当前是否在滚动
    showTooltipFlag: false, //当前tooltip是否展示
    hoverStatus: false, //当前是否还在hover中
  };

  isScrollEnd = () => {
    // 滚动停止时获取当前滚动条高度
    this.state.top2 =
      document.documentElement.scrollTop || document.body.scrollTop;
    if (this.state.top1 == this.state.top2) {
      console.log("滚动结束了");
      // 如果此时仍然是hover状态,那么吧tooltip设置为true
      if (this.state.hoverStatus) {
        this.setState({ showTooltipFlag: true });
      }
      this.setState({ isScrolling: false });
    }
  };
  componentDidMount() {
    window.addEventListener("scroll", this.onScrollStopTooltip, true);
  }
  componentWillUnmount() {
    window.removeEventListener("scroll", this.onScrollStopTooltip, true);
  }
  onScrollStopTooltip = () => {
    clearTimeout(this.state.timer);
    // 滚动的时候,滚动状态为true,tooltip不展示
    this.setState({ isScrolling: true, showTooltipFlag: false });
    this.state.timer = setTimeout(this.isScrollEnd, 1000);
    // 滚动时获取滚动条高度
    this.state.top1 =
      document.documentElement.scrollTop || document.body.scrollTop;
    console.log("滚动中"); //滚动的时候触发
  };
  handleTooltipShow = () => {
    //如果此时是滚动中,设置为false
    // 如果此时滚动停止了,设置为true
    // 并且吧hover状态变为true,在hover
    if (this.state.isScrolling) {
      this.setState({ showTooltipFlag: false, hoverStatus: true });
    } else {
      this.setState({ showTooltipFlag: true, hoverStatus: true });
    }
  };
  handleTooltipHide = () => {
    // 离开时吧tooltip隐藏
    // 并且吧hover状态变为false,不hover
    this.setState({ showTooltipFlag: false, hoverStatus: false });
  };

  render() {
    const {
      isDragging,
      connectDragSource,
      connectDropTarget,
      itemData,
      locations,
      groupInf,
      operateType,
    } = this.props;
    const opacity = isDragging ? 0 : 1;
    const addChild = ["if", "elseif", "for", "while", "else"];
    const basicColor = "#999";
    const titleTip = (itemData) => {
      // console.log(itemData)
      return (
        <div>
          {itemData.expression ? (
            <span className="mr10">{i18n.operateState}</span>
          ) : null}
          {itemData.expression ? (
            <span className="mr10">{itemData.expression || "_"}</span>
          ) : null}
          {itemData.left ? (
            <span className="mr10">{itemData.left || "_"}</span>
          ) : null}
          {itemData.left || itemData.right ? (
            <span className="mr10">{itemData.function || "_"}</span>
          ) : null}
          {itemData.right ? (
            <span className="mr10">{itemData.right || "_"}</span>
          ) : null}
        </div>
      );
    };
    return connectDragSource(
      connectDropTarget(
        <div style={{ ...style, opacity }}>
          <Row style={{ marginTop: "10px" }}>
            {operateType == "look" ? (
              <Col span={1} offset={locations.length}></Col>
            ) : (
              <Col span={1} offset={locations.length}>
                {addChild.includes(itemData.function) &&
                locations.length < 5 ? (
                  <Icon
                    className="delete-button ml20"
                    type="plus-circle-o"
                    onClick={this.props.addChild.bind(
                      this,
                      "new",
                      {},
                      locations,
                      "add"
                    )}
                  />
                ) : null}
              </Col>
            )}
            <Col span={2}>
              {/**<Tag color={tagColor[itemData.function]}>{itemData.function}</Tag>**/}
              <a
                style={{ color: itemData.disable ? "#ccc" : null }}
                onClick={
                  itemData.disable
                    ? null
                    : this.props.editItem.bind(
                        this,
                        itemData.function,
                        itemData,
                        locations
                      )
                }
              >
                <Tag
                  color={basicColor}
                  style={{ width: "100%", textAlign: "center" }}
                >
                  {itemData.function != "include"
                    ? itemData.function
                    : groupInf.motype == "0"
                    ? "union"
                    : groupInf.motype == "1"
                    ? "sql"
                    : groupInf.motype == "2"
                    ? "inter"
                    : groupInf.motype == "5"
                    ? "ui"
                    : groupInf.motype == "6"
                    ? "App"
                    : groupInf.motype == "7"
                    ? "Doc"
                    : "SP"}
                </Tag>
              </a>
            </Col>
            {itemData.order ? (
              <Col span={2} style={{ marginLeft: "10px" }}>
                <a
                  style={{ color: itemData.disable ? "#ccc" : null }}
                  onClick={
                    itemData.disable
                      ? null
                      : this.props.editItem.bind(
                          this,
                          itemData.function,
                          itemData,
                          locations
                        )
                  }
                >
                  <Tag
                    style={{ width: "100%", textAlign: "center" }}
                    color={basicColor}
                  >
                    {itemData.order}
                  </Tag>
                </a>
              </Col>
            ) : (
              ""
            )}
            <Col span={12} style={{ marginLeft: "20px" }}>
              <a
                style={{
                  color: itemData.disable ? "#ccc" : null,
                  cursor: itemData.disable ? "default" : "pointer",
                }}
                onClick={
                  itemData.disable
                    ? null
                    : this.props.editContent.bind(
                        this,
                        itemData.function,
                        itemData,
                        locations
                      )
                }
              >
                {/* 下拉的时候禁用tooltip,下拉结束的时候启用,其实也就是隐藏吧,默认是显示的,一下啦就隐藏
                下拉停止就显示 */}
                {itemData.function == "include" ? (
                  <Tooltip
                    placement="right"
                    title={titleTip(itemData)}
                    visible={this.state.showTooltipFlag}
                    onMouseLeave={this.handleTooltipHide}
                    onMouseEnter={this.handleTooltipShow}
                  >
                    {/* 此处要用div包起来,如若不这样,一段长文本,明明都属于tooltip范畴
                    但是你hover到行之间的空白,居然也会触发onmouseleave,。。。。。,就会不停触发
                    不停的闪烁
                    所以用div包起来 */}
                    <div>
                      <span className="mr10">{itemData.left || "_"}</span>
                      <span className="mr10">{`${i18n.mlname}${":"}`}</span>
                      <span className="mr10">{groupInf.mlname}</span>
                      <span className="mr10">{i18n.descriptionValue}</span>
                      <span className="mr10">{itemData.desc || "_"}</span>
                    </div>
                  </Tooltip>
                ) : (
                  <div
                    style={{
                      whiteSpace: "pre-wrap",
                      wordBreak: "break-all",
                      wordWrap: "break-word",
                    }}
                  >
                    {/**{itemData.expression ? <span className="mr10">{i18n.operateState}</span> : null}**/}
                    {itemData.expression ? (
                      <span className="mr10">{itemData.expression || "_"}</span>
                    ) : null}
                    {itemData.left ? (
                      <span className="mr10">{itemData.left || "_"}</span>
                    ) : null}
                    {itemData.left || itemData.right ? (
                      <span className="mr10">{itemData.function || "_"}</span>
                    ) : null}
                    {itemData.right ? (
                      <span className="mr10">{itemData.right || "_"}</span>
                    ) : null}
                    &nbsp;
                    <span className="mr10">{i18n.descriptionValue}</span>
                    <span className="mr10">{itemData.desc || "_"}</span>
                  </div>
                )}
              </a>
            </Col>
            {operateType == "look" ? null : (
              <Col span={4}>
                <a disabled={itemData.disable}>
                  <i
                    className="icon-plus3"
                    onClick={this.props.addNext.bind(
                      this,
                      "new",
                      {},
                      locations,
                      "add",
                      itemData
                    )}
                  ></i>
                </a>
                <Divider />
                <a disabled={itemData.disable}>
                  <i
                    className="icon-cross2"
                    onClick={this.props.remove.bind(this, locations, itemData)}
                  ></i>
                </a>
                {this.props.groupOrCase == "case" && (
                  <span>
                    <Divider />

                    {!itemData.disable ? (
                      <a>
                        <i
                          className="icon-blocked"
                          onClick={this.props.disabledVal.bind(
                            this,
                            locations,
                            itemData
                          )}
                        ></i>
                      </a>
                    ) : (
                      <a>
                        <i
                          className="icon-play4"
                          onClick={this.props.disabledVal.bind(
                            this,
                            locations,
                            itemData
                          )}
                        ></i>
                      </a>
                    )}
                    {/* <Divider />
                    <a>
                        <i
                          style={{color:itemData&&itemData.order=='before'?'#a9a9a9':''}}
                          className="icon-move-up"
                          onClick={this.props.beforeOrder.bind(
                            this,
                            locations,
                            itemData
                          )}
                        ></i>
                      </a>
                      <Divider />
                    <a>
                        <i
                         style={{color:itemData&&itemData.order=='after'?'#a9a9a9':''}}
                          className="icon-move-down"
                          onClick={this.props.afterOrder.bind(
                            this,
                            locations,
                            itemData
                          )}
                        ></i>
                      </a> */}
                  </span>
                )}
              </Col>
            )}
          </Row>
        </div>
      )
    );
  }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值