Skip to content
This repository has been archived by the owner on Apr 9, 2020. It is now read-only.

Commit

Permalink
feat: 支持排序
Browse files Browse the repository at this point in the history
  • Loading branch information
ltaoo committed Feb 23, 2018
1 parent 4e2718d commit 6ea4f73
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 60 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"file-saver": "^1.3.3",
"fs-extra": "3.0.1",
"html-webpack-plugin": "2.29.0",
"immutability-helper": "^2.6.5",
"jest": "20.0.4",
"jszip": "^3.1.5",
"monaco-editor": "^0.10.1",
Expand Down
2 changes: 2 additions & 0 deletions src/common/actions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const ADD_COMPONENT = 'ADD_COMPONENT';
export const UPDATE_COMPONENT = 'UPDATE_COMPONENT';
export const REMOVE_COMPONENT = 'REMOVE_COMPONENT';

export const SORT = 'SORT';
1 change: 1 addition & 0 deletions src/common/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const ItemTypes = {
FIELD: 'FIELD',
CONTAINER: 'CONTAINER',
OTHER: 'OTHER',
};
3 changes: 2 additions & 1 deletion src/components/Container/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,11 @@ class Container extends React.Component {
*/
renderComponent = () => {
const { instances = [] } = this.props;
return instances.map((instance) => {
return instances.map((instance, index) => {
return (
<Field
key={instance.uuid}
index={index}
item={instance}
// 用在获取嵌套组件代码的时候,只当 root === true 时才获取代码
root
Expand Down
227 changes: 173 additions & 54 deletions src/components/Field/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/**
* @file Field - 即一个字段,由自身维护一个模态框、源码字符串
* @file Field - 即一个组件,由自身维护一个模态框
* @author wuya
*/
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import { Form, Modal, Icon, Checkbox, Col, Select } from 'antd';
import { DropTarget, DragSource } from 'react-dnd';

import store from '../../store';
import {
UPDATE_COMPONENT
import {
UPDATE_COMPONENT,
SORT,
} from '../../common/actions';
import { ItemTypes } from '../../common/constants';
import createSource from '../../common/create-source';
import ComponentEditor from '../Editor';

Expand All @@ -27,17 +31,17 @@ class Field extends React.Component {
/**
* 更新属性
*/
updateProps = (values) => {
updateProps = values => {
const { item } = this.props;
store.dispatch({
type: UPDATE_COMPONENT,
payload: {
payload: {
item,
values,
},
});
this.hideEditorModal();
}
};
/**
* 移除组件
*/
Expand All @@ -52,31 +56,36 @@ class Field extends React.Component {
const { props: changedProps } = this.state;
const { item, root } = this.props;
const { props } = item;
const newProps = Object.assign({}, {...props}, changedProps);
const newProps = Object.assign({}, { ...props }, changedProps);
const code = root ? createSource(item, newProps) : '';
console.log(code);
}
};
showEditorModal = () => {
this.setState({
editorModalVisible: true,
});
}
};
hideEditorModal = () => {
this.setState({
editorModalVisible: false,
});
}
};
/**
* 选中 Row,接下来选择的组件都会填充到该组件内
*/
selectRow = (e) => {
selectRow = e => {
const checked = e.target.checked;
const { item } = this.props;
this.props.switchContainer(item, checked);
}
};
render() {
const { editorModalVisible } = this.state;
const { form, item } = this.props;
const {
form,
item,
connectDragSource,
connectDropTarget,
} = this.props;

const { getFieldDecorator } = form;
const {
Expand All @@ -95,19 +104,22 @@ class Field extends React.Component {
rules,
initialValue,
labelCol,
wrapperCol
wrapperCol,
} = fieldProps;

const childrenComponent = children.length > 0 ? children.map((child, i) => {
return (
<WrappedField
key={child.uuid}
item={child}
removeComponent={this.removeComponent}
switchContainer={this.props.switchContainer}
/>
);
}) : null;
const childrenComponent =
children.length > 0
? children.map((child, i) => {
return (
<WrappedField
key={child.uuid}
item={child}
removeComponent={this.removeComponent}
switchContainer={this.props.switchContainer}
/>
);
})
: null;

// todo: 使用策略模式拆分,对应的策略从 instanceObj 中读取,并且该部分逻辑在 create-source 以及 renderComponent 中也要用到
let instanceCom = null;
Expand All @@ -118,27 +130,47 @@ class Field extends React.Component {
instanceCom = <div>{childrenComponent}</div>;
} else if (Tag === 'Select') {
const { options } = item;
const chidlrenOptions = options.map((option, i) => <Option key={i} value={option.value}>{option.label}</Option>);
const chidlrenOptions = options.map((option, i) => (
<Option key={i} value={option.value}>
{option.label}
</Option>
));
instanceCom = <Component {...props}>{chidlrenOptions}</Component>;
} else if (Tag === 'CheckboxGroup' || Tag === 'RadioGroup' || Tag === 'Cascader') {
} else if (
Tag === 'CheckboxGroup' ||
Tag === 'RadioGroup' ||
Tag === 'Cascader'
) {
const { options } = item;
const newProps = Object.assign({}, {...props}, {
options,
form: this.props.form,
});
instanceCom = <Component {...newProps}></Component>;
const newProps = Object.assign(
{},
{ ...props },
{
options,
form: this.props.form,
},
);
instanceCom = <Component {...newProps} />;
} else if (Tag === 'Upload') {
const { Component: Tag, props: childProps } = item.children[0];
instanceCom = <Component {...props}><Tag {...childProps} /></Component>;
instanceCom = (
<Component {...props}>
<Tag {...childProps} />
</Component>
);
} else if (Tag === 'Table') {
const { columns, dataSource } = item;
const newProps = Object.assign({}, {...props}, {
columns,
dataSource,
});
instanceCom = <Component {...newProps}></Component>;
const newProps = Object.assign(
{},
{ ...props },
{
columns,
dataSource,
},
);
instanceCom = <Component {...newProps} />;
} else {
instanceCom = <Component {...props}></Component>;
instanceCom = <Component {...props} />;
}
const modal = (
<Modal
Expand All @@ -148,10 +180,7 @@ class Field extends React.Component {
onCancel={this.hideEditorModal}
footer={null}
>
<ComponentEditor
submit={this.updateProps}
instance={item}
/>
<ComponentEditor submit={this.updateProps} instance={item} />
</Modal>
);
const operators = (
Expand All @@ -162,7 +191,11 @@ class Field extends React.Component {
<div className="edit__btn" onClick={this.removeComponent}>
<Icon type="delete" />
</div>
{layout && <Checkbox onChange={this.selectRow}>勾选后会将组件添加到内部</Checkbox>}
{layout && (
<Checkbox onChange={this.selectRow}>
勾选后会将组件添加到内部
</Checkbox>
)}
</div>
);
// Button 要使用 Form.Item 布局但是不是字段,所以判断下要不要 getFieldDecorator
Expand All @@ -176,29 +209,115 @@ class Field extends React.Component {
<div className="field">
<div className="edit__wrapper">
{operators}
{isField ? <FormItem label={title} labelCol={labelCol} wrapperCol={wrapperCol}>
{
fieldInstance
}
</FormItem>
: instanceCom}
{isField ? (
<FormItem label={title} labelCol={labelCol} wrapperCol={wrapperCol}>
{fieldInstance}
</FormItem>
) : (
instanceCom
)}
</div>
{modal}
</div>
);
if (item.label === 'Col') {
return <Col {...props}>
{content}
</Col>
return <Col {...props}>{content}</Col>;
}
return content;
return connectDropTarget(connectDragSource(content));
}
}

Field.PropType = {
item: PropTypes.object,
isDragging: PropTypes.bool.isRequired,
connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
};
const fieldSource = {
beginDrag(props) {
return {
id: props.id,
index: props.index,
};
},
};
/**
* Implements the drag source contract.
*/
const fieldTarget = {
hover(props, monitor, component) {
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
console.log(dragIndex, hoverIndex);
// 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);
store.dispatch({
type: SORT,
payload: {
dragIndex,
hoverIndex,
},
});
// console.log(dragIndex, hoverIndex);

// 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;
},
};

/**
* Specifies the props to inject into your component.
*/
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
};
}

function dropConnect(connect) {
return {
connectDropTarget: connect.dropTarget(),
};
}

// 在 Field 内渲染 Field 没有 form 属性
const WrappedField = Form.create()(Field);
export default WrappedField;

export default DropTarget(ItemTypes.OTHER, fieldTarget, dropConnect)(
DragSource(ItemTypes.OTHER, fieldSource, collect)(WrappedField),
);
Loading

0 comments on commit 6ea4f73

Please sign in to comment.