Skip to content

Commit b5f139a

Browse files
committed
feat : 增加懒加载完善组件文档
1 parent d94c3f0 commit b5f139a

File tree

4 files changed

+293
-188
lines changed

4 files changed

+293
-188
lines changed

packages/devui-vue/devui/editable-select/src/editable-select-types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export const editableSelectProps = {
3535
loading: {
3636
type: Boolean
3737
},
38+
enableLazyLoad: {
39+
type: Boolean,
40+
default: false
41+
},
3842
remoteMethod: {
3943
type: Function as PropType<(inputValue: string) => Array<Options>>
4044
},
Lines changed: 84 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,43 @@
1-
import { defineComponent, ref, renderSlot, computed, Transition } from "vue"
2-
import {
3-
OptionItem,
4-
editableSelectProps,
5-
EditableSelectProps,
6-
} from "./editable-select-types"
7-
import "./editable-select.scss"
8-
import { Icon } from "../../icon"
9-
import ClickOutside from "../../shared/devui-directive/clickoutside"
10-
import { className } from "./utils"
11-
import { debounce } from "lodash"
1+
import { defineComponent, ref, renderSlot, computed, Transition, watch } from 'vue'
2+
import { OptionItem, editableSelectProps, EditableSelectProps } from './editable-select-types'
3+
import './editable-select.scss'
4+
import { Icon } from '../../icon'
5+
import ClickOutside from '../../shared/devui-directive/clickoutside'
6+
import { className } from './utils'
7+
import { debounce } from 'lodash'
128
export default defineComponent({
13-
name: "DEditableSelect",
9+
name: 'DEditableSelect',
1410
directives: { ClickOutside },
1511
props: editableSelectProps,
16-
emits: ["update:modelValue"],
12+
emits: ['update:modelValue'],
1713
setup(props: EditableSelectProps, ctx) {
18-
const inputCls = className(
19-
"devui-form-control devui-dropdown-origin devui-dropdown-origin-open",
20-
{
21-
disabled: props.disabled,
22-
}
23-
)
24-
25-
const getLiCls = (item) => {
26-
const { disabledKey } = props
27-
return className("devui-dropdown-item", {
28-
disabled: disabledKey ? !!item[disabledKey] : false,
29-
})
30-
}
31-
14+
const dropdownRef = ref(null)
3215
const visible = ref(false)
33-
const inputValue = ref("")
16+
const inputValue = ref('')
17+
const activeIndex = ref(0)
3418
const query = ref(props.modelValue)
3519

3620
const wait = computed(() => (props.remote ? 300 : 0))
3721

3822
const emptyText = computed(() => {
3923
const options = filteredOptions.value
40-
if (!props.remote && inputValue.value && options.length === 0) {
41-
return "没有相关记录"
24+
if (!props.remote && options.length === 0) {
25+
return '没有相关记录'
4226
}
4327
if (options.length === 0) {
44-
return "没有数据"
28+
return '没有数据'
4529
}
4630
return null
4731
})
32+
4833
const normalizeOptions = computed(() => {
4934
let options: OptionItem
5035
const { disabledKey } = props
51-
disabledKey ? disabledKey : "disabled"
36+
disabledKey ? disabledKey : 'disabled'
5237
return props.options.map((item) => {
53-
if (typeof item !== "object") {
38+
if (typeof item !== 'object') {
5439
options = {
55-
name: item,
40+
name: item
5641
}
5742
return options
5843
}
@@ -61,9 +46,11 @@ export default defineComponent({
6146
})
6247

6348
const filteredOptions = computed(() => {
64-
const isValidOption = (o: OptionItem): boolean => {
49+
const isValidOption = (o: OptionItem) => {
6550
const query = inputValue.value
66-
const containsQueryString = query ? o.name.includes(query) : true
51+
const containsQueryString = query
52+
? o.name.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) >= 0
53+
: true
6754
return containsQueryString
6855
}
6956
return normalizeOptions.value
@@ -76,6 +63,12 @@ export default defineComponent({
7663
.filter((item) => item !== null)
7764
})
7865

66+
const findIndex = (o) => {
67+
return normalizeOptions.value.findIndex((item) => {
68+
return item.name === o.name
69+
})
70+
}
71+
7972
const handleClose = () => {
8073
visible.value = false
8174
}
@@ -84,11 +77,12 @@ export default defineComponent({
8477
visible.value = !visible.value
8578
}
8679
}
87-
const onInputChange = () => {
80+
81+
const onInputChange = (val: string) => {
8882
if (props.filterMethod) {
89-
props.filterMethod(inputValue.value)
83+
props.filterMethod(val)
9084
} else if (props.remote) {
91-
props.remoteMethod(inputValue.value)
85+
props.remoteMethod(val)
9286
}
9387
}
9488

@@ -99,65 +93,83 @@ export default defineComponent({
9993
inputValue.value = value
10094
query.value = value
10195
if (props.remote) {
102-
debouncedOnInputChange()
96+
debouncedOnInputChange(value)
10397
} else {
104-
onInputChange()
98+
onInputChange(value)
10599
}
106100
}
101+
107102
const selectOptionClick = (e, item) => {
108103
const { disabledKey } = props
109104
if (disabledKey && item[disabledKey]) {
110105
e.stopPropagation()
111106
} else {
112107
query.value = item.name
113-
ctx.emit("update:modelValue", item.name)
108+
activeIndex.value = findIndex(item)
109+
inputValue.value = ''
110+
ctx.emit('update:modelValue', item.name)
114111
}
115112
}
113+
114+
const loadMore = () => {
115+
if (!props.enableLazyLoad) return
116+
const dropdownVal = dropdownRef.value
117+
if (dropdownVal.clientHeight + dropdownVal.scrollTop >= dropdownVal.scrollHeight) {
118+
props.remoteMethod(inputValue.value)
119+
}
120+
}
121+
116122
return () => {
123+
const selectCls = className('devui-form-group devui-has-feedback', {
124+
'devui-select-open': visible.value
125+
})
126+
const inputCls = className(
127+
'devui-form-control devui-dropdown-origin devui-dropdown-origin-open',
128+
{
129+
disabled: props.disabled
130+
}
131+
)
132+
133+
const getLiCls = (item, index) => {
134+
const { disabledKey } = props
135+
return className('devui-dropdown-item', {
136+
disabled: disabledKey ? !!item[disabledKey] : false,
137+
selected: activeIndex.value === index
138+
})
139+
}
140+
117141
return (
118-
<div
119-
class="devui-form-group devui-has-feedback devui-select-open"
120-
v-click-outside={handleClose}
121-
onClick={toggleMenu}
122-
>
123-
<input
124-
class={inputCls}
125-
type="text"
126-
onInput={handleInput}
127-
value={query.value}
128-
/>
129-
<span class="devui-form-control-feedback">
130-
<span class="devui-select-chevron-icon">
131-
<Icon name="select-arrow" />
142+
<div class={selectCls} v-click-outside={handleClose} onClick={toggleMenu}>
143+
<input class={inputCls} type='text' onInput={handleInput} value={query.value} />
144+
<span class='devui-form-control-feedback'>
145+
<span class='devui-select-chevron-icon'>
146+
<Icon name='select-arrow' />
132147
</span>
133148
</span>
134-
<div class="devui-editable-select">
135-
<Transition name="fade">
136-
<div class="devui-dropdown-menu" v-show={visible.value}>
149+
<div class='devui-editable-select'>
150+
<Transition name='fade'>
151+
<div class='devui-dropdown-menu' v-show={visible.value}>
137152
<ul
138-
class="devui-list-unstyled scroll-height"
153+
class='devui-list-unstyled scroll-height'
154+
ref={dropdownRef}
139155
style={{
140-
maxHeight: props.maxHeight + "px",
156+
maxHeight: props.maxHeight + 'px'
141157
}}
158+
onScroll={loadMore}
142159
>
143-
{filteredOptions.value.map((item) => {
160+
{filteredOptions.value.map((item, index) => {
144161
return (
145162
<li
146-
class={getLiCls(item)}
163+
class={getLiCls(item, index)}
147164
onClick={($evnet) => selectOptionClick($evnet, item)}
148165
key={item.name}
149166
>
150-
{ctx.slots.default
151-
? renderSlot(ctx.slots, "default", { item })
152-
: item.name}
167+
{ctx.slots.default ? renderSlot(ctx.slots, 'default', { item }) : item.name}
153168
</li>
154169
)
155170
})}
156-
<li
157-
class="devui-no-result-template"
158-
v-show={filteredOptions.value.length === 0}
159-
>
160-
<div class="devui-no-data-tip">{emptyText.value}</div>
171+
<li class='devui-no-result-template' v-show={filteredOptions.value.length === 0}>
172+
<div class='devui-no-data-tip'>{emptyText.value}</div>
161173
</li>
162174
</ul>
163175
</div>
@@ -166,5 +178,5 @@ export default defineComponent({
166178
</div>
167179
)
168180
}
169-
},
181+
}
170182
})

0 commit comments

Comments
 (0)