feat: upadate transfer

pull/309/head
wangxueliang 2018-12-05 20:00:13 +08:00
parent 44d55b329d
commit 86bbeff161
8 changed files with 80 additions and 34 deletions

View File

@ -19,8 +19,10 @@ The most basic usage of `Transfer` involves providing the source data and target
@selectChange="handleSelectChange" @selectChange="handleSelectChange"
@scroll="handleScroll" @scroll="handleScroll"
:render="item=>item.title" :render="item=>item.title"
:disabled="disabled"
> >
</a-transfer> </a-transfer>
<a-switch unCheckedChildren="disabled" checkedChildren="disabled" :checked="disabled" @change="handleDisable" />
</template> </template>
<script> <script>
export default { export default {
@ -35,20 +37,21 @@ export default {
}); });
} }
const targetKeys = mockData const oriTargetKeys = mockData
.filter(item => +item.key % 3 > 1) .filter(item => +item.key % 3 > 1)
.map(item => item.key); .map(item => item.key);
return { return {
mockData, mockData,
targetKeys, targetKeys: oriTargetKeys,
selectedKeys: ['1', '4'], selectedKeys: ['1', '4'],
disabled: false,
} }
}, },
methods: { methods: {
handleChange(nextTargetKeys, direction, moveKeys) { handleChange(nextTargetKeys, direction, moveKeys) {
this.targetKeys = nextTargetKeys this.targetKeys = nextTargetKeys
console.log('targetKeys: ', this.targetKeys); console.log('targetKeys: ', nextTargetKeys);
console.log('direction: ', direction); console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys); console.log('moveKeys: ', moveKeys);
}, },
@ -62,6 +65,9 @@ export default {
console.log('direction:', direction); console.log('direction:', direction);
console.log('target:', e.target); console.log('target:', e.target);
}, },
handleDisable(disabled) {
this.disabled = disabled
},
}, },
} }
</script> </script>

View File

@ -3,14 +3,14 @@
| Property | Description | Type | Default | | Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- | | -------- | ----------- | ---- | ------- |
| dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop. | \[{key: string.isRequired,title: string.isRequired,description: string,disabled: bool}\] | \[] | | dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop. | \[{key: string.isRequired,title: string.isRequired,description: string,disabled: bool}\] | \[] |
| disabled | Whether disabled transfer | boolean | false |
| filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | | | filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | |
| footer | customize the progress dot by setting a scoped slot | slot="footer" slot-scope="props" | | | footer | customize the progress dot by setting a scoped slot | slot="footer" slot-scope="props" | |
| lazy | property of vc-lazy-load for lazy rendering items. Turn off it by set to `false`. | object\|boolean | `{ height: 32, offset: 32 }` | | lazy | property of vc-lazy-load for lazy rendering items. Turn off it by set to `false`. | object\|boolean | `{ height: 32, offset: 32 }` |
| listStyle | A custom CSS style used for rendering the transfer columns. | object | | | listStyle | A custom CSS style used for rendering the transfer columns. | object | |
| notFoundContent | Text to display when a column is empty. | string\|slot | 'The list is empty' | | locale | i18n text including filter, empty text, item unit, etc | object | `{ itemUnit: 'item', itemsUnit: 'items', notFoundContent: 'The list is empty', searchPlaceholder: 'Search here' }` |
| operations | A set of operations that are sorted from bottom to top. | string\[] | ['>', '<'] | | operations | A set of operations that are sorted from bottom to top. | string\[] | ['>', '<'] |
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a element and `value` is for title | Function(record) | | | render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a element and `value` is for title | Function(record) | |
| searchPlaceholder | The hint text of the search box. | string | 'Search here' |
| selectedKeys | A set of keys of selected items. | string\[] | \[] | | selectedKeys | A set of keys of selected items. | string\[] | \[] |
| showSearch | If included, a search box is shown on each column. | boolean | false | | showSearch | If included, a search box is shown on each column. | boolean | false |
| targetKeys | A set of keys of elements that are listed on the right column. | string\[] | \[] | | targetKeys | A set of keys of elements that are listed on the right column. | string\[] | \[] |

View File

@ -1,10 +1,11 @@
import PropTypes from '../_util/vue-types' import PropTypes from '../_util/vue-types'
import { initDefaultProps, getOptionProps, getComponentFromProp } from '../_util/props-util' import { hasProp, initDefaultProps, getOptionProps, getComponentFromProp } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin' import BaseMixin from '../_util/BaseMixin'
import classNames from 'classnames' import classNames from 'classnames'
import List from './list' import List from './list'
import Operation from './operation' import Operation from './operation'
// import Search from './search' // import Search from './search'
import warning from '../_util/warning'
import LocaleReceiver from '../locale-provider/LocaleReceiver' import LocaleReceiver from '../locale-provider/LocaleReceiver'
import defaultLocale from '../locale-provider/default' import defaultLocale from '../locale-provider/default'
@ -23,6 +24,7 @@ export const TransferItem = {
export const TransferProps = { export const TransferProps = {
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
dataSource: PropTypes.arrayOf(PropTypes.shape(TransferItem).loose), dataSource: PropTypes.arrayOf(PropTypes.shape(TransferItem).loose),
disabled: PropTypes.boolean,
targetKeys: PropTypes.arrayOf(PropTypes.string), targetKeys: PropTypes.arrayOf(PropTypes.string),
selectedKeys: PropTypes.arrayOf(PropTypes.string), selectedKeys: PropTypes.arrayOf(PropTypes.string),
render: PropTypes.func, render: PropTypes.func,
@ -34,6 +36,7 @@ export const TransferProps = {
filterOption: PropTypes.func, filterOption: PropTypes.func,
searchPlaceholder: PropTypes.string, searchPlaceholder: PropTypes.string,
notFoundContent: PropTypes.any, notFoundContent: PropTypes.any,
locale: PropTypes.object,
rowKey: PropTypes.func, rowKey: PropTypes.func,
lazy: PropTypes.oneOfType([ lazy: PropTypes.oneOfType([
PropTypes.object, PropTypes.object,
@ -44,7 +47,6 @@ export const TransferProps = {
export const TransferLocale = { export const TransferLocale = {
titles: PropTypes.arrayOf(PropTypes.string), titles: PropTypes.arrayOf(PropTypes.string),
notFoundContent: PropTypes.string, notFoundContent: PropTypes.string,
searchPlaceholder: PropTypes.string,
itemUnit: PropTypes.string, itemUnit: PropTypes.string,
itemsUnit: PropTypes.string, itemsUnit: PropTypes.string,
} }
@ -54,9 +56,16 @@ const Transfer = {
mixins: [BaseMixin], mixins: [BaseMixin],
props: initDefaultProps(TransferProps, { props: initDefaultProps(TransferProps, {
dataSource: [], dataSource: [],
locale: {},
showSearch: false, showSearch: false,
}), }),
data () { data () {
warning(
!(getComponentFromProp(this, 'notFoundContent') || hasProp(this, 'searchPlaceholder')),
'Transfer[notFoundContent] and Transfer[searchPlaceholder] will be removed, ' +
'please use Transfer[locale] instead.',
)
this.separatedDataSource = { this.separatedDataSource = {
leftDataSource: [], leftDataSource: [],
rightDataSource: [], rightDataSource: [],
@ -296,19 +305,33 @@ const Transfer = {
return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys' return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys'
}, },
renderTransfer (locale) { getLocale (transferLocale) {
// Keep old locale props still working.
const oldLocale = {}
const notFoundContent = getComponentFromProp(this, 'notFoundContent')
if (notFoundContent) {
oldLocale.notFoundContent = notFoundContent
}
if (hasProp(this, 'searchPlaceholder')) {
oldLocale.searchPlaceholder = this.$props.searchPlaceholder
}
return ({ ...transferLocale, ...oldLocale, ...this.$props.locale })
},
renderTransfer (transferLocale) {
const props = getOptionProps(this) const props = getOptionProps(this)
const { const {
prefixCls = 'ant-transfer', prefixCls = 'ant-transfer',
disabled,
operations = [], operations = [],
showSearch, showSearch,
searchPlaceholder,
listStyle, listStyle,
operationStyle, operationStyle,
filterOption, filterOption,
lazy, lazy,
} = props } = props
const notFoundContent = getComponentFromProp(this, 'notFoundContent') const locale = this.getLocale(transferLocale)
const { leftFilter, rightFilter, sourceSelectedKeys, targetSelectedKeys, $scopedSlots } = this const { leftFilter, rightFilter, sourceSelectedKeys, targetSelectedKeys, $scopedSlots } = this
const { body, footer } = $scopedSlots const { body, footer } = $scopedSlots
const renderItem = props.render const renderItem = props.render
@ -316,7 +339,7 @@ const Transfer = {
const leftActive = targetSelectedKeys.length > 0 const leftActive = targetSelectedKeys.length > 0
const rightActive = sourceSelectedKeys.length > 0 const rightActive = sourceSelectedKeys.length > 0
const cls = classNames(prefixCls) const cls = classNames(prefixCls, disabled && `${prefixCls}-disabled`)
const titles = this.getTitles(locale) const titles = this.getTitles(locale)
return ( return (
@ -335,14 +358,15 @@ const Transfer = {
handleSelectAll={this.handleLeftSelectAll} handleSelectAll={this.handleLeftSelectAll}
renderItem={renderItem} renderItem={renderItem}
showSearch={showSearch} showSearch={showSearch}
searchPlaceholder={searchPlaceholder || locale.searchPlaceholder}
notFoundContent={notFoundContent || locale.notFoundContent}
itemUnit={locale.itemUnit}
itemsUnit={locale.itemsUnit}
body={body} body={body}
footer={footer} footer={footer}
lazy={lazy} lazy={lazy}
onScroll={this.handleLeftScroll} onScroll={this.handleLeftScroll}
disabled={disabled}
itemUnit={locale.itemUnit}
itemsUnit={locale.itemsUnit}
notFoundContent={locale.notFoundContent}
searchPlaceholder={locale.searchPlaceholder}
/> />
<Operation <Operation
class={`${prefixCls}-operation`} class={`${prefixCls}-operation`}
@ -353,6 +377,7 @@ const Transfer = {
leftArrowText={operations[1]} leftArrowText={operations[1]}
moveToLeft={this.moveToLeft} moveToLeft={this.moveToLeft}
style={operationStyle} style={operationStyle}
disabled={disabled}
/> />
<List <List
prefixCls={`${prefixCls}-list`} prefixCls={`${prefixCls}-list`}
@ -368,14 +393,15 @@ const Transfer = {
handleSelectAll={this.handleRightSelectAll} handleSelectAll={this.handleRightSelectAll}
renderItem={renderItem} renderItem={renderItem}
showSearch={showSearch} showSearch={showSearch}
searchPlaceholder={searchPlaceholder || locale.searchPlaceholder}
notFoundContent={notFoundContent || locale.notFoundContent}
itemUnit={locale.itemUnit}
itemsUnit={locale.itemsUnit}
body={body} body={body}
footer={footer} footer={footer}
lazy={lazy} lazy={lazy}
onScroll={this.handleRightScroll} onScroll={this.handleRightScroll}
disabled={disabled}
itemUnit={locale.itemUnit}
itemsUnit={locale.itemsUnit}
notFoundContent={locale.notFoundContent}
searchPlaceholder={locale.searchPlaceholder}
/> />
</div> </div>
) )

View File

@ -3,14 +3,14 @@
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | \[{key: string.isRequired,title: string.isRequired,description: string,disabled: bool}\]\[] | \[] | | dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | \[{key: string.isRequired,title: string.isRequired,description: string,disabled: bool}\]\[] | \[] |
| disabled | 是否禁用 | boolean | false |
| filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | (inputValue, option): boolean | | | filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | (inputValue, option): boolean | |
| footer | 可以设置为一个 作用域插槽 | slot="footer" slot-scope="props" | | | footer | 可以设置为一个 作用域插槽 | slot="footer" slot-scope="props" | |
| lazy | Transfer 使用了 [vc-lazy-load]优化性能,这里可以设置相关参数。设为 `false` 可以关闭懒加载。 | object\|boolean | `{ height: 32, offset: 32 }` | | lazy | Transfer 使用了 [vc-lazy-load]优化性能,这里可以设置相关参数。设为 `false` 可以关闭懒加载。 | object\|boolean | `{ height: 32, offset: 32 }` |
| listStyle | 两个穿梭框的自定义样式 | object | | | listStyle | 两个穿梭框的自定义样式 | object | |
| notFoundContent | 当列表为空时显示的内容 | string\|slot | '列表为空' | | locale | 各种语言 | object | `{ itemUnit: '项', itemsUnit: '项', notFoundContent: '列表为空', searchPlaceholder: '请输入搜索内容' }` |
| operations | 操作文案集合,顺序从下至上 | string\[] | ['>', '<'] | | operations | 操作文案集合,顺序从下至上 | string\[] | ['>', '<'] |
| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 element。或者返回一个普通对象其中 `label` 字段为 element`value` 字段为 title | Function(record) | | | render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 element。或者返回一个普通对象其中 `label` 字段为 element`value` 字段为 title | Function(record) | |
| searchPlaceholder | 搜索框的默认值 | string | '请输入搜索内容' |
| selectedKeys | 设置哪些项应该被选中 | string\[] | \[] | | selectedKeys | 设置哪些项应该被选中 | string\[] | \[] |
| showSearch | 是否显示搜索框 | boolean | false | | showSearch | 是否显示搜索框 | boolean | false |
| targetKeys | 显示在右侧框数据的key集合 | string\[] | \[] | | targetKeys | 显示在右侧框数据的key集合 | string\[] | \[] |

View File

@ -17,25 +17,34 @@ export default {
]), ]),
checked: PropTypes.bool, checked: PropTypes.bool,
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
disabled: PropTypes.bool,
}, },
name: 'Item', name: 'Item',
render () { render () {
const { renderedText, renderedEl, item, lazy, checked, prefixCls } = this.$props const {
renderedText, renderedEl, item, lazy,
checked, disabled, prefixCls,
} = this.$props
const className = classNames({ const className = classNames({
[`${prefixCls}-content-item`]: true, [`${prefixCls}-content-item`]: true,
[`${prefixCls}-content-item-disabled`]: item.disabled, [`${prefixCls}-content-item-disabled`]: disabled || item.disabled,
}) })
let title
if (typeof renderedText === 'string' || typeof renderedText === 'number') {
title = String(renderedText)
}
const listItem = ( const listItem = (
<li <li
class={className} class={className}
title={renderedText} title={title}
onClick={item.disabled ? noop : () => { onClick={(disabled || item.disabled) ? noop : () => {
this.$emit('click', item) this.$emit('click', item)
}} }}
> >
<Checkbox checked={checked} disabled={item.disabled} /> <Checkbox checked={checked} disabled={disabled || item.disabled} />
<span>{renderedEl}</span> <span>{renderedEl}</span>
</li> </li>
) )

View File

@ -51,6 +51,7 @@ export const TransferListProps = {
PropTypes.bool, PropTypes.bool,
PropTypes.object, PropTypes.object,
]), ]),
disabled: PropTypes.bool,
} }
export default { export default {
@ -179,14 +180,14 @@ export default {
render () { render () {
const { const {
prefixCls, dataSource, titleText, checkedKeys, lazy, prefixCls, dataSource, titleText, checkedKeys, lazy, disabled,
body = noop, footer = noop, showSearch, filter, body, footer, showSearch, filter,
searchPlaceholder, notFoundContent, itemUnit, itemsUnit, searchPlaceholder, notFoundContent, itemUnit, itemsUnit,
} = this.$props } = this.$props
// Custom Layout // Custom Layout
const footerDom = footer({ ...this.$props }) const footerDom = footer && footer({ ...this.$props })
const bodyDom = body({ ...this.$props }) const bodyDom = body && body({ ...this.$props })
const listCls = classNames(prefixCls, { const listCls = classNames(prefixCls, {
[`${prefixCls}-with-footer`]: !!footerDom, [`${prefixCls}-with-footer`]: !!footerDom,
@ -211,6 +212,7 @@ export default {
const checked = checkedKeys.indexOf(item.key) >= 0 const checked = checkedKeys.indexOf(item.key) >= 0
return ( return (
<Item <Item
disabled={disabled}
key={item.key} key={item.key}
item={item} item={item}
lazy={lazy} lazy={lazy}
@ -242,7 +244,7 @@ export default {
}) })
const listBody = bodyDom || ( const listBody = bodyDom || (
<div <div
class={showSearch ? `${prefixCls}-body ${prefixCls}-body-with-search` : `${prefixCls}-body`} class={classNames(showSearch ? `${prefixCls}-body ${prefixCls}-body-with-search` : `${prefixCls}-body`)}
> >
{search} {search}
<transition-group <transition-group
@ -270,6 +272,7 @@ export default {
const checkAllCheckbox = ( const checkAllCheckbox = (
<Checkbox <Checkbox
ref='checkbox' ref='checkbox'
disabled={disabled}
checked={checkedAll} checked={checkedAll}
indeterminate={checkStatus === 'part'} indeterminate={checkStatus === 'part'}
onChange={() => { onChange={() => {

View File

@ -13,6 +13,7 @@ export const TransferOperationProps = {
moveToRight: PropTypes.any, moveToRight: PropTypes.any,
leftActive: PropTypes.bool, leftActive: PropTypes.bool,
rightActive: PropTypes.bool, rightActive: PropTypes.bool,
disabled: PropTypes.bool,
} }
export default { export default {
@ -20,6 +21,7 @@ export default {
props: { ...TransferOperationProps }, props: { ...TransferOperationProps },
render () { render () {
const { const {
disabled,
moveToLeft = noop, moveToLeft = noop,
moveToRight = noop, moveToRight = noop,
leftArrowText = '', leftArrowText = '',
@ -32,7 +34,7 @@ export default {
<Button <Button
type='primary' type='primary'
size='small' size='small'
disabled={!rightActive} disabled={disabled || !rightActive}
onClick={moveToRight} onClick={moveToRight}
icon='right' icon='right'
> >
@ -41,7 +43,7 @@ export default {
<Button <Button
type='primary' type='primary'
size='small' size='small'
disabled={!leftActive} disabled={disabled || !leftActive}
onClick={moveToLeft} onClick={moveToLeft}
icon='left' icon='left'
> >

View File

@ -30,7 +30,7 @@ export default {
const { placeholder, value, prefixCls } = getOptionProps(this) const { placeholder, value, prefixCls } = getOptionProps(this)
const icon = (value && value.length > 0) ? ( const icon = (value && value.length > 0) ? (
<a href='#' class={`${prefixCls}-action`} onClick={this.handleClear2}> <a href='#' class={`${prefixCls}-action`} onClick={this.handleClear2}>
<Icon type='cross-circle' /> <Icon type='close-circle' />
</a> </a>
) : ( ) : (
<span class={`${prefixCls}-action`}><Icon type='search' /></span> <span class={`${prefixCls}-action`}><Icon type='search' /></span>