介绍
组合了级联弹出框、输入框组件,实现了便捷快速的级联选择功能。
代码演示
基础使用
使用 v-model 绑定当前值,通过 title 和 placeholder 属性设置弹出框标题和输入框占位文本。
在点击输入框后会显示级联弹出框。
vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:" :value="JSON.stringify(value) ?? 'undefined'" />
<s-list-item
title="设置为:440111 (广东省/广州市/白云区)"
arrow
hover
@click="value = 440111"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getRegionData, type Node } from 'region-data'
const regionData = getRegionData()
const options = ref<Node[]>([])
const loading = ref(true)
setTimeout(() => {
options.value = regionData
loading.value = false
}, 1500)
const value = ref<number | undefined>(440111)
const optionKeys = { label: 'name', value: 'code' }
const onChange = (value: any, selectedOptions: any) => {
console.log('change', value, selectedOptions)
}
</script>vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:" :value="JSON.stringify(value) ?? 'undefined'" />
<s-list-item
title="设置为:440111 (广东省/广州市/白云区)"
arrow
hover
@click="value = 440111"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
import { getRegionData } from 'region-data'
const regionData = getRegionData()
const options = ref([])
const loading = ref(true)
setTimeout(() => {
options.value = regionData
loading.value = false
}, 1500)
const value = ref(440111)
const optionKeys = {
label: 'name',
value: 'code',
}
const onChange = (value, selectedOptions) => {
console.log('change', value, selectedOptions)
}
</script>多选
设置 multiple 可进行多选,设置 max-rows 可限制输入框展示的行数。
vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
multiple
all-levels
check-strictly
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:">
<template #value>
<div class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</div>
</template>
</s-list-item>
<s-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getRegionData, type Node } from 'region-data'
import { type CascaderValue } from 'sard'
const regionData = getRegionData()
const options = ref<Node[]>([])
const loading = ref(true)
setTimeout(() => {
options.value = regionData
loading.value = false
}, 1500)
const value = ref<CascaderValue | undefined>([
[440000, 440100, 440106],
[440000, 440100, 440111],
])
const optionKeys = { label: 'name', value: 'code' }
const onChange = (value: any, selectedOptions: any) => {
console.log('change', value, selectedOptions)
}
</script>vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
multiple
all-levels
check-strictly
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:">
<template #value>
<div class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</div>
</template>
</s-list-item>
<s-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="js">
import { ref } from 'vue'
import { getRegionData } from 'region-data'
import 'sard'
const regionData = getRegionData()
const options = ref([])
const loading = ref(true)
setTimeout(() => {
options.value = regionData
loading.value = false
}, 1500)
const value = ref([
[44e4, 440100, 440106],
[44e4, 440100, 440111],
])
const optionKeys = {
label: 'name',
value: 'code',
}
const onChange = (value, selectedOptions) => {
console.log('change', value, selectedOptions)
}
</script>懒加载
没有加载到数据时,输入框会暂时展示值,而不是标签文本,当加载完数据时,才替换为标签文本。
vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:field-keys="{ label: 'name', value: 'code', isLeaf: 'isLeaf' }"
lazy
:load="loadNode"
multiple
all-levels
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:">
<template #value>
<div class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</div>
</template>
</s-list-item>
<s-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="ts">
import { mapProvinces, mapCities, mapCounties } from 'region-data'
import { type CascaderValue, type CascaderOption, type CascaderStateNode } from 'sard'
import { ref } from 'vue'
const doGetTreeData = (parentId?: number) => {
if (!parentId) {
return Object.entries(mapProvinces).map(([code, name]) => ({
code: +code,
name,
isLeaf: false,
}))
} else {
const isProvince = /^\d{2}0{4}/.test(String(parentId))
const isCity = !isProvince && /^\d{4}0{2}/.test(String(parentId))
const prefixCode = isProvince
? String(parentId).slice(0, 2)
: isCity
? String(parentId).slice(0, 4)
: ''
const map = isProvince ? mapCities : isCity ? mapCounties : {}
return Object.entries(map)
.filter(([code]) => String(code).startsWith(prefixCode))
.map(([code, name]) => ({
code: +code,
name,
isLeaf: isCity,
}))
}
}
const getTreeData = (parentId?: number) => {
return new Promise<ReturnType<typeof doGetTreeData>>((resolve, reject) => {
setTimeout(() => {
try {
const treeData = doGetTreeData(parentId)
resolve(treeData)
} catch {
reject()
}
}, 500)
})
}
const value = ref<CascaderValue | undefined>([
[440000, 440100, 440106],
[440000, 440100, 440111],
])
const loadNode = async (node?: CascaderStateNode) => {
return await getTreeData(node?.key as number)
}
const onChange = (value: any, selectedOptions: CascaderOption[]) => {
console.log('change', value, selectedOptions)
}
</script>vue
<template>
<s-list card>
<s-list-item>
<s-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:field-keys="{ label: 'name', value: 'code', isLeaf: 'isLeaf' }"
lazy
:load="loadNode"
multiple
all-levels
@change="onChange"
/>
</s-list-item>
<s-list-item title="当前值:">
<template #value>
<div class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</div>
</template>
</s-list-item>
<s-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<s-list-item title="清空" arrow hover @click="value = undefined" />
</s-list>
</template>
<script setup lang="js">
import { mapProvinces, mapCities, mapCounties } from 'region-data'
import 'sard'
import { ref } from 'vue'
const doGetTreeData = (parentId) => {
if (!parentId) {
return Object.entries(mapProvinces).map(([code, name]) => ({
code: +code,
name,
isLeaf: false,
}))
} else {
const isProvince = /^\d{2}0{4}/.test(String(parentId))
const isCity = !isProvince && /^\d{4}0{2}/.test(String(parentId))
const prefixCode = isProvince
? String(parentId).slice(0, 2)
: isCity
? String(parentId).slice(0, 4)
: ''
const map = isProvince ? mapCities : isCity ? mapCounties : {}
return Object.entries(map)
.filter(([code]) => String(code).startsWith(prefixCode))
.map(([code, name]) => ({
code: +code,
name,
isLeaf: isCity,
}))
}
}
const getTreeData = (parentId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
const treeData = doGetTreeData(parentId)
resolve(treeData)
} catch {
reject()
}
}, 500)
})
}
const value = ref([
[44e4, 440100, 440106],
[44e4, 440100, 440111],
])
const loadNode = async (node) => {
return await getTreeData(node?.key)
}
const onChange = (value, selectedOptions) => {
console.log('change', value, selectedOptions)
}
</script>API
CascaderInputProps
继承 CascaderPopoutProps 和 PopoutInputProps 。
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| max-rows | 多选时,输入框最大展示行数,设为 -1 表示不限制 | number | 3 |
CascaderInputSlots
继承 CascaderPopoutSlots和PopoutInputSlots