refactor(transfer): virtual scroll list

This commit is contained in:
07akioni 2020-10-30 17:07:17 +08:00
parent acb59f5d7d
commit 33986f496e
9 changed files with 100 additions and 58 deletions

View File

@ -4,10 +4,11 @@ Left, right, left, right... As a boring guy, I can play it all day.
## Demos
```demo
basic
large-data
size
filterable
```
<!-- large-data -->
<!-- -->
## Props
|Name|Type|Default|Description|
@ -24,7 +25,7 @@ filterable
|theme|`'light' \| 'dark' \| string`|`undefined`||
|value|`Array<string \| number>`|`null`||
|on-update:value|`(value: Array<string \| number>) => any`|`undefined`||
<!-- |virtual-scroll|`boolean`|`false`|If use virtual scroll on transfer. If set to `true` it can handles large data (and turn transfer animation off)| -->
|virtual-scroll|`boolean`|`false`|If use virtual scroll on transfer. If set to `true` it can handles large data (and turn transfer animation off)|
### TransferOption Type
|Property|Type|Description|

View File

@ -27,6 +27,6 @@ export default {
options: createOptions(),
value: createValues()
}
},
}
}
```

View File

@ -4,10 +4,10 @@
## 演示
```demo
basic
large-data
size
filterable
```
<!-- large-data -->
## Props
|名称|类型|默认值|说明|
@ -24,7 +24,7 @@ filterable
|theme|`'light' \| 'dark' \| string`|`undefined`||
|value|`Array<string \| number>`|`null`||
|on-update:value|`(value: Array<string \| number>) => any`|`undefined`||
<!-- |virtual-scroll|`boolean`|`false`|If use virtual scroll on transfer. If set to `true` it can handles large data (and turn transfer animation off)| -->
|virtual-scroll|`boolean`|`false`|If use virtual scroll on transfer. If set to `true` it can handles large data (and turn transfer animation off)|
### TransferOption Type
|属性|类型|说明|

View File

@ -27,6 +27,6 @@ export default {
options: createOptions(),
value: createValues()
}
},
}
}
```

View File

@ -33,7 +33,7 @@
@focus="handleInputFocus"
@blur="handleInputBlur"
>
<template v-slot:suffix>
<template #suffix>
<n-icon :size="16">
<search-icon />
</n-icon>
@ -42,32 +42,36 @@
</div>
<div class="n-transfer-list-flex-container">
<template v-if="filteredSrcOpts.length">
<!-- <n-scrollbar
<n-scrollbar
v-if="virtualScroll"
ref="srcScrollerRef"
:theme="mergedTheme"
:container="sourceScrollContainer"
:content="sourceScrollContent"
:container="srcScrollContainer"
:content="srcScrollContent"
>
<recycle-scroller
v-if="virtualScroll"
ref="sourceVirtualScroller"
<virtual-list
ref="srcVlRef"
class="n-virtual-scroller n-transfer-list-content"
:items="filteredSourceOptions"
:items="filteredSrcOpts"
:item-size="itemSize"
key-field="value"
:show-scrollbar="false"
@resize="syncSrcVLScroller"
@scroll="syncSrcVLScroller"
>
<template v-slot="{ item: option }">
<template #="{ item }">
<n-transfer-source-list-item
:key="option.value"
:value="option.value"
:disabled="!!option.disabled"
:label="option.label"
@click="handleSourceCheckboxClick"
:key="item.value"
:value="item.value"
:disabled="item.disabled"
:label="item.label"
/>
</template>
</recycle-scroller>
</n-scrollbar> -->
<n-scrollbar :theme="mergedTheme">
</virtual-list>
</n-scrollbar>
<n-scrollbar
v-else
:theme="mergedTheme"
>
<div class="n-transfer-list-content">
<transition-group name="item" :appear="isMounted" :css="!isInputing">
<n-transfer-source-list-item
@ -123,7 +127,7 @@
@focus="handleInputFocus"
@blur="handleInputBlur"
>
<template v-slot:suffix>
<template #suffix>
<n-icon :size="16">
<search-icon />
</n-icon>
@ -132,32 +136,36 @@
</div>
<div class="n-transfer-list-flex-container">
<template v-if="filteredTgtOpts.length">
<!-- <n-scrollbar
<n-scrollbar
v-if="virtualScroll"
ref="tgtScrollerRef"
:theme="mergedTheme"
:container="targetScrollContainer"
:content="targetScrollContent"
:container="tgtScrollContainer"
:content="tgtScrollContent"
>
<recycle-scroller
v-if="virtualScroll"
ref="targetVirtualScroller"
<virtual-list
ref="tgtVlRef"
class="n-virtual-scroller n-transfer-list-content"
:items="filteredTgtOpts"
:item-size="itemSize"
key-field="value"
:show-scrollbar="false"
@resize="syncTgtVLScroller"
@scroll="syncTgtVLScroller"
>
<template v-slot="{ item: option }">
<template #default="{ item: option }">
<n-transfer-target-list-item
:key="option.value"
:value="option.value"
:disabled="!!option.disabled"
:label="option.label"
@click="handleTargetCheckboxClick"
/>
</template>
</recycle-scroller>
</n-scrollbar> -->
<n-scrollbar :theme="mergedTheme">
</virtual-list>
</n-scrollbar>
<n-scrollbar
v-else
:theme="mergedTheme"
>
<div class="n-transfer-list-content">
<transition-group name="item" :appear="isMounted" :css="!isInputing">
<n-transfer-target-list-item
@ -182,6 +190,9 @@
</template>
<script>
import { ref } from 'vue'
import { VirtualList } from 'vueuc'
import { useIsMounted } from 'vooks'
import NScrollbar from '../../scrollbar'
import NTransferHeaderCheckbox from './TransferHeaderCheckbox.vue'
import NTransferHeaderExtra from './TransferHeaderExtra.vue'
@ -200,9 +211,9 @@ import {
locale
} from '../../_mixins'
import styles from './styles'
import { warn } from '../../_utils/naive'
import { call } from '../../_utils/vue'
import { useIsMounted } from 'vooks'
import { depx } from '../../_utils/css'
import { createKey } from '../../_utils/cssr'
import { warn, call } from '../../_utils'
import { data } from './data-utils'
export default {
@ -217,8 +228,8 @@ export default {
NInput,
NIcon,
NEmpty,
SearchIcon
// RecycleScroller
SearchIcon,
VirtualList
},
mixins: [
configurable,
@ -280,7 +291,7 @@ export default {
validator (value) {
return ['small', 'medium', 'large'].includes(value)
},
default: null
default: undefined
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': {
@ -303,9 +314,18 @@ export default {
setup (props) {
return {
isMounted: useIsMounted(),
srcScrollerRef: ref(null),
tgtScrollerRef: ref(null),
srcVlRef: ref(null),
tgtVlRef: ref(null),
...data(props)
}
},
computed: {
itemSize () {
return depx(this.cssrProps.$local[createKey('itemHeight', this.mergedSize)])
}
},
methods: {
doUpdateValue (...args) {
const {
@ -373,6 +393,31 @@ export default {
const tgtCheckedValueSet = new Set(this.tgtCheckedValues)
this.doUpdateValue((this.value || []).filter(v => !tgtCheckedValueSet.has(v)))
this.tgtCheckedValues = []
},
// scroll related
syncSrcVLScroller () {
const {
srcScrollerRef
} = this
srcScrollerRef && srcScrollerRef.sync()
},
syncTgtVLScroller () {
const {
tgtScrollerRef
} = this
tgtScrollerRef && tgtScrollerRef.sync()
},
srcScrollContainer () {
return this.srcVlRef?.listRef
},
srcScrollContent () {
return this.srcVlRef?.itemsRef
},
tgtScrollContainer () {
return this.tgtVlRef?.listRef
},
tgtScrollContent () {
return this.tgtVlRef?.itemsRef
}
}
}

View File

@ -5,7 +5,7 @@
:indeterminate="checkboxProps.indeterminate"
:disabled="checkboxProps.disabled"
:size="NTransfer.mergedSize"
@change="onChange"
@update:checked="onChange"
/>
</template>

View File

@ -1,12 +1,12 @@
import { c, cTB, cB, cM } from '../../../_utils/cssr'
import { c, cTB, cB, cM, createKey } from '../../../_utils/cssr'
import depx from '../../../_utils/css/depx'
import pxfy from '../../../_utils/css/pxfy'
export default c([
({ props }) => {
const size = props.$instance.mergedSize
const height = props.$local.height[size]
const fontSize = props.$local.fontSize[size]
const height = props.$local[createKey('itemHeight', size)]
const fontSize = props.$local[createKey('fontSize', size)]
return [
c(`@keyframes transfer-height-collapse--${size}`, {
raw: `

View File

@ -1,12 +1,8 @@
export default {
fontSize: {
small: '14px',
medium: '14px',
large: '15px'
},
height: {
small: '28px',
medium: '34px',
large: '40px'
}
fontSizeSmall: '14px',
fontSizeMedium: '14px',
fontSizeLarge: '15px',
itemHeightSmall: '28px',
itemHeightMedium: '34px',
itemHeightLarge: '40px'
}

View File

@ -309,5 +309,5 @@ placeable 进行了大调整
- clean delegate
- site production tag (bug)
- [x] demo scrollbar 的问题
- table x scroll 右侧阴影不消失
- [x] table x scroll 右侧阴影不消失
- [x] log scrollTo 有点问题