添加用户选择结果展示组件

This commit is contained in:
2betop 2020-05-12 11:41:59 +08:00
parent 080dbe33a7
commit 25075b2298
7 changed files with 243 additions and 1 deletions

View File

@ -809,7 +809,7 @@ export default {
label: false,
value: 'none',
// mode: 'inline',
columnClassName: 'v-middle w-sm no-grow',
columnClassName: 'v-middle w-ssm no-grow',
options: [
{
label: '不重复',

View File

@ -1147,6 +1147,10 @@
height: 90px;
}
.w-ssm {
width: 120px;
}
.w-sm {
width: 150px;
}
@ -1155,6 +1159,10 @@
height: 150px;
}
.h-ssm {
height: 120px;
}
.w {
width: 200px;
}

View File

@ -0,0 +1,72 @@
.#{$ns}Selections {
height: 100%;
min-width: px2rem(200px);
position: relative;
display: flex;
flex-direction: column;
&-title {
height: $Form-input-height;
background: $Table-thead-bg;
font-size: $Form-input-fontSize;
padding: (
$Form-input-height - $Form-input-lineHeight * $Form-input-fontSize
)/2 $gap-sm;
}
&-placeholder {
color: $Form-input-placeholderColor;
text-align: center;
width: 100%;
flex-basis: $Form-input-height;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
&-items {
flex-grow: 1;
height: 0;
overflow: auto;
}
&-item {
display: flex;
flex-direction: row;
height: $Form-input-height;
line-height: $Form-input-lineHeight;
font-size: $Form-input-fontSize;
padding: (
$Form-input-height - $Form-input-lineHeight * $Form-input-fontSize
)/2 $gap-sm;
> label {
flex-basis: px2rem(50px);
flex-grow: 1;
}
> .#{$ns}Selections-dragbar {
width: px2rem(20px);
position: relative;
left: px2rem(-5px);
color: $icon-color;
cursor: move;
}
&--dragging {
> * {
opacity: 0.2;
}
}
}
&-delBtn {
color: $icon-color;
cursor: pointer;
&:hover {
color: $icon-onHover-color;
}
}
}

View File

@ -550,6 +550,7 @@ $Combo--horizontal-dragger-top: px2rem(5px);
@import '../components/form/switch';
@import '../components/form/number';
@import '../components/form/select';
@import '../components/form/selections';
@import '../components/form/list';
@import '../components/form/location';
@import '../components/form/matrix';

View File

@ -213,6 +213,7 @@ pre {
@import '../components/form/switch';
@import '../components/form/number';
@import '../components/form/select';
@import '../components/form/selections';
@import '../components/form/list';
@import '../components/form/location';
@import '../components/form/matrix';

View File

@ -78,6 +78,7 @@ $Form-input-borderColor: #cfdadd;
@import '../components/form/switch';
@import '../components/form/number';
@import '../components/form/select';
@import '../components/form/selections';
@import '../components/form/list';
@import '../components/form/location';
@import '../components/form/matrix';

View File

@ -0,0 +1,159 @@
/**
*
*/
import React from 'react';
import {Option} from './Select';
import {ThemeProps, themeable} from '../theme';
import {Icon} from './icons';
import {autobind, guid} from '../utils/helper';
import Sortable from 'sortablejs';
import { findDOMNode } from 'react-dom';
export interface SelectionsProps extends ThemeProps {
className?: string;
value?: Array<Option>;
onChange?: (value: Array<Option>) => void;
sortable?: boolean;
disabled?: boolean;
title?: string;
placeholder: string;
optionRender: (option: Option) => JSX.Element;
itemClassName?: string;
}
export class Selections extends React.Component<SelectionsProps> {
static defaultProps: Pick<SelectionsProps, 'placeholder' | 'optionRender'> = {
placeholder: '请先选择数据',
optionRender: (option: Option) => <span>{option.label}</span>
};
id = guid();
sortable?: Sortable;
componentDidMount() {
this.props.sortable && this.initSortable();
}
componentDidUpdate() {
if (this.props.sortable) {
this.sortable || this.initSortable();
} else {
this.desposeSortable();
}
}
componentWillUnmount() {
this.desposeSortable();
}
@autobind
handleRemove(e: React.MouseEvent<HTMLElement>) {
const index = parseInt(e.currentTarget.getAttribute('data-index')!, 10);
const {value, onChange} = this.props;
if (!Array.isArray(value)) {
return;
}
const newValue = value.concat();
newValue.splice(index, 1);
onChange?.(newValue);
}
initSortable() {
const ns = this.props.classPrefix;
const dom = findDOMNode(this) as HTMLElement;
const container = dom.querySelector(`.${ns}Selections-items`) as HTMLElement;
if (!container) {
return;
}
this.sortable = new Sortable(
container,
{
group: `selections-${this.id}`,
animation: 150,
handle: `.${ns}Selections-dragbar`,
ghostClass: `${ns}Selections-item--dragging`,
onEnd: (e: any) => {
// 没有移动
if (e.newIndex === e.oldIndex) {
return;
}
// 换回来
const parent = e.to as HTMLElement;
if (e.newIndex < e.oldIndex && e.oldIndex < parent.childNodes.length - 1) {
parent.insertBefore(e.item, parent.childNodes[e.oldIndex + 1]);
} else if (e.oldIndex < parent.childNodes.length - 1) {
parent.insertBefore(e.item, parent.childNodes[e.oldIndex]);
} else {
parent.appendChild(e.item);
}
const value = this.props.value;
if (!Array.isArray(value)) {
return;
}
const newValue = value.concat();
newValue.splice(e.newIndex, 0, newValue.splice(e.oldIndex, 1)[0]);
this.props.onChange?.(newValue);
}
}
);
}
desposeSortable() {
this.sortable?.destroy();
delete this.sortable;
}
render() {
const {
classnames: cx,
className,
value,
placeholder,
optionRender,
disabled,
title,
itemClassName,
sortable
} = this.props;
return (
<div className={cx('Selections', className)}>
{title ? <div className={cx('Selections-title')}>{title}</div> : null}
{Array.isArray(value) && value.length ? (
<div className={cx('Selections-items')}>
{value.map((option, index) => (
<div className={cx('Selections-item', itemClassName, option?.className)} key={index}>
{sortable && !disabled ? (
<Icon className={cx('Selections-dragbar')} icon="combo-dragger"/>
) : null}
<label>{optionRender(option)}</label>
{!disabled ? (
<a
className={cx('Selections-delBtn')}
data-index={index}
onClick={this.handleRemove}
>
<Icon icon="close" />
</a>
) : null}
</div>
))}
</div>
) : (
<div className={cx('Selections-placeholder')}>{placeholder}</div>
)}
</div>
);
}
}
export default themeable(Selections);