From 69e9c981a278aea1538b3e38edfacaca04b9e3d3 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Mon, 16 Mar 2020 12:20:55 +0800 Subject: [PATCH] add events-setter --- packages/editor/src/config/setters.ts | 3 +- .../events-setter/event-dialog.tsx | 129 ++++++++ .../builtin-setters/events-setter/index.tsx | 310 ++++++++++++++++++ .../events-setter/native-events.ts | 56 ++++ .../builtin-setters/events-setter/style.less | 155 +++++++++ .../src/register-transducer.ts | 29 ++ 6 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx create mode 100644 packages/plugin-settings/src/builtin-setters/events-setter/index.tsx create mode 100644 packages/plugin-settings/src/builtin-setters/events-setter/native-events.ts create mode 100644 packages/plugin-settings/src/builtin-setters/events-setter/style.less diff --git a/packages/editor/src/config/setters.ts b/packages/editor/src/config/setters.ts index dc3ae6cb0..ba8f607c0 100644 --- a/packages/editor/src/config/setters.ts +++ b/packages/editor/src/config/setters.ts @@ -1,5 +1,6 @@ import { Input } from '@alifd/next'; import NumberSetter from '../../../plugin-setters/number-setter'; +import EventsSetter from '../../../plugin-settings/src/builtin-setters/events-setter' import { registerSetter } from '../../../plugin-settings/src'; import { createElement } from 'react'; @@ -13,7 +14,7 @@ registerSetter('ClassNameSetter', () => { ); }); -registerSetter('EventsSetter', Input); +registerSetter('EventsSetter', EventsSetter); registerSetter('StringSetter', { component: Input, props: { placeholder: '请输入' } }); diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx b/packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx new file mode 100644 index 000000000..7303f3649 --- /dev/null +++ b/packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx @@ -0,0 +1,129 @@ +import { Component, isValidElement, ReactElement, ReactNode } from 'react'; +import { Dialog, Search, Input } from '@alifd/next'; +import './style.less'; + +export default class EventDialog extends Component<{ + dialigVisiable:?Boolean, + closeDialog:?()=>void, + submitDialog:?()=>void, + bindEventName:?String +}> { + + private eventList : Array = [ + { + name: 'getData', + }, + { + name: 'deleteData', + }, + { + name: 'initData', + }, + { + name: 'editData', + }, + { + name: 'submitData' + }, + ] + + state = { + selectedEventName:'', + eventName:'' + }; + + componentWillReceiveProps(nextProps){ + this.setState({ + eventName:nextProps.bindEventName + }) + } + + initEventName = () => { + const {bindEventName} = this.props; + let eventName = bindEventName; + this.eventList.map((item)=>{ + if (item.name === eventName){ + eventName = `${eventName}_new`; + } + }) + + this.setState({ + eventName + }) + } + + onInputChange = (eventName:String) => { + this.setState({ + eventName + }) + } + + onSelectItem = (eventName:String) => { + this.setState({ + selectedEventName:eventName + }) + + // 为空是新建事件 + if (eventName === ''){ + this.initEventName() + }else{ + this.setState({ + selectedEventName:eventName, + eventName + }) + } + } + + onSearchEvent = (searchEventName:String) => { + + } + + onOk = () => { + this.props.submitDialog(this.state.eventName); + } + + + render() { + const { dialigVisiable, closeDialog} = this.props; + const {selectedEventName,eventName} = this.state; + return ( + +
+
+
事件选择
+ +
+
    +
  • 内置函数
  • +
  • 组件事件
  • +
+ +
+
+ + +
    +
  • this.onSelectItem('')}>新建事件
  • + { + this.eventList.map((item,index)=>
  • this.onSelectItem(item.name)}>{item.name}
  • ) + } +
+
+
+
+
+ +
+
事件名称
+
+ +
+ +
参数设置
+ +
+
+
+ ); + } +} diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/index.tsx b/packages/plugin-settings/src/builtin-setters/events-setter/index.tsx new file mode 100644 index 000000000..34e7f482d --- /dev/null +++ b/packages/plugin-settings/src/builtin-setters/events-setter/index.tsx @@ -0,0 +1,310 @@ +import { Component, isValidElement, ReactElement, ReactNode } from 'react'; +import { Radio, Menu, Table, Icon, Dialog } from '@alifd/next'; +import nativeEvents from './native-events'; + +import './style.less'; +import EventDialog from './event-dialog'; +const { SubMenu, Item, Group, Divider } = Menu; +const RadioGroup = Radio.Group; + +const EVENT_CONTENTS = { + COMPONENT_EVENT: 'componentEvent', + NATIVE_EVENT: 'nativeEvent', + LIFE_CYCLE_EVENT: 'lifeCycleEvent', +}; + +const DEFINITION_EVENT_TYPE = { + EVENTS: 'events', + NATIVE_EVENTS: 'nativeEvents', + LIFE_CYCLE_EVENT: 'lifeCycleEvent', +}; + +export default class EventsSetter extends Component<{}> { + state = { + showEventList: false, + eventBtns: [], + eventList: [], + selectType: null, + nativeEventList: [], + lifeCycleEventList: [], + eventDataList: [], + isShowEventDialog: false, + bindEventName: '', + relatedEventName: '', + }; + + componentWillMount() { + this.initEventBtns(); + this.initEventList(); + } + + /** + * 初始化事件按钮 + */ + initEventBtns() { + const { prop } = this.props; + const { definition } = prop.extraProps; + let isRoot = false; + definition.map(item => { + if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT) { + isRoot = true; + } + }); + + this.setState({ + eventBtns: !isRoot + ? [ + { + value: EVENT_CONTENTS.COMPONENT_EVENT, + label: '组件自带事件', + }, + { + value: EVENT_CONTENTS.NATIVE_EVENT, + label: '原生事件', + }, + ] + : [ + { + value: EVENT_CONTENTS.LIFE_CYCLE_EVENT, + label: '生命周期', + }, + ], + }); + } + + initEventList() { + const { definition } = this.props.prop.extraProps; + let nativeEventList = []; + definition.map(item => { + if (item.type === DEFINITION_EVENT_TYPE.EVENTS) { + this.setState({ + eventList: item.list, + }); + } + + if (item.type === DEFINITION_EVENT_TYPE.NATIVE_EVENTS) { + nativeEventList = item.list; + } + + if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT){ + this.setState({ + lifeCycleEventList:item.list + }) + } + }); + + if (nativeEventList.length == 0) { + nativeEventList = nativeEvents; + this.setState({ + nativeEventList, + }); + } + } + + /** + * 渲染事件信息 + */ + renderEventInfoCell = (value, index, record) => { + let eventTagText = ''; + if (record.type === EVENT_CONTENTS.NATIVE_EVENT) { + eventTagText = '原'; + } else if (record.type === EVENT_CONTENTS.COMPONENT_EVENT) { + eventTagText = '组'; + } else if (record.type === EVENT_CONTENTS.LIFE_CYCLE_EVENT) { + eventTagText = '生'; + } + return ( +
+
+
{eventTagText}
+ {record.name} +
+
+ + {record.relatedEventName || ''} +
+
+ ); + }; + + /** + * 渲染事件操作项 + */ + renderEventOperateCell = (eventName: String) => { + return ( +
+ this.openDialog(eventName)} + /> + this.openDeleteEventDialog(eventName)} /> +
+ ); + }; + + updateEventListStatus = (eventName: String, unDisabled: boolean) => { + const { eventList, nativeEventList } = this.state; + eventList.map(item => { + if (item.name === eventName) { + item.disabled = !unDisabled; + } + }); + + nativeEventList.map(item => { + item.eventList.map(itemData => { + if (itemData.name === eventName) { + itemData.disabled = !unDisabled; + } + }); + }); + }; + + onRadioChange = value => { + this.setState({ + selectType: value, + }); + }; + + onEventMenuClick = (eventName: String) => { + const { selectType, eventDataList } = this.state; + eventDataList.push({ + type: selectType, + name: eventName, + }); + + this.setState({ + eventDataList, + }); + + this.updateEventListStatus(eventName); + this.closeEventMenu(); + this.openDialog(eventName); + }; + + closeEventMenu = () => { + if (this.state.selectType !== null) { + this.setState({ + selectType: null, + }); + } + }; + + openDeleteEventDialog = (eventName: String) => { + this.deleteEvent(eventName); + // Dialog.confirm({ + // title: '删除事件', + // content: '确定删除当前事件吗', + // onOk: () => this.deleteEvent(eventName), + // }); + }; + + deleteEvent = (eventName: String) => { + const { eventDataList } = this.state; + eventDataList.map((item, index) => { + if (item.name === eventName) { + eventDataList.splice(index, 1); + } + }); + + this.setState({ + eventDataList, + }); + + this.updateEventListStatus(eventName, true); + }; + + openDialog = (bindEventName: String) => { + this.setState({ + isShowEventDialog: true, + bindEventName, + }); + }; + + closeDialog = () => { + this.setState({ + isShowEventDialog: false, + }); + }; + + submitDialog = (relatedEventName: String) => { + const { bindEventName } = this.state; + const { eventDataList } = this.state; + eventDataList.map(item => { + if (item.name === bindEventName) { + item.relatedEventName = relatedEventName; + } + }); + + this.closeDialog(); + }; + + render() { + const { + eventBtns, + eventList, + nativeEventList, + lifeCycleEventList, + selectType, + eventDataList, + isShowEventDialog, + bindEventName, + } = this.state; + + let showEventList = (lifeCycleEventList.length>0?lifeCycleEventList:eventList); + return ( +
+
+ 点击选择事件类型 +
+ + + {selectType && selectType != EVENT_CONTENTS.NATIVE_EVENT && ( + + {showEventList.map((item, index) => ( + + {item.name} + + ))} + + )} + + {selectType && selectType === EVENT_CONTENTS.NATIVE_EVENT && ( + + {nativeEventList.map((item, index) => ( + + {item.eventList.map(item => ( + + {item.name} + + ))} + + ))} + + )} + +
+ + + +
+
+ + +
+ ); + } +} diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/native-events.ts b/packages/plugin-settings/src/builtin-setters/events-setter/native-events.ts new file mode 100644 index 000000000..9bf6c5ae5 --- /dev/null +++ b/packages/plugin-settings/src/builtin-setters/events-setter/native-events.ts @@ -0,0 +1,56 @@ +export default [ + { + category: 'commonlyEvent', + name: '常用事件', + eventList: [ + { name: 'onClick' }, + { name: 'onChange' }, + { name: 'onInput' }, + { name: 'onSelect' }, + { name: 'onSubmit' }, + { name: 'onReset' }, + { name: 'onFocus' }, + { name: 'onBlur' }, + { name: 'onScroll' }, + { name: 'onLoad' }, + { name: 'onError' }, + ], + }, + { + category: 'keybordEvent', + name: '键盘事件', + eventList: [{ name: 'onKeyDown' }, { name: 'onKeyPress' }, { name: 'onKeyUp' }], + }, + { + category: 'mouseEvent', + name: '鼠标事件', + eventList: [ + { name: 'onDoubleClick' }, + { name: 'onDrag' }, + { name: 'onDragEnd' }, + { name: 'onDragEnter' }, + { name: 'onDragExit' }, + { name: 'onDragLeave' }, + { name: 'onDragOver' }, + { name: 'onDragStart' }, + { name: 'onDrop' }, + { name: 'onMouseDown' }, + { name: 'onMouseEnter' }, + { name: 'onMouseLeave' }, + { name: 'onMouseMove' }, + { name: 'onMouseOut' }, + { name: 'onMouseOver' }, + { name: 'onMouseUp' }, + ], + }, + { + category: 'animateEvent', + name: '动画事件', + eventList: [ + { name: 'onAnimationStart' }, + { name: 'onAnimationEnd' }, + { name: 'onAnimationItration' }, + { name: 'onTransitionEnd' }, + ], + }, +]; diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/style.less b/packages/plugin-settings/src/builtin-setters/events-setter/style.less new file mode 100644 index 000000000..625129486 --- /dev/null +++ b/packages/plugin-settings/src/builtin-setters/events-setter/style.less @@ -0,0 +1,155 @@ +.event-body { + padding: 0 10px 0 10px; + position: relative; + min-height: 450px; + + .event-title { + height: 30px; + line-height: 30px; + margin-bottom: 10px; + } + + + .next-radio-group { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + } + + .next-radio-group label { + -webkit-box-flex: 1; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + text-align: center; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + + .event-cell { + padding-left: 25px; + position: relative; + font-size: 12px; + } + + .event-type-tag { + position: absolute; + width: 20px; + height: 20px; + left: 0px; + top: -2px; + border-radius: 50%; + line-height: 20px; + text-align: center; + color: #ffffff; + background-color: #2077ff; + } + + .related-icon { + margin-right: 5px; + } + + .related-event-name { + color: #2077ff; + cursor: pointer; + } + + + .event-menu { + max-height: 300px; + width: 230px; + overflow-x: hidden; + position: absolute; + top: 67px; + left: 10px; + z-index: 10; + } + + .event-table { + margin-top: 20px; + } + + .event-operate-icon { + cursor: pointer; + } + + .event-operate-icon:hover { + color: #0079f2; + } +} + + +.event-dialog-body { + width: 800px; + height: 450px; + + + .dialog-small-title { + font-weight: 700; + margin-bottom: 8px; + color: rgba(0, 0, 0); + } + + .dialog-left-container { + float: left; + + .dialog-left-context { + width: 268px; + height: 392px; + border: 1px solid rgba(31, 56, 88, .3); + border-radius: 3px; + + .event-type-container { + width: 110px; + height: 390px; + border-right: 1px solid rgba(31, 56, 88, .3); + float: left; + } + + .select-item { + font-size: 12px; + height: 28px; + line-height: 28px; + padding: 0 30px 0 12px; + cursor: pointer; + position: relative; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .select-item-active { + background: rgba(31, 56, 88, .06); + } + + .event-select-container { + width: 156px; + float: left; + + .event-search-box { + width: 135px; + margin: 10px; + } + } + + .event-list { + overflow-y: auto; + overflow-x: hidden; + height: 342px; + } + } + } + + .dialog-right-container { + width: 530px; + padding-left: 20px; + float: left; + + .event-input-container { + margin-bottom: 20px; + } + } +} diff --git a/packages/plugin-settings/src/register-transducer.ts b/packages/plugin-settings/src/register-transducer.ts index 0e634cb48..165ec1c3c 100644 --- a/packages/plugin-settings/src/register-transducer.ts +++ b/packages/plugin-settings/src/register-transducer.ts @@ -386,6 +386,35 @@ registerMetadataTransducer((metadata) => { definition: [] } }, + + // 先简单mock一下 + definition:[ + // { + // type: 'lifeCycleEvent', // 平台配置的,一般只有根节点才会配置 + // title: '生命周期', + // list: [{ + // title: '装载时', + // name: 'componentDidMount' + // },{ + // title: '卸载时', + // name: 'componentWillUnmount' + // }] + // }, + { + type: 'events', // 组件自定义的 + list: [{ + name:'onClick', + title:'点击回调' + }, + { + name:'onChange', + title:'变更回调' + }, + { + name:'onSubmit' + }] + }], + getValue(field: SettingField) { return []; },