闪烁问题,是由于没有用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}
<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>
)
);
}
}