From b2f3d2fff2051099a010092998631c19b5939db3 Mon Sep 17 00:00:00 2001 From: Echo Date: Sun, 29 Aug 2021 02:05:09 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E7=A9=BF=E6=A2=AD=E6=A1=86.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sites/components/transfer/index.md | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 sites/components/transfer/index.md diff --git a/sites/components/transfer/index.md b/sites/components/transfer/index.md new file mode 100644 index 00000000..d98b3733 --- /dev/null +++ b/sites/components/transfer/index.md @@ -0,0 +1,35 @@ +# Transfer 穿梭框 + +穿梭框。 + + +### 基本用法 + +:::demo + +```vue + + +``` + +::: + +### 尺寸 + + +### API + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | --------- | +| id | `string` | -- | 可选,文本框 id | [基本用法](#基本用法) || +| placeholder | `string` | '--' | 可选,文本框 placeholder | [基本用法](#基本用法) || +| disabled | `boolean` | false | 可选,文本框是否被禁用 | [基本用法](#基本用法) || +| error | `boolean` | false | 可选,文本框是否出现输入错误 | [基本用法](#基本用法) || +| size | `'sm'\|''\|'lg'` | '' | 可选,文本框尺寸,有三种选择`'lg'`,`''`,`'sm'` | [基本用法](#尺寸) || + -- Gitee From a7ce7ba242643dc433240255b7f981a86d243319 Mon Sep 17 00:00:00 2001 From: Echo Date: Sun, 29 Aug 2021 15:04:07 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E7=A9=BF=E6=A2=AD=E6=A1=86?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/transfer/__tests__/use-transfer-base.ts | 90 ++++++++ .../__tests__/use-transfer-operation.ts | 18 ++ devui/transfer/__tests__/use-transfer.ts | 76 +++++++ devui/transfer/doc/api-cn.md | 32 +++ devui/transfer/doc/api-en.md | 32 +++ devui/transfer/index.ts | 16 ++ devui/transfer/src/transfer-base.tsx | 92 +++++++++ devui/transfer/src/transfer-operation.tsx | 33 +++ devui/transfer/src/transfer.scss | 150 ++++++++++++++ devui/transfer/src/transfer.tsx | 195 ++++++++++++++++++ sites/components/transfer/index.md | 128 +++++++++--- 11 files changed, 834 insertions(+), 28 deletions(-) create mode 100644 devui/transfer/__tests__/use-transfer-base.ts create mode 100644 devui/transfer/__tests__/use-transfer-operation.ts create mode 100644 devui/transfer/__tests__/use-transfer.ts create mode 100644 devui/transfer/doc/api-cn.md create mode 100644 devui/transfer/doc/api-en.md create mode 100644 devui/transfer/index.ts create mode 100644 devui/transfer/src/transfer-base.tsx create mode 100644 devui/transfer/src/transfer-operation.tsx create mode 100644 devui/transfer/src/transfer.scss create mode 100644 devui/transfer/src/transfer.tsx diff --git a/devui/transfer/__tests__/use-transfer-base.ts b/devui/transfer/__tests__/use-transfer-base.ts new file mode 100644 index 00000000..3fbe6e3a --- /dev/null +++ b/devui/transfer/__tests__/use-transfer-base.ts @@ -0,0 +1,90 @@ +import { computed, ExtractPropTypes, PropType, ComputedRef, SetupContext } from 'vue' +import { ISourceOption } from './use-transfer' + + +export const transferBaseProps = { + sourceOption: { + type: Array as () => ISourceOption[], + default(): Array { + return [] + } + }, + targetOption: { + type: Array as () => ISourceOption[], + default(): Array { + return [] + } + }, + type: { + type: String, + default: 'source' + }, + title: { + type: String, + default: 'Source' + }, + filterable: { + type: Boolean, + default: false + }, + allChecked: { + type: Boolean, + default: (): boolean => false + }, + query: { + type: String, + default: (): string => '' + }, + alltargetState: { + type: Boolean, + default: (): boolean => false + }, + checkedNum: { + type: Number, + default: (): number => 0 + }, + scopedSlots: { + type: Object + }, + onChangeSource: { + // type: Function as unknown as () => ((item: ISourceOption, idx: number) => void) + type: Function as PropType<(item: ISourceOption, idx: number) => void> + }, + onChangeAllSource: { + type: Function as unknown as () => (() => void) + }, + onChangeQuery: { + type: Function as PropType<(val: string) => void> + } +} + +export const transferOperationProps = { + sourceDisabled: { + type: Boolean, + default: (): boolean => true + }, + targetDisabled: { + type: Boolean, + default: (): boolean => true + }, + onUpdateSourceData: { + type: Function as unknown as () => (() => void) + }, + onUpdateTargetData: { + type: Function as unknown as () => (() => void) + } +} + + +export type TransferOperationProps = ExtractPropTypes + +export const TransferBaseClass = (props: TransferOperationProps): ComputedRef => { + return computed(() => { + return `devui-transfer-panel devui-transfer-${props.type}` + }) +} + +export const Query = ((props: TransferOperationProps): ComputedRef => { + return computed(() => props.query) +}) + diff --git a/devui/transfer/__tests__/use-transfer-operation.ts b/devui/transfer/__tests__/use-transfer-operation.ts new file mode 100644 index 00000000..2c55cb69 --- /dev/null +++ b/devui/transfer/__tests__/use-transfer-operation.ts @@ -0,0 +1,18 @@ +import { ExtractPropTypes, PropType } from 'vue' + +export const transferOperationProps = { + sourceDisabled: { + type: Boolean, + default: (): boolean => true + }, + targetDisabled: { + type: Boolean, + default: (): boolean => true + }, + onUpdateSourceData: { + type: Function as unknown as () => (() => void) + }, + onUpdateTargetData: { + type: Function as unknown as () => (() => void) + } +} diff --git a/devui/transfer/__tests__/use-transfer.ts b/devui/transfer/__tests__/use-transfer.ts new file mode 100644 index 00000000..4036a45d --- /dev/null +++ b/devui/transfer/__tests__/use-transfer.ts @@ -0,0 +1,76 @@ +import { ExtractPropTypes, PropType } from 'vue' +export interface ISourceOption { + key: string + value: string | number + disabled: boolean +} + +export interface IItem extends ISourceOption { + checked: boolean +} + +interface ITitles { + [index: number]: string +} + +interface IModel { + [index: number]: string | number +} + +export const transferProps = { + sourceOption: { + type: Array as () => ISourceOption[], + require: true, + default(): ISourceOption[] { + return [] + } + }, + targetOption: { + type: Array as () => ISourceOption[], + require: true, + default(): ISourceOption[] { + return [] + } + }, + titles: { + type: Array as PropType, + default(): ITitles[] { + return ['Source', 'Target'] + } + }, + modelValue: { + type: Array as PropType, + default: () => (): IModel[] => [], + }, + height: { + type: String, + default: '320px' + }, + filterable: { + type: Boolean, + default: false + }, + isSourceDroppable: { + type: Boolean, + default: false + }, + isTargetDroppable: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + showOptionTitle: { + type: Boolean, + default: false + }, + slots: { + type: Object + } +} + +export type TransferProps = ExtractPropTypes; + + diff --git a/devui/transfer/doc/api-cn.md b/devui/transfer/doc/api-cn.md new file mode 100644 index 00000000..7d13f183 --- /dev/null +++ b/devui/transfer/doc/api-cn.md @@ -0,0 +1,32 @@ +# 如何使用 +在module中引入: +```ts +import { TransferModule } from 'ng-devui/transfer'; +``` +在页面中使用: +```html + +``` + +# d-transfer + +## d-transfer 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | +| sourceOption | `array` | [] | 可选参数,穿梭框源数据 | [基本用法](demo#transfer-demo-base) | +| targetOption | `array` | [] | 可选参数,穿梭框目标数据 | [基本用法](demo#transfer-demo-base) | +| titles | `array` | [] | 可选参数,穿梭框标题 | [基本用法](demo#transfer-demo-base) | +| height | `string` | 320px | 可选参数,穿梭框高度 | +| isSearch | `number` | false | 可选参数,是否可以搜索 | [搜索穿梭框](demo#transfer-demo-search) | +| isSourceDroppable | `boolean` | false | 可选参数,源是否可以拖拽 | +| isTargetDroppable | `boolean` | false | 可选参数,目标是否可以拖拽 | [排序穿梭框](demo#transfer-demo-sort) | +| disabled | `boolean` | false | 可选参数 穿梭框禁止使用 | [基本用法](demo#transfer-demo-base) | +| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | 可选参数 在transfer事件发生前判断事件是否允许触发 | [基本用法](demo#transfer-demo-base) | + +## d-transfer 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | +| transferToSource | 返回穿梭框源和目标数据 | 当点击右穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | +| transferToTarget | 返回穿梭框源和目标数据 | 当点击左穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | diff --git a/devui/transfer/doc/api-en.md b/devui/transfer/doc/api-en.md new file mode 100644 index 00000000..dabb0e54 --- /dev/null +++ b/devui/transfer/doc/api-en.md @@ -0,0 +1,32 @@ +# How To Use +Import into module: +```ts +import { TransferModule } from 'ng-devui/transfer'; +``` +In the page: +```html + +``` + +# d-transfer + +## d-transfer parameter + +| Parameter | Type | Default | Description | Jump to Demo | +| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | +| sourceOption | `array` | [] | Optional. This parameter indicates the source data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | +| targetOption | `array` | [] | Optional. This parameter indicates the target data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | +| titles | `array` | [] | Optional. Title of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | +| height | `string` | 320px | Optional. It indicates the height of the shuttle box. | +| isSearch | `number` | false | Optional. Specifies whether to search. | [Search Shuttle Box](demo#transfer-demo-search) | +| isSourceDroppable | `boolean` | false | Optional. Indicates whether the source can be dragged. | +| isTargetDroppable | `boolean` | false | Optional. Indicates whether the object can be dragged. | [Sorting Shuttle Box](demo#transfer-demo-sort) | +| disabled | `boolean` | false | Optional. The shuttle box cannot be used. | [Basic Usage](demo#transfer-demo-base) | +| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | Optional. Determines whether the transfer event can be triggered before the transfer event occurs. | [Basic Usage](demo#transfer-demo-base) | + +## d-transfer event + +| Event | Type | Description | Jump to Demo | +| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | +| transferToSource | Return the source and target data in the shuttle box. | When you click the right button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | +| transferToTarget | Return the source and target data in the shuttle box. | When you click the left button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | diff --git a/devui/transfer/index.ts b/devui/transfer/index.ts new file mode 100644 index 00000000..dfc390d6 --- /dev/null +++ b/devui/transfer/index.ts @@ -0,0 +1,16 @@ +import type { App } from 'vue' +import Transfer from './src/transfer' + +Transfer.install = function (app: App) { + app.component(Transfer.name, Transfer) +} + +export { Transfer } + +export default { + title: 'Transfer 穿梭框', + category: '数据录入', + install(app: App): void { + app.use(Transfer as any) + } +} diff --git a/devui/transfer/src/transfer-base.tsx b/devui/transfer/src/transfer-base.tsx new file mode 100644 index 00000000..62cdc0ba --- /dev/null +++ b/devui/transfer/src/transfer-base.tsx @@ -0,0 +1,92 @@ +import { defineComponent, computed, ref, watch } from 'vue'; +import { ISourceOption } from '../__tests__/use-transfer' +import { transferBaseProps, TransferBaseClass, Query } from '../__tests__/use-transfer-base' +import DCheckbox from '../../checkbox/src/checkbox' +import DSearch from '../../search/src/search' +export default defineComponent({ + name: 'DTransferBase', + components: { + DCheckbox, + DSearch + }, + props: transferBaseProps, + setup(props, ctx) { + const baseClass = TransferBaseClass(props) + const searchQuery = Query(props) + const allSourceChecked = (): void => { + ctx.emit('changeAllSource') + } + const updateChecked = (item: ISourceOption, idx: number): void => { + ctx.emit('changeSource', item, idx) + } + const setSearchQuery = (val: string) => ctx.emit('changeQuery', val) + + return { + baseClass, + searchQuery, + allSourceChecked, + updateChecked, + setSearchQuery + } + }, + data() { + return {} + }, + render() { + const { + title, + baseClass, + checkedNum, + allSourceChecked, + allChecked, + updateChecked, + sourceOption, + setSearchQuery, + filterable, + searchQuery + } = this + + return ( +
+ { + this.$slots.Header ? this.$slots.Header() : (
+
+ + {title} + +
+
{checkedNum}/{sourceOption.length}
+
) + } + { + this.$slots.Body ? this.$slots.Body() :
+ {filterable && } +
+ { + sourceOption.length ? sourceOption.map((item, idx) => { + return updateChecked(item, idx)} + key={idx}> + {item.key} + + }) :
无数据
+ } +
+
+ } +
+ ) + } +}) \ No newline at end of file diff --git a/devui/transfer/src/transfer-operation.tsx b/devui/transfer/src/transfer-operation.tsx new file mode 100644 index 00000000..698a3d08 --- /dev/null +++ b/devui/transfer/src/transfer-operation.tsx @@ -0,0 +1,33 @@ +import { defineComponent } from 'vue'; +import DButton from '../../button/index' +import { transferOperationProps } from '../__tests__/use-transfer-operation' + +export default defineComponent({ + name: 'DTransferOperation', + components: { + DButton + }, + props: transferOperationProps, + setup(props, ctx) { + return () => { + return
+
+ + + {/* + */} +
+
+ } + }, + data() { + return {} + }, + // render() { + + // } +}) \ No newline at end of file diff --git a/devui/transfer/src/transfer.scss b/devui/transfer/src/transfer.scss new file mode 100644 index 00000000..2071d011 --- /dev/null +++ b/devui/transfer/src/transfer.scss @@ -0,0 +1,150 @@ +// @import '../../style/theme/color'; +@import '../../style/theme/color'; + +$devui-transfer-border-color: #adb0b8; +$devui-transfer-border-radius: 2px; +$devui-transfer-header-height: 40px; +$devui-transfer-header-border-line-color:#dfe1e6; +$devui-transfer-body-search-height: 42px; +$devui-transfer-body-list-item-height: 36px; + +.devui-transfer { + display: flex; + + &-panel { + width: 300px; + border: 1px solid $devui-transfer-border-color; + border-radius: $devui-transfer-border-radius; + + &-header { + display: flex; + justify-content: space-between; + height: $devui-transfer-header-height; + line-height: $devui-transfer-header-height; + border-bottom: 1px solid$devui-transfer-header-border-line-color; + + &-allChecked { + display: flex; + margin-left: 20px; + } + + &-num { + margin-right: 12px; + } + } + + &-body { + height: 100%; + + &-search { + height: $devui-transfer-body-search-height; + display: flex; + justify-content: center; + width: calc(100% - 40px); + align-items: center; + margin: 0 auto; + + .devui-search, + .devui-input__wrap { + width: 100%; + } + } + + &-list { + overflow: auto; + height: calc(100% - #{$devui-transfer-header-height} - #{$devui-transfer-body-search-height}); + width: 100%; + + &-item { + margin: 0 20px; + height: $devui-transfer-body-list-item-height; + line-height: $devui-transfer-body-list-item-height; + } + + &-empty { + height: 100%; + // width: 100%; + display: flex; + justify-content: center; + align-items: center; + color: $devui-disabled-text; + } + } + } + + &-operation { + width: 10%; + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + + &-group { + width: 36px; + + &-left, + &-right { + width: 36px; + height: 36px; + color: $devui-light-text; + background: $devui-primary; + border-radius: 50%; + border: none; + cursor: pointer; + } + + &-right { + margin-top: 12px; + } + + &-left:hover, + &-left span:hover, + &-right:hover, + &-right span:hover { + background: $devui-primary-hover; + } + + &-left:active, + &-left span:active, + &-right:active, + &-right span:active { + background: $devui-primary-active; + } + + &-left:disabled, + &-left span:disabled, + &-right:disabled, + &-right span:disabled { + color: $devui-disabled-text; + background: $devui-disabled-bg; + cursor: not-allowed; + } + } + } + } + + .custom { + &-body { + &-header, + &-list { + display: flex; + justify-content: space-around; + line-height: $devui-transfer-body-list-item-height; + flex-wrap: wrap; + margin: 0; + } + + &-header { + border-bottom: 1px solid $devui-transfer-border-color; + width: 100%; + } + + &-header > div, + &-list > div { + width: 25%; + display: flex; + justify-content: center; + } + } + } +} diff --git a/devui/transfer/src/transfer.tsx b/devui/transfer/src/transfer.tsx new file mode 100644 index 00000000..75207325 --- /dev/null +++ b/devui/transfer/src/transfer.tsx @@ -0,0 +1,195 @@ +import { defineComponent, reactive, computed } from 'vue' +import DTransferBase from './transfer-base' +import DTransferOperation from './transfer-operation' +import { transferProps, TransferProps, IItem } from '../__tests__/use-transfer' +import DCheckbox from '../..//checkbox/src/checkbox' +import './transfer.scss' + +export default defineComponent({ + name: 'DTransfer', + components: { + DTransferBase, + DTransferOperation, + DCheckbox + }, + props: transferProps, + setup(props: TransferProps, ctx) { + const sourceDataOptions = reactive({ + data: props.sourceOption, + allChecked: false, + disabled: true, + checkedNum: props.modelValue.length, + query: '', + modelValue: props.modelValue, + filterData: computed(() => { + return sourceDataOptions.data.filter((item) => { + if (item.key.indexOf(sourceDataOptions.query) !== -1) { + return Object.assign(item, { + checked: sourceDataOptions.modelValue.some(cur => cur === item.value) + }) + } + }) + }), + changeAllSource: (): void => { + sourceDataOptions.allChecked = !sourceDataOptions.allChecked + if (sourceDataOptions.allChecked) { + sourceDataOptions.filterData.map(item => { + if (!item.disabled && !item.checked) { + sourceDataOptions.modelValue.push(item.value) + } + }) + } else { + sourceDataOptions.modelValue = [] + } + sourceDataOptions.setCheckedNum() + targetDataOptions.setDisabled(!sourceDataOptions.modelValue.length ? true : false) + }, + sourceChangeSource: (item: IItem, idx: number): void => { + if (!item.checked) { + sourceDataOptions.modelValue.push(item.value) + } else { + sourceDataOptions.modelValue = sourceDataOptions.modelValue.filter(cur => cur !== item.value) + } + sourceDataOptions.setCheckedNum() + targetDataOptions.setDisabled(!sourceDataOptions.modelValue.length ? true : false) + }, + updateData: (): void => { + targetDataOptions.data = targetDataOptions.data.filter(item => { + if (item.checked) { + sourceDataOptions.data.push({ + ...item, + checked: false + }) + targetDataOptions.modelValue = targetDataOptions.modelValue.filter(cur => cur !== item.value) + } + return item.checked !== true; + }) + targetDataOptions.setState() + }, + setDisabled: (value: boolean): void => { + sourceDataOptions.disabled = value + }, + setState: (): void => { + targetDataOptions.disabled = true + sourceDataOptions.checkedNum = 0 + sourceDataOptions.allChecked = false + }, + changeQuery: (val: string): void => { + sourceDataOptions.query = val; + }, + setCheckedNum: (): void => { + sourceDataOptions.checkedNum = sourceDataOptions.modelValue.length + sourceDataOptions.allChecked = sourceDataOptions.checkedNum === sourceDataOptions.filterData.length + } + }) + + const targetDataOptions = reactive({ + data: props.targetOption, + allChecked: false, + query: '', + disabled: props.modelValue.length ? false : true, + checkedNum: 0, + modelValue: [], + filterData: computed(() => { + return targetDataOptions.data.filter((item) => { + if (item.key.indexOf(targetDataOptions.query) !== -1) { + return Object.assign(item, { + checked: targetDataOptions.modelValue.some(cur => cur === item.value) + }) + } + }) + }), + changeAllTarget: (): void => { + targetDataOptions.allChecked = !targetDataOptions.allChecked + if (targetDataOptions.allChecked) { + targetDataOptions.data.map(item => { + if (!item.disabled && !item.checked) { + targetDataOptions.modelValue.push(item.value) + } + }) + } else { + targetDataOptions.modelValue = [] + } + targetDataOptions.setCheckedNum() + sourceDataOptions.setDisabled(!targetDataOptions.modelValue.length ? true : false) + }, + targetChangeSource: (item: IItem, idx: number): void => { + if (!item.checked) { + targetDataOptions.modelValue.push(item.value) + } else { + targetDataOptions.modelValue = targetDataOptions.modelValue.filter(cur => cur !== item.value) + } + targetDataOptions.setCheckedNum() + sourceDataOptions.setDisabled(!targetDataOptions.modelValue.length ? true : false) + }, + updateData: (): void => { + sourceDataOptions.data = sourceDataOptions.data.filter(item => { + if (item.checked) { + targetDataOptions.data.push({ + ...item, + checked: false + }) + sourceDataOptions.modelValue = sourceDataOptions.modelValue.filter(cur => cur !== item.value) + } + return item.checked !== true + }) + sourceDataOptions.setState() + }, + setDisabled: (value: boolean): void => { + targetDataOptions.disabled = value + }, + setState: (): void => { + sourceDataOptions.disabled = true + targetDataOptions.checkedNum = 0 + targetDataOptions.allChecked = false + }, + changeQuery: (val: string): void => { + targetDataOptions.query = val + }, + setCheckedNum: (): void => { + targetDataOptions.checkedNum = targetDataOptions.modelValue.length + targetDataOptions.allChecked = targetDataOptions.checkedNum === targetDataOptions.filterData.length + } + }) + const transferStyle = { + height: props.height, + } + + return () => { + return
+ + + +
+ } + } +}) \ No newline at end of file diff --git a/sites/components/transfer/index.md b/sites/components/transfer/index.md index d98b3733..ca69577e 100644 --- a/sites/components/transfer/index.md +++ b/sites/components/transfer/index.md @@ -2,34 +2,106 @@ 穿梭框。 +### 何时使用 -### 基本用法 - -:::demo - -```vue - - -``` +需要手动输入文字使用。 -::: - -### 尺寸 - - -### API - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | -| :---------: | :------: | :-------: | :----------------------- | --------------------------------- | --------- | -| id | `string` | -- | 可选,文本框 id | [基本用法](#基本用法) || -| placeholder | `string` | '--' | 可选,文本框 placeholder | [基本用法](#基本用法) || -| disabled | `boolean` | false | 可选,文本框是否被禁用 | [基本用法](#基本用法) || -| error | `boolean` | false | 可选,文本框是否出现输入错误 | [基本用法](#基本用法) || -| size | `'sm'\|''\|'lg'` | '' | 可选,文本框尺寸,有三种选择`'lg'`,`''`,`'sm'` | [基本用法](#尺寸) || +### 基本用法 + + + -- Gitee From a916ac6176e26538b7108f7be8042acef46757ae Mon Sep 17 00:00:00 2001 From: Echo Date: Sat, 4 Sep 2021 17:09:41 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E7=A9=BF=E6=A2=AD=E6=A1=86?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E7=89=88=E6=94=B9=E7=89=88=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/transfer/__tests__/use-transfer-base.ts | 60 +++- .../__tests__/use-transfer-operation.ts | 6 +- devui/transfer/__tests__/use-transfer.ts | 32 +- devui/transfer/src/transfer-base.tsx | 87 +++--- devui/transfer/src/transfer-operation.tsx | 20 +- devui/transfer/src/transfer.scss | 2 + devui/transfer/src/transfer.tsx | 274 ++++++++---------- devui/transfer/types.ts | 54 ++++ sites/components/transfer/index.md | 145 ++++++++- 9 files changed, 413 insertions(+), 267 deletions(-) create mode 100644 devui/transfer/types.ts diff --git a/devui/transfer/__tests__/use-transfer-base.ts b/devui/transfer/__tests__/use-transfer-base.ts index 3fbe6e3a..b5bc3205 100644 --- a/devui/transfer/__tests__/use-transfer-base.ts +++ b/devui/transfer/__tests__/use-transfer-base.ts @@ -1,17 +1,19 @@ -import { computed, ExtractPropTypes, PropType, ComputedRef, SetupContext } from 'vue' -import { ISourceOption } from './use-transfer' +import { computed, ExtractPropTypes, PropType, ComputedRef } from 'vue' +import { IItem, TState, TResult } from '../types' +import { TransferProps } from '../__tests__/use-transfer' +export type TransferOperationProps = ExtractPropTypes export const transferBaseProps = { sourceOption: { - type: Array as () => ISourceOption[], - default(): Array { + type: Array as () => IItem[], + default(): Array { return [] } }, targetOption: { - type: Array as () => ISourceOption[], - default(): Array { + type: Array as () => IItem[], + default(): Array { return [] } }, @@ -23,7 +25,7 @@ export const transferBaseProps = { type: String, default: 'Source' }, - filterable: { + search: { type: Boolean, default: false }, @@ -43,21 +45,26 @@ export const transferBaseProps = { type: Number, default: (): number => 0 }, + checkedValues: { + type: Array, + default: [] + }, scopedSlots: { type: Object }, - onChangeSource: { - // type: Function as unknown as () => ((item: ISourceOption, idx: number) => void) - type: Function as PropType<(item: ISourceOption, idx: number) => void> - }, onChangeAllSource: { - type: Function as unknown as () => (() => void) + type: Function as unknown as () => ((val: boolean) => void) }, onChangeQuery: { type: Function as PropType<(val: string) => void> + }, + onUpdateCheckeds: { + type: Function as PropType<(val: string[]) => void> } } +export type TransferBaseProps = ExtractPropTypes + export const transferOperationProps = { sourceDisabled: { type: Boolean, @@ -75,8 +82,35 @@ export const transferOperationProps = { } } +const getFilterData = (props, type: string): TResult => { + const newModel: string[] = []; + const data: IItem[] = type === 'source' ? props.sourceOption : props.targetOption + const resultData: IItem[] = data.map((item: IItem) => { + const checked = props.modelValue.some(cur => cur === item.value) + checked && newModel.push(item.value) + return item + }) + return { + model: newModel, + data: resultData + } +} + -export type TransferOperationProps = ExtractPropTypes + +export const initState = (props: TransferProps, type: string): TState => { + const initModel: TResult = getFilterData(props, type); + const state: TState = { + data: initModel.data, + allChecked: false, + disabled: false, + checkedNum: initModel.model.length, + query: '', + checkedValues: initModel.model, + filterData: initModel.data + } + return state +} export const TransferBaseClass = (props: TransferOperationProps): ComputedRef => { return computed(() => { diff --git a/devui/transfer/__tests__/use-transfer-operation.ts b/devui/transfer/__tests__/use-transfer-operation.ts index 2c55cb69..c4eb000f 100644 --- a/devui/transfer/__tests__/use-transfer-operation.ts +++ b/devui/transfer/__tests__/use-transfer-operation.ts @@ -1,4 +1,4 @@ -import { ExtractPropTypes, PropType } from 'vue' + export const transferOperationProps = { sourceDisabled: { @@ -9,6 +9,10 @@ export const transferOperationProps = { type: Boolean, default: (): boolean => true }, + disabled: { + type: Boolean, + default: (): boolean => false + }, onUpdateSourceData: { type: Function as unknown as () => (() => void) }, diff --git a/devui/transfer/__tests__/use-transfer.ts b/devui/transfer/__tests__/use-transfer.ts index 4036a45d..6eaa39f3 100644 --- a/devui/transfer/__tests__/use-transfer.ts +++ b/devui/transfer/__tests__/use-transfer.ts @@ -1,42 +1,24 @@ import { ExtractPropTypes, PropType } from 'vue' -export interface ISourceOption { - key: string - value: string | number - disabled: boolean -} - -export interface IItem extends ISourceOption { - checked: boolean -} - -interface ITitles { - [index: number]: string -} - -interface IModel { - [index: number]: string | number -} +import { IItem, ITitles, IModel } from '../types' export const transferProps = { sourceOption: { - type: Array as () => ISourceOption[], + type: Array as () => IItem[], require: true, - default(): ISourceOption[] { + default(): IItem[] { return [] } }, targetOption: { - type: Array as () => ISourceOption[], + type: Array as () => IItem[], require: true, - default(): ISourceOption[] { + default(): IItem[] { return [] } }, titles: { type: Array as PropType, - default(): ITitles[] { - return ['Source', 'Target'] - } + default: () => (): ITitles[] => ['Source', 'Target'] }, modelValue: { type: Array as PropType, @@ -46,7 +28,7 @@ export const transferProps = { type: String, default: '320px' }, - filterable: { + isSearch: { type: Boolean, default: false }, diff --git a/devui/transfer/src/transfer-base.tsx b/devui/transfer/src/transfer-base.tsx index 62cdc0ba..28e5c7fc 100644 --- a/devui/transfer/src/transfer-base.tsx +++ b/devui/transfer/src/transfer-base.tsx @@ -1,49 +1,49 @@ -import { defineComponent, computed, ref, watch } from 'vue'; -import { ISourceOption } from '../__tests__/use-transfer' -import { transferBaseProps, TransferBaseClass, Query } from '../__tests__/use-transfer-base' +import { defineComponent, computed } from 'vue' +import { transferBaseProps, TransferBaseClass } from '../__tests__/use-transfer-base' +import { TransferBaseProps } from '../__tests__/use-transfer-base' import DCheckbox from '../../checkbox/src/checkbox' +import DCheckboxGroup from '../../checkbox/src/checkbox-group' import DSearch from '../../search/src/search' export default defineComponent({ name: 'DTransferBase', components: { - DCheckbox, - DSearch + DSearch, + DCheckboxGroup, + DCheckbox }, props: transferBaseProps, - setup(props, ctx) { + setup(props: TransferBaseProps, ctx) { + /** data start **/ + const modelValues = computed(() => props.checkedValues) + const searchQuery = computed(() => props.query) const baseClass = TransferBaseClass(props) - const searchQuery = Query(props) - const allSourceChecked = (): void => { - ctx.emit('changeAllSource') - } - const updateChecked = (item: ISourceOption, idx: number): void => { - ctx.emit('changeSource', item, idx) - } - const setSearchQuery = (val: string) => ctx.emit('changeQuery', val) + /** data end **/ + + /** watch start **/ + /** watch start **/ + + /** methods start **/ + const updateSearchQuery = (val: string): void => ctx.emit('changeQuery', val) + /** methods start **/ return { baseClass, searchQuery, - allSourceChecked, - updateChecked, - setSearchQuery + modelValues, + updateSearchQuery } }, - data() { - return {} - }, render() { const { title, baseClass, checkedNum, - allSourceChecked, allChecked, - updateChecked, sourceOption, - setSearchQuery, - filterable, - searchQuery + updateSearchQuery, + search, + searchQuery, + modelValues } = this return ( @@ -52,9 +52,8 @@ export default defineComponent({ this.$slots.Header ? this.$slots.Header() : (
+ modelValue={allChecked} + onChange={(value: boolean) => this.$emit('changeAllSource', value)}> {title}
@@ -63,25 +62,29 @@ export default defineComponent({ } { this.$slots.Body ? this.$slots.Body() :
- {filterable && diff --git a/devui/transfer/src/transfer-operation.tsx b/devui/transfer/src/transfer-operation.tsx index 698a3d08..0448b96f 100644 --- a/devui/transfer/src/transfer-operation.tsx +++ b/devui/transfer/src/transfer-operation.tsx @@ -1,5 +1,5 @@ -import { defineComponent } from 'vue'; -import DButton from '../../button/index' +import { defineComponent, computed } from 'vue'; +import DButton from '../../button/src/button' import { transferOperationProps } from '../__tests__/use-transfer-operation' export default defineComponent({ @@ -12,22 +12,14 @@ export default defineComponent({ return () => { return
- - - {/* - */} + ctx.emit('updateSourceData')}> + ctx.emit('updateTargetData')}>
} }, data() { return {} - }, - // render() { - - // } + } }) \ No newline at end of file diff --git a/devui/transfer/src/transfer.scss b/devui/transfer/src/transfer.scss index 2071d011..c24d4f81 100644 --- a/devui/transfer/src/transfer.scss +++ b/devui/transfer/src/transfer.scss @@ -91,6 +91,8 @@ $devui-transfer-body-list-item-height: 36px; border-radius: 50%; border: none; cursor: pointer; + padding: 0; + min-width: 36px !important; } &-right { diff --git a/devui/transfer/src/transfer.tsx b/devui/transfer/src/transfer.tsx index 75207325..9745506a 100644 --- a/devui/transfer/src/transfer.tsx +++ b/devui/transfer/src/transfer.tsx @@ -1,7 +1,9 @@ -import { defineComponent, reactive, computed } from 'vue' +import { defineComponent, reactive, watch, ref } from 'vue' +import { TState } from '../types' import DTransferBase from './transfer-base' import DTransferOperation from './transfer-operation' -import { transferProps, TransferProps, IItem } from '../__tests__/use-transfer' +import { initState } from '../__tests__/use-transfer-base' +import { transferProps, TransferProps } from '../__tests__/use-transfer' import DCheckbox from '../..//checkbox/src/checkbox' import './transfer.scss' @@ -13,181 +15,137 @@ export default defineComponent({ DCheckbox }, props: transferProps, - setup(props: TransferProps, ctx) { - const sourceDataOptions = reactive({ - data: props.sourceOption, - allChecked: false, - disabled: true, - checkedNum: props.modelValue.length, - query: '', - modelValue: props.modelValue, - filterData: computed(() => { - return sourceDataOptions.data.filter((item) => { - if (item.key.indexOf(sourceDataOptions.query) !== -1) { - return Object.assign(item, { - checked: sourceDataOptions.modelValue.some(cur => cur === item.value) - }) - } - }) - }), - changeAllSource: (): void => { - sourceDataOptions.allChecked = !sourceDataOptions.allChecked - if (sourceDataOptions.allChecked) { - sourceDataOptions.filterData.map(item => { - if (!item.disabled && !item.checked) { - sourceDataOptions.modelValue.push(item.value) - } - }) - } else { - sourceDataOptions.modelValue = [] - } - sourceDataOptions.setCheckedNum() - targetDataOptions.setDisabled(!sourceDataOptions.modelValue.length ? true : false) - }, - sourceChangeSource: (item: IItem, idx: number): void => { - if (!item.checked) { - sourceDataOptions.modelValue.push(item.value) - } else { - sourceDataOptions.modelValue = sourceDataOptions.modelValue.filter(cur => cur !== item.value) - } - sourceDataOptions.setCheckedNum() - targetDataOptions.setDisabled(!sourceDataOptions.modelValue.length ? true : false) - }, - updateData: (): void => { - targetDataOptions.data = targetDataOptions.data.filter(item => { - if (item.checked) { - sourceDataOptions.data.push({ - ...item, - checked: false - }) - targetDataOptions.modelValue = targetDataOptions.modelValue.filter(cur => cur !== item.value) - } - return item.checked !== true; - }) - targetDataOptions.setState() - }, - setDisabled: (value: boolean): void => { - sourceDataOptions.disabled = value - }, - setState: (): void => { - targetDataOptions.disabled = true - sourceDataOptions.checkedNum = 0 - sourceDataOptions.allChecked = false - }, - changeQuery: (val: string): void => { - sourceDataOptions.query = val; - }, - setCheckedNum: (): void => { - sourceDataOptions.checkedNum = sourceDataOptions.modelValue.length - sourceDataOptions.allChecked = sourceDataOptions.checkedNum === sourceDataOptions.filterData.length + setup(props: TransferProps) { + /** data start **/ + const leftOptions = reactive(initState(props, 'source')) + const rightOptions = reactive(initState(props, 'target')) + const origin = ref(null); + /** data end **/ + + /** watch start **/ + watch( + () => leftOptions.query, + (nVal: string): void => { + leftOptions.filterData = leftOptions.data.filter(item => item.key.indexOf(nVal) !== -1) } - }) + ) - const targetDataOptions = reactive({ - data: props.targetOption, - allChecked: false, - query: '', - disabled: props.modelValue.length ? false : true, - checkedNum: 0, - modelValue: [], - filterData: computed(() => { - return targetDataOptions.data.filter((item) => { - if (item.key.indexOf(targetDataOptions.query) !== -1) { - return Object.assign(item, { - checked: targetDataOptions.modelValue.some(cur => cur === item.value) - }) - } - }) - }), - changeAllTarget: (): void => { - targetDataOptions.allChecked = !targetDataOptions.allChecked - if (targetDataOptions.allChecked) { - targetDataOptions.data.map(item => { - if (!item.disabled && !item.checked) { - targetDataOptions.modelValue.push(item.value) - } - }) - } else { - targetDataOptions.modelValue = [] - } - targetDataOptions.setCheckedNum() - sourceDataOptions.setDisabled(!targetDataOptions.modelValue.length ? true : false) - }, - targetChangeSource: (item: IItem, idx: number): void => { - if (!item.checked) { - targetDataOptions.modelValue.push(item.value) - } else { - targetDataOptions.modelValue = targetDataOptions.modelValue.filter(cur => cur !== item.value) - } - targetDataOptions.setCheckedNum() - sourceDataOptions.setDisabled(!targetDataOptions.modelValue.length ? true : false) - }, - updateData: (): void => { - sourceDataOptions.data = sourceDataOptions.data.filter(item => { - if (item.checked) { - targetDataOptions.data.push({ - ...item, - checked: false - }) - sourceDataOptions.modelValue = sourceDataOptions.modelValue.filter(cur => cur !== item.value) - } - return item.checked !== true - }) - sourceDataOptions.setState() + watch( + () => leftOptions.checkedValues, + (values: string[]): void => { + leftOptions.checkedNum = values.length + setAllCheckedState(leftOptions, values) }, - setDisabled: (value: boolean): void => { - targetDataOptions.disabled = value - }, - setState: (): void => { - sourceDataOptions.disabled = true - targetDataOptions.checkedNum = 0 - targetDataOptions.allChecked = false + { + deep: true + } + ) + + watch( + () => rightOptions.query, + (nVal: string): void => { + rightOptions.filterData = rightOptions.data.filter(item => item.key.indexOf(nVal) !== -1) }, - changeQuery: (val: string): void => { - targetDataOptions.query = val + ) + + watch( + () => rightOptions.checkedValues, + (values: string[]): void => { + rightOptions.checkedNum = values.length; + setAllCheckedState(rightOptions, values) }, - setCheckedNum: (): void => { - targetDataOptions.checkedNum = targetDataOptions.modelValue.length - targetDataOptions.allChecked = targetDataOptions.checkedNum === targetDataOptions.filterData.length + { + deep: true + } + ) + + /** watch end **/ + + /** methods start **/ + const setAllCheckedState = (source: TState, value: string[]): void => { + if (origin.value === 'click') { + source.allChecked = false + } else { + source.allChecked = value.length === source.filterData.filter(item => !item.disabled).length ? true : false } - }) - const transferStyle = { - height: props.height, } + const updateFilterData = (source: TState, target: TState): void => { + const newData = [] + source.filterData = source.data = source.filterData.filter(item => { + const hasInclues = source.checkedValues.includes(item.value) + hasInclues && newData.push(item) + return !hasInclues + }) + target.filterData = target.data = target.filterData.concat(newData) + source.checkedValues = [] + target.disabled = !target.disabled + setOrigin('click') + } + const changeAllSource = (source: TState, value: boolean): void => { + if (source.filterData.every(item => item.disabled)) return + source.allChecked = value + if (value) { + source.checkedValues = source.filterData.filter(item => !item.disabled) + .map(item => item.value) + } else { + source.checkedValues = [] + } + setOrigin('change') + } + const updateLeftCheckeds = (values: string[]): void => { + leftOptions.checkedValues = values + setOrigin('change') + } + const updateRightCheckeds = (values: string[]): void => { + rightOptions.checkedValues = values + setOrigin('change') + } + const setOrigin = (value: string): void => { + origin.value = value + } + /** methods end **/ + return () => { return
changeAllSource(leftOptions, value)} + onUpdateCheckeds={updateLeftCheckeds} + onChangeQuery={(value) => leftOptions.query = value} /> 0 ? false : true} + targetDisabled={leftOptions.checkedNum > 0 ? false : true} + onUpdateSourceData={() => { updateFilterData(rightOptions, leftOptions) }} + onUpdateTargetData={() => { updateFilterData(leftOptions, rightOptions) }} /> changeAllSource(rightOptions, value)} + onUpdateCheckeds={updateRightCheckeds} + onChangeQuery={(value) => rightOptions.query = value} />
} diff --git a/devui/transfer/types.ts b/devui/transfer/types.ts new file mode 100644 index 00000000..c527d74e --- /dev/null +++ b/devui/transfer/types.ts @@ -0,0 +1,54 @@ + +export interface IItem { + key: string + value: string + disabled: boolean +} + +export interface ITitles { + [index: number]: string +} + +export interface IModel { + [index: number]: string | number +} + +export interface TState { + data: IItem[] + allChecked: boolean + checkedNum: number + query: string + checkedValues: string[] + filterData: IItem[] + disabled: boolean +} + +export interface TResult { + model: string[] + data: IItem[] +} + + + +// import { ComputedRef } from 'vue' +// export type TItem = { +// key: string +// value: string +// disabled: boolean +// checked?: boolean +// } + +// export type TState = { +// data: TItem[] +// allChecked: boolean +// // disabled: boolean // ComputedRef// +// checkedNum: number +// query: string +// checkedValues: string[] +// filterData: TItem[] +// } + +// export type TResult = { +// model: string[] +// data: TItem[] +// } diff --git a/sites/components/transfer/index.md b/sites/components/transfer/index.md index ca69577e..988204fe 100644 --- a/sites/components/transfer/index.md +++ b/sites/components/transfer/index.md @@ -1,19 +1,24 @@ # Transfer 穿梭框 -穿梭框。 +双栏穿梭选择框。 ### 何时使用 -需要手动输入文字使用。 +需要在多个可选项中进行多选时。穿梭选择框可用只管的方式在两栏中移动数据,完成选择行为。其中左边一栏为source,右边一栏为target。最终返回两栏的数据,提供给开发者使用。 ### 基本用法 - - + +穿梭框基本用法。 + +
+ + +
+ +```html + + +``` + +```ts +import {defineComponent, reactive} from 'vue' + type TData = { + id: number + age: number + value: string + disabled?: boolean + } + export default defineComponent({ + setup() { + const options = reactive({ + titles: ['sourceHeader', 'targetHeader'], + source: [ + { + key: '北京', + value: '北京', + disabled: false + }, + { + key: '上海', + value: '上海', + disabled: true + }, + { + key: '广州', + value: '广州', + disabled: false + }, + { + key: '深圳', + value: '深圳', + disabled: false + }, + { + key: '成都', + value: '成都', + disabled: false + }, + { + key: '武汉', + value: '武汉', + disabled: false + }, + { + key: '西安', + value: '西安', + disabled: false + }, + { + key: '福建', + value: '福建', + disabled: false + }, + { + key: '大连', + value: '大连', + disabled: false + }, + { + key: '重庆', + value: '重庆', + disabled: false + } + ], + target: [ { key: '南充', value: '南充', disabled: false }, + { + key: '广元', + value: '广元', + disabled: true + }, { key: '绵阳', value: '绵阳', disabled: false } ], - filterable: true, - modelValues: ['深圳', '成都'] + isSearch: true, + modelValues: ['深圳', '成都', '绵阳'] }) return { options } } }) - +``` + +### 参数 + +| **参数** | **类型** | **默认** | **说明** | **跳转 Demo** | +| ------------------ | ------------------------------------------------------------ | ------------------------- | ------------------------------------------------------------ | ---------------------------- | +| sourceOption | Array | [] | 可选参数,穿梭框源数据 | [基本用法](#基本用法) | +| targetOption | Array | [] | 可选参数,穿梭框目标数据 | [基本用法](#基本用法) | +| titles | Array | [] | 可选参数,穿梭框标题 | [基本用法](#基本用法) | +| height | string | 320px | 可选参数,穿梭框高度 | [基本用法](#基本用法) | +| isSearch | boolean | true | 可选参数,是否可以搜索 | [基本用法](#基本用法) | +| disabled | boolean | false | 可选参数 穿梭框禁止使用 | [基本用法](#基本用法) | -- Gitee From 06dbb1ee971446429490cabfa09a9cd429f63233 Mon Sep 17 00:00:00 2001 From: Echo Date: Sun, 5 Sep 2021 17:36:45 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=E7=A9=BF=E6=A2=AD=E6=A1=86?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/transfer/__tests__/use-transfer-base.ts | 12 ++++++++---- devui/transfer/src/transfer-base.tsx | 3 ++- devui/transfer/src/transfer.tsx | 4 +++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/devui/transfer/__tests__/use-transfer-base.ts b/devui/transfer/__tests__/use-transfer-base.ts index b5bc3205..d33fc9a2 100644 --- a/devui/transfer/__tests__/use-transfer-base.ts +++ b/devui/transfer/__tests__/use-transfer-base.ts @@ -19,15 +19,15 @@ export const transferBaseProps = { }, type: { type: String, - default: 'source' + default: (): string => 'source' }, title: { type: String, - default: 'Source' + default: (): string => 'Source' }, search: { type: Boolean, - default: false + default: (): boolean => false }, allChecked: { type: Boolean, @@ -47,7 +47,11 @@ export const transferBaseProps = { }, checkedValues: { type: Array, - default: [] + default: (): string[] => [] + }, + allCount: { + type: Number, + default: (): number => 0 }, scopedSlots: { type: Object diff --git a/devui/transfer/src/transfer-base.tsx b/devui/transfer/src/transfer-base.tsx index 28e5c7fc..ce6bbab7 100644 --- a/devui/transfer/src/transfer-base.tsx +++ b/devui/transfer/src/transfer-base.tsx @@ -40,6 +40,7 @@ export default defineComponent({ checkedNum, allChecked, sourceOption, + allCount, updateSearchQuery, search, searchQuery, @@ -57,7 +58,7 @@ export default defineComponent({ {title}
-
{checkedNum}/{sourceOption.length}
+
{checkedNum}/{allCount}
) } { diff --git a/devui/transfer/src/transfer.tsx b/devui/transfer/src/transfer.tsx index 9745506a..d8f94c53 100644 --- a/devui/transfer/src/transfer.tsx +++ b/devui/transfer/src/transfer.tsx @@ -66,7 +66,7 @@ export default defineComponent({ if (origin.value === 'click') { source.allChecked = false } else { - source.allChecked = value.length === source.filterData.filter(item => !item.disabled).length ? true : false + source.allChecked = value.length === source.data.filter(item => !item.disabled).length ? true : false } } @@ -120,6 +120,7 @@ export default defineComponent({ checkedNum={leftOptions.checkedNum} query={leftOptions.query} checkedValues={leftOptions.checkedValues} + allCount={leftOptions.data.length} onChangeAllSource={(value) => changeAllSource(leftOptions, value)} onUpdateCheckeds={updateLeftCheckeds} onChangeQuery={(value) => leftOptions.query = value} @@ -143,6 +144,7 @@ export default defineComponent({ checkedNum={rightOptions.checkedNum} query={rightOptions.query} checkedValues={rightOptions.checkedValues} + allCount={rightOptions.data.length} onChangeAllSource={(value) => changeAllSource(rightOptions, value)} onUpdateCheckeds={updateRightCheckeds} onChangeQuery={(value) => rightOptions.query = value} -- Gitee From 4d9af969debc69d5d81dc1fa0a19988057c96223 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 6 Sep 2021 23:18:27 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=E8=B7=AF=E5=BE=84=E6=9B=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../use-transfer-base.ts | 2 +- .../use-transfer-operation.ts | 0 .../{__tests__ => common}/use-transfer.ts | 0 devui/transfer/doc/api-cn.md | 32 ------------------- devui/transfer/doc/api-en.md | 32 ------------------- devui/transfer/src/transfer-base.tsx | 4 +-- devui/transfer/src/transfer-operation.tsx | 2 +- devui/transfer/src/transfer.tsx | 17 ++++++---- 8 files changed, 15 insertions(+), 74 deletions(-) rename devui/transfer/{__tests__ => common}/use-transfer-base.ts (98%) rename devui/transfer/{__tests__ => common}/use-transfer-operation.ts (100%) rename devui/transfer/{__tests__ => common}/use-transfer.ts (100%) delete mode 100644 devui/transfer/doc/api-cn.md delete mode 100644 devui/transfer/doc/api-en.md diff --git a/devui/transfer/__tests__/use-transfer-base.ts b/devui/transfer/common/use-transfer-base.ts similarity index 98% rename from devui/transfer/__tests__/use-transfer-base.ts rename to devui/transfer/common/use-transfer-base.ts index d33fc9a2..ff58c152 100644 --- a/devui/transfer/__tests__/use-transfer-base.ts +++ b/devui/transfer/common/use-transfer-base.ts @@ -1,6 +1,6 @@ import { computed, ExtractPropTypes, PropType, ComputedRef } from 'vue' import { IItem, TState, TResult } from '../types' -import { TransferProps } from '../__tests__/use-transfer' +import { TransferProps } from './use-transfer' export type TransferOperationProps = ExtractPropTypes diff --git a/devui/transfer/__tests__/use-transfer-operation.ts b/devui/transfer/common/use-transfer-operation.ts similarity index 100% rename from devui/transfer/__tests__/use-transfer-operation.ts rename to devui/transfer/common/use-transfer-operation.ts diff --git a/devui/transfer/__tests__/use-transfer.ts b/devui/transfer/common/use-transfer.ts similarity index 100% rename from devui/transfer/__tests__/use-transfer.ts rename to devui/transfer/common/use-transfer.ts diff --git a/devui/transfer/doc/api-cn.md b/devui/transfer/doc/api-cn.md deleted file mode 100644 index 7d13f183..00000000 --- a/devui/transfer/doc/api-cn.md +++ /dev/null @@ -1,32 +0,0 @@ -# 如何使用 -在module中引入: -```ts -import { TransferModule } from 'ng-devui/transfer'; -``` -在页面中使用: -```html - -``` - -# d-transfer - -## d-transfer 参数 - -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | -| sourceOption | `array` | [] | 可选参数,穿梭框源数据 | [基本用法](demo#transfer-demo-base) | -| targetOption | `array` | [] | 可选参数,穿梭框目标数据 | [基本用法](demo#transfer-demo-base) | -| titles | `array` | [] | 可选参数,穿梭框标题 | [基本用法](demo#transfer-demo-base) | -| height | `string` | 320px | 可选参数,穿梭框高度 | -| isSearch | `number` | false | 可选参数,是否可以搜索 | [搜索穿梭框](demo#transfer-demo-search) | -| isSourceDroppable | `boolean` | false | 可选参数,源是否可以拖拽 | -| isTargetDroppable | `boolean` | false | 可选参数,目标是否可以拖拽 | [排序穿梭框](demo#transfer-demo-sort) | -| disabled | `boolean` | false | 可选参数 穿梭框禁止使用 | [基本用法](demo#transfer-demo-base) | -| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | 可选参数 在transfer事件发生前判断事件是否允许触发 | [基本用法](demo#transfer-demo-base) | - -## d-transfer 事件 - -| 事件 | 类型 | 说明 | 跳转 Demo | -| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | -| transferToSource | 返回穿梭框源和目标数据 | 当点击右穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | -| transferToTarget | 返回穿梭框源和目标数据 | 当点击左穿梭时,返回源和目标数据; | [基本用法](demo#transfer-demo-base) | diff --git a/devui/transfer/doc/api-en.md b/devui/transfer/doc/api-en.md deleted file mode 100644 index dabb0e54..00000000 --- a/devui/transfer/doc/api-en.md +++ /dev/null @@ -1,32 +0,0 @@ -# How To Use -Import into module: -```ts -import { TransferModule } from 'ng-devui/transfer'; -``` -In the page: -```html - -``` - -# d-transfer - -## d-transfer parameter - -| Parameter | Type | Default | Description | Jump to Demo | -| :---------------: | :-----: | :---: | :------------------------- | ------------------------------------------------------------ | -| sourceOption | `array` | [] | Optional. This parameter indicates the source data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| targetOption | `array` | [] | Optional. This parameter indicates the target data of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| titles | `array` | [] | Optional. Title of the shuttle box. | [Basic Usage](demo#transfer-demo-base) | -| height | `string` | 320px | Optional. It indicates the height of the shuttle box. | -| isSearch | `number` | false | Optional. Specifies whether to search. | [Search Shuttle Box](demo#transfer-demo-search) | -| isSourceDroppable | `boolean` | false | Optional. Indicates whether the source can be dragged. | -| isTargetDroppable | `boolean` | false | Optional. Indicates whether the object can be dragged. | [Sorting Shuttle Box](demo#transfer-demo-sort) | -| disabled | `boolean` | false | Optional. The shuttle box cannot be used. | [Basic Usage](demo#transfer-demo-base) | -| beforeTransfer | `(sourceOption, targetOption) => boolean \| Promise \| Observable` | - | Optional. Determines whether the transfer event can be triggered before the transfer event occurs. | [Basic Usage](demo#transfer-demo-base) | - -## d-transfer event - -| Event | Type | Description | Jump to Demo | -| :--------------: | :--------------------: | :--------------------------------: | -------------------------------------------------------- | -| transferToSource | Return the source and target data in the shuttle box. | When you click the right button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | -| transferToTarget | Return the source and target data in the shuttle box. | When you click the left button, the source and target data are returned. | [Basic Usage](demo#transfer-demo-base) | diff --git a/devui/transfer/src/transfer-base.tsx b/devui/transfer/src/transfer-base.tsx index ce6bbab7..be6c197a 100644 --- a/devui/transfer/src/transfer-base.tsx +++ b/devui/transfer/src/transfer-base.tsx @@ -1,6 +1,6 @@ import { defineComponent, computed } from 'vue' -import { transferBaseProps, TransferBaseClass } from '../__tests__/use-transfer-base' -import { TransferBaseProps } from '../__tests__/use-transfer-base' +import { transferBaseProps, TransferBaseClass } from '../common/use-transfer-base' +import { TransferBaseProps } from '../common/use-transfer-base' import DCheckbox from '../../checkbox/src/checkbox' import DCheckboxGroup from '../../checkbox/src/checkbox-group' import DSearch from '../../search/src/search' diff --git a/devui/transfer/src/transfer-operation.tsx b/devui/transfer/src/transfer-operation.tsx index 0448b96f..9718e3ce 100644 --- a/devui/transfer/src/transfer-operation.tsx +++ b/devui/transfer/src/transfer-operation.tsx @@ -1,6 +1,6 @@ import { defineComponent, computed } from 'vue'; import DButton from '../../button/src/button' -import { transferOperationProps } from '../__tests__/use-transfer-operation' +import { transferOperationProps } from '../common/use-transfer-operation' export default defineComponent({ name: 'DTransferOperation', diff --git a/devui/transfer/src/transfer.tsx b/devui/transfer/src/transfer.tsx index d8f94c53..dac3cc92 100644 --- a/devui/transfer/src/transfer.tsx +++ b/devui/transfer/src/transfer.tsx @@ -2,8 +2,8 @@ import { defineComponent, reactive, watch, ref } from 'vue' import { TState } from '../types' import DTransferBase from './transfer-base' import DTransferOperation from './transfer-operation' -import { initState } from '../__tests__/use-transfer-base' -import { transferProps, TransferProps } from '../__tests__/use-transfer' +import { initState } from '../common/use-transfer-base' +import { transferProps, TransferProps } from '../common/use-transfer' import DCheckbox from '../..//checkbox/src/checkbox' import './transfer.scss' @@ -26,7 +26,7 @@ export default defineComponent({ watch( () => leftOptions.query, (nVal: string): void => { - leftOptions.filterData = leftOptions.data.filter(item => item.key.indexOf(nVal) !== -1) + searchFilterData(leftOptions) } ) @@ -44,7 +44,7 @@ export default defineComponent({ watch( () => rightOptions.query, (nVal: string): void => { - rightOptions.filterData = rightOptions.data.filter(item => item.key.indexOf(nVal) !== -1) + searchFilterData(rightOptions) }, ) @@ -72,14 +72,16 @@ export default defineComponent({ const updateFilterData = (source: TState, target: TState): void => { const newData = [] - source.filterData = source.data = source.filterData.filter(item => { + source.data = source.data.filter(item => { const hasInclues = source.checkedValues.includes(item.value) hasInclues && newData.push(item) return !hasInclues }) - target.filterData = target.data = target.filterData.concat(newData) + target.data = target.data.concat(newData) source.checkedValues = [] target.disabled = !target.disabled + searchFilterData(source) + searchFilterData(target) setOrigin('click') } const changeAllSource = (source: TState, value: boolean): void => { @@ -101,6 +103,9 @@ export default defineComponent({ rightOptions.checkedValues = values setOrigin('change') } + const searchFilterData = (source: TState): void => { + source.filterData = source.data.filter(item => item.key.indexOf(source.query) !== -1) + } const setOrigin = (value: string): void => { origin.value = value } -- Gitee