import * as classNames from "classnames" import { Connect } from "dob-react" import * as _ from "lodash" import * as React from "react" import * as ReactDOM from "react-dom" import { StoreProps } from "../../../stores" import { addClass, hasClass, removeClass } from "../../../utils/dom" import * as Style from "./edit-helper.style" import { Props, State } from "./edit-helper.type" // 注入全局样式,辅助编辑器 Style.injectGlob() /** * 一个辅助编辑状态的外壳,内部包裹实际渲染的组件 */ class EditHelper extends React.Component { public static defaultProps = new Props() public state = new State() /** * 暴露内层组件实例 */ public wrappedInstance: React.ReactInstance /** * 组件的类 */ private componentClass: React.ComponentClass /** * 组件实例的信息 */ private instanceInfo: InstanceInfo /** * 当前组件 dom 对象 */ private domInstance: HTMLElement /** * 当前实例设置信息 */ private setting: IGaeaSetting /** * 当前实例默认配置 */ private defaultProps: IDefaultProps public componentWillMount() { this.instanceInfo = this.props.stores.ViewportStore.instances.get(this.props.instanceKey) this.componentClass = this.props.actions.ApplicationAction.getComponentClassByKey(this.instanceInfo.gaeaKey) this.setting = this.props.actions.ApplicationAction.getSettingByInstance(this.instanceInfo) this.defaultProps = this.props.actions.ApplicationAction.getDefaultPropsByInstance(this.instanceInfo) } public componentDidMount() { this.domInstance = ReactDOM.findDOMNode(this.wrappedInstance) as HTMLElement // 绑定监听 this.domInstance.addEventListener("mouseover", this.handleMouseOver) this.domInstance.addEventListener("click", this.handleClick) this.setLayoutClassIfCanDragIn() addClass(this.domInstance, "gaea-draggable") // 设置此实例的 dom 节点 this.props.actions.ViewportAction.setDomInstance(this.props.instanceKey, this.domInstance) // 如果自己是布局元素, 给子元素绑定 sortable if (this.setting.isContainer) { // 添加可排序拖拽 this.props.actions.ViewportAction.registerInnerDrag(this.props.instanceKey, this.domInstance, { draggable: ".gaea-draggable" }) } // 当组件 props 设置改变时,会触发,强制刷新 this.props.actions.EventAction.on(`${this.props.stores.EventStore.instanceUpdate}.${this.props.instanceKey}`, this.forceRender) } public componentWillUnmount() { this.props.actions.EventAction.off(`${this.props.stores.EventStore.instanceUpdate}.${this.props.instanceKey}`, this.forceRender) } public forceRender = () => { this.forceUpdate() } public handleMouseOver = (event: MouseEvent) => { event.stopPropagation() this.props.actions.EventAction.emit(this.props.stores.EventStore.mouseHoveringComponent, { instanceKey: this.props.instanceKey, type: "instance" }) this.props.actions.ViewportAction.setCurrentHoverInstanceKey(this.props.instanceKey) } public handleClick = (event: MouseEvent) => { event.stopPropagation() const setting = this.props.actions.ApplicationAction.getSettingByInstance(this.instanceInfo) // 将当前组件设置为正在编辑状态 this.props.actions.ViewportAction.setCurrentEditInstanceKey(this.props.instanceKey) } /** * 如果是布局容器,且不是最外层元素,添加 gaea-layout class,用于添加布局样式 */ public setLayoutClassIfCanDragIn = () => { if (this.setting.isContainer && this.instanceInfo.parentInstanceKey !== null) { addClass(this.domInstance, "gaea-container") } } public render() { // 子元素 let childs: Array> = null // 布局元素可以有子元素 if (this.setting.isContainer) { childs = this.instanceInfo.childs.map(childKey => { return ( ) }) } const wrapProps: any = _.merge({}, this.defaultProps, { ...this.instanceInfo.data.props }, { ref: (ref: React.ReactInstance) => { this.wrappedInstance = ref } }) return React.createElement(this.componentClass, wrapProps, childs) } } const ConnectedEditHelper = Connect(EditHelper) export default ConnectedEditHelper