介绍
组合了级联弹出框、输入框组件,实现了便捷快速的级联选择功能。
引入
js
import CascaderInput from 'sard-uniapp/components/cascader-input/cascader-input.vue'代码演示
基础使用
使用 v-model 绑定当前值,通过 title 和 placeholder 属性设置弹出框标题和输入框占位文本。
在点击输入框后会显示级联弹出框。
vue
<template>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
@change="onChange"
/>
</sar-list-item>
<sar-list-item
title="当前值:"
:value="JSON.stringify(value) ?? 'undefined'"
/>
<sar-list-item
title="设置为:440111 (广东省/广州市/白云区)"
arrow
hover
@click="value = 440111"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-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>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
@change="onChange"
/>
</sar-list-item>
<sar-list-item
title="当前值:"
:value="JSON.stringify(value) ?? 'undefined'"
/>
<sar-list-item
title="设置为:440111 (广东省/广州市/白云区)"
arrow
hover
@click="value = 440111"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-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 = (value2, selectedOptions) => {
console.log("change", value2, selectedOptions);
};
</script>多选
设置 multiple 可进行多选,设置 max-rows 可限制输入框展示的行数。
vue
<template>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
multiple
all-levels
check-strictly
@change="onChange"
/>
</sar-list-item>
<sar-list-item title="当前值:">
<template #value>
<view class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</view>
</template>
</sar-list-item>
<sar-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-list>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getRegionData, type Node } from 'region-data'
import { type CascaderValue } from 'sard-uniapp'
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>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:options="options"
:option-keys="optionKeys"
:loading="loading"
multiple
all-levels
check-strictly
@change="onChange"
/>
</sar-list-item>
<sar-list-item title="当前值:">
<template #value>
<view class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</view>
</template>
</sar-list-item>
<sar-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-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([
[44e4, 440100, 440106],
[44e4, 440100, 440111]
]);
const optionKeys = { label: "name", value: "code" };
const onChange = (value2, selectedOptions) => {
console.log("change", value2, selectedOptions);
};
</script>懒加载 1.25.5+
没有加载到数据时,输入框会暂时展示值,而不是标签文本,当加载完数据时,才替换为标签文本。
vue
<template>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:field-keys="{ label: 'name', value: 'code', isLeaf: 'isLeaf' }"
lazy
:load="loadNode"
multiple
all-levels
@change="onChange"
/>
</sar-list-item>
<sar-list-item title="当前值:">
<template #value>
<view class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</view>
</template>
</sar-list-item>
<sar-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-list>
</template>
<script setup lang="ts">
import { mapProvinces, mapCities, mapCounties } from 'region-data'
import {
type CascaderValue,
type CascaderOption,
type CascaderStateNode,
} from 'sard-uniapp'
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>
<sar-list card>
<sar-list-item>
<sar-cascader-input
v-model="value"
title="请选择省市区"
placeholder="请选择省市区"
clearable
:field-keys="{ label: 'name', value: 'code', isLeaf: 'isLeaf' }"
lazy
:load="loadNode"
multiple
all-levels
@change="onChange"
/>
</sar-list-item>
<sar-list-item title="当前值:">
<template #value>
<view class="line-clamp-3">
{{ JSON.stringify(value) ?? 'undefined' }}
</view>
</template>
</sar-list-item>
<sar-list-item
title="设置为:[[440000, 440100, 440106], [440000, 440100, 440111]] ([天河区, 白云区])"
arrow
hover
@click="
value = [
[440000, 440100, 440106],
[440000, 440100, 440111],
]
"
/>
<sar-list-item title="清空" arrow hover @click="value = undefined" />
</sar-list>
</template>
<script setup lang="js">
import { mapProvinces, mapCities, mapCounties } from "region-data";
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 = (value2, selectedOptions) => {
console.log("change", value2, selectedOptions);
};
</script>API
CascaderInputProps
继承 CascaderPopoutProps 并有以下额外属性:
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| root-class | 弹出式输入框根元素类名 | string | - |
| root-style | 弹出式输入框根元素样式 | StyleValue | - |
| disabled | 禁用状态 | boolean | false |
| readonly | 只读状态 | boolean | false |
| loading | 加载状态 | boolean | false |
| clearable | 是否显示清空按钮 | boolean | false |
| placeholder | 输入框占位符内容 | string | - |
| value-on-clear 1.19.2+ | 设置点击清除按钮后的值 | () => any | () => undefined |
| arrow 1.22+ | 自定义箭头图标名 | string | 'caret-right' |
| arrow-family 1.22+ | 自定义箭头图标字体 | string | 'sari' |
| input-props 1.22+ | 自定义输入框组件属性 | InputProps | - |
| max-rows 1.25.5+ | 多选时,输入框最大展示行数,设为 -1 表示不限制 | number | 3 |
CascaderInputSlots
继承 CascaderPopoutSlots和PopoutInputSlots