import * as React from 'react' import * as ReactDOM from 'react-dom' import { dobEvent, IDebugInfo } from 'dob' import { startDebug, stopDebug } from 'dob-react' import * as PropTypes from 'prop-types' import { Props, State } from './tool-box.type' import * as S from './tool-box.style' import { debugContainerId } from '../utils/isomorphic' import { DebugLine } from './debug-line/debug-line.component' import { scrollTo } from '../utils/scroll-to' import * as debounce from 'lodash.debounce' import Icon from '../components/icon/src' export class ToolBox extends React.PureComponent{ static defaultProps = new Props() public state = new State() static contextTypes = { dyDebug: PropTypes.object } static childContextTypes = { dyDebug: PropTypes.object } /** * debugInfos 容器 */ private actionContainerDOM: HTMLElement = null getChildContext() { return { dyDebug: this.context.dyDebug } } public componentDidMount() { dobEvent.on('debug', debugInfo => { this.context.dyDebug.debugInfoMap.set(debugInfo.id, debugInfo) setTimeout(() => { this.forceUpdate() }) }) this.context.dyDebug.event.on('focusActionDetail', this.handleFocusActionDetail) // 在 body 下创建一个放置 debug-box 的节点 const debugContainer = document.createElement("div") debugContainer.id = debugContainerId debugContainer.style.position = 'fixed' debugContainer.style.top = '0px' debugContainer.style.right = '0px' debugContainer.style.bottom = '0px' debugContainer.style.left = '0px' debugContainer.style.pointerEvents = 'none' debugContainer.style.overflow = 'hidden' ReactDOM.findDOMNode(this).appendChild(debugContainer) } public componentWillUnmount() { this.context.dyDebug.event.on('focusActionDetail', this.handleFocusActionDetail) } public render() { return ( {/* provider root */} {this.props.children} {this.renderToolBox()} {this.renderControlButton()} ) } /** * 渲染测试控制按钮 */ private renderControlButton = () => { return ( { this.setState({ showToolBox: !this.state.showToolBox }) }}> {this.state.showToolBox ? : } { if (this.state.useDebug) { stopDebug() } else { startDebug() } this.setState({ useDebug: !this.state.useDebug }) }}> {this.state.useDebug ? : } ) } private getDebugInfoArray = () => { return Array .from((this.context.dyDebug.debugInfoMap as Map).values()) .sort((left, right) => right.id - left.id) } /** * 高亮列表中某个 debugId,对列表来说,移动到这个元素上 */ private handleFocusActionDetail = (debugId: number) => { if (!this.actionContainerDOM) { return } // 找到是列表中第几个元素 const debugInfos = this.getDebugInfoArray() const debugIndex = debugInfos.findIndex(debugInfo => debugInfo.id === debugId) if (debugIndex === -1) { return } const childDOM = this.actionContainerDOM.firstChild.childNodes[debugIndex] as HTMLElement if (!childDOM) { return } this.scrollTopDebugItem(this.actionContainerDOM, childDOM) } private scrollTopDebugItem = debounce((parentDOM: HTMLElement, childDOM: HTMLElement) => { scrollTo(this.actionContainerDOM, childDOM.offsetTop, 50) }, 60) private renderToolBox = () => { if (!this.state.showToolBox) { return null } const debugInfos = this.getDebugInfoArray() const Debugs = debugInfos.map((debugInfo, index) => { return ( ) }) return ( { this.setState({ searchValue: event.currentTarget.value }) }} placeholder="search actions.." /> Clear { if (!this.actionContainerDOM) { this.actionContainerDOM = ReactDOM.findDOMNode(ref) as HTMLElement } }} > {Debugs} ) } private handleClear = () => { this.context.dyDebug.debugInfoMap.clear() setTimeout(() => { this.forceUpdate() }) } }