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"
@scroll="handleScroll"
:render="item=>item.title"
:disabled="disabled"
>
</a-transfer>
<a-switch unCheckedChildren="disabled" checkedChildren="disabled" :checked="disabled" @change="handleDisable" />
</template>
<script>
export default {
@ -35,20 +37,21 @@ export default {
});
}
const targetKeys = mockData
const oriTargetKeys = mockData
.filter(item => +item.key % 3 > 1)
.map(item => item.key);
return {
mockData,
targetKeys,
targetKeys: oriTargetKeys,
selectedKeys: ['1', '4'],
disabled: false,
}
},
methods: {
handleChange(nextTargetKeys, direction, moveKeys) {
this.targetKeys = nextTargetKeys
console.log('targetKeys: ', this.targetKeys);
console.log('targetKeys: ', nextTargetKeys);
console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys);
},
@ -62,6 +65,9 @@ export default {
console.log('direction:', direction);
console.log('target:', e.target);
},
handleDisable(disabled) {
this.disabled = disabled
},
},
}
</script>

View File

@ -3,14 +3,14 @@
| 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}\] | \[] |
| disabled | Whether disabled transfer | boolean | false |
| 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" | |
| 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 | |
| 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\[] | ['>', '<'] |
| 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\[] | \[] |
| 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\[] | \[] |

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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