The cascader component is used for the selection of multi-level data. The typical scene is the selection of provinces and cities.
import { createApp } from 'vue';
import { Cascader, Tabs, TabPane } from '@nutui/nutui';
const app = createApp();
app.use(Cascader);
app.use(Tabs);
app.use(TabPane);
Pass in the options list.
:::demo
<template>
<nut-form>
<nut-form-item label="Select address">
<input
class="nut-input-text"
@click="state.visible = true"
:value="state.value"
readonly
placeholder="Please select an address"
type="text"
/>
<nut-cascader
title="Select address"
v-model:visible="state.visible"
v-model="state.value"
@change="events.change"
@path-change="events.pathChange"
:options="state.options"
></nut-cascader>
</nut-form-item>
</nut-form>
</template>
<script lang="ts">
import { reactive } from 'vue';
export default {
setup() {
// 基础用法
const state = reactive({
visible: false,
// value: ['湖南'],
value: [],
options: [
{
value: '浙江',
text: '浙江',
children: [
{
value: '杭州',
text: '杭州',
disabled: true,
children: [
{ value: '西湖区', text: '西湖区' },
{ value: '余杭区', text: '余杭区' }
]
},
{
value: '温州',
text: '温州',
children: [
{ value: '鹿城区', text: '鹿城区' },
{ value: '瓯海区', text: '瓯海区' }
]
}
]
},
{
value: '湖南',
text: '湖南',
disabled: true
},
{
value: '福建',
text: '福建',
children: [
{
value: '福州',
text: '福州',
children: [
{ value: '鼓楼区', text: '鼓楼区' },
{ value: '台江区', text: '台江区' }
]
}
]
}
]
});
const events = {
change(...args: any) {
console.log('change', ...args);
},
pathChange(...args: any) {
console.log('pathChange', ...args);
}
};
return {
state,
events
}
}
}
</script>
:::
use textKey、valueKey、childrenKeySpecify the property name.
:::demo
<template>
<nut-form>
<nut-form-item label="Select address">
<input
class="nut-input-text"
@click="state.visible = true"
:value="state.value"
readonly
placeholder="Please select an address"
type="text"
/>
<nut-cascader
title="Select address"
v-model:visible="state.visible"
v-model="state.value"
text-key="text"
@change="events.change"
@path-change="events.pathChange"
value-key="text"
children-key="items"
:options="state.options"
></nut-cascader>
</nut-form-item>
</nut-form>
</template>
<script lang="ts">
import { reactive } from 'vue';
export default {
setup() {
// 自定义属性名称
const state = reactive({
visible: false,
value: ['福建', '福州', '台江区'],
options: [
{
text: '浙江',
items: [
{
text: '杭州',
disabled: true,
items: [{ text: '西湖区' }, { text: '余杭区' }]
},
{
text: '温州',
items: [{ text: '鹿城区' }, { text: '瓯海区' }]
}
]
},
{
text: '福建',
items: [
{
text: '福州',
items: [{ text: '鼓楼区' }, { text: '台江区' }]
}
]
}
]
});
const events = {
change(...args: any) {
console.log('change', ...args);
},
pathChange(...args: any) {
console.log('pathChange', ...args);
},
};
return { state, events };
}
}
</script>
:::
Use lazy to identify whether data needs to be obtained dynamically. At this time, not transmitting options means that all data needs to be loaded through lazyload . The first loading is distinguished by the root attribute. When a non leaf node is encountered, the lazyload method will be called. The parameters are the current node and the resolve method. Note that the resolve method must be called. If it is not transmitted to a child node, it will be treated as a leaf node.
:::demo
<template>
<nut-form>
<nut-form-item label="Select address">
<input
class="nut-input-text"
@click="state.visible = true"
:value="state.value"
readonly
placeholder="Please select an address"
type="text"
/>
<nut-cascader
title="Select address"
v-model:visible="state.visible"
v-model="state.value"
@change="events.change"
@path-change="events.pathChange"
lazy
:lazy-load="state.lazyLoad"
></nut-cascader>
</nut-form-item>
</nut-form>
</template>
<script lang="ts">
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
visible: false,
value: ['A0', 'A12', 'A23', 'A32'],
lazyLoad(node: any, resolve: (children: any) => void) {
setTimeout(() => {
// root表示第一层数据
if (node.root) {
resolve([
{ value: 'A0', text: 'A0' },
{ value: 'B0', text: 'B0' },
{ value: 'C0', text: 'C0' }
]);
} else {
const { value, level } = node;
const text = value.substring(0, 1);
const value1 = `${text}${level + 1}1`;
const value2 = `${text}${level + 1}2`;
const value3 = `${text}${level + 1}3`;
resolve([
{ value: value1, text: value1, leaf: level >= 6 },
{ value: value2, text: value2, leaf: level >= 6 },
{ value: value3, text: value3, leaf: level >= 6 }
]);
}
}, 300);
}
});
const events = {
change(...args: any) {
console.log('change', ...args);
},
pathChange(...args: any) {
console.log('pathChange', ...args);
},
};
return { state, events };
}
}
</script>
:::
:::demo
<template>
<nut-form>
<nut-form-item label="Select address">
<input
class="nut-input-text"
@click="state.visible = true"
:value="state.value"
readonly
placeholder="Please select an address"
type="text"
/>
<nut-cascader
title="Select address"
v-model:visible="state.visible"
v-model="state.value"
@change="events.change"
@path-change="events.pathChange"
:options="state.options"
lazy
:lazy-load="state.lazyLoad"
></nut-cascader>
</nut-form-item>
</nut-form>
</template>
<script lang="ts">
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
visible: false,
value: [],
options: [
{ value: 'A0', text: 'A0' },
{
value: 'B0',
text: 'B0',
children: [
{ value: 'B11', text: 'B11', leaf: true },
{ value: 'B12', text: 'B12' }
]
},
{ value: 'C0', text: 'C0' }
],
lazyLoad(node: any, resolve: (children: any) => void) {
setTimeout(() => {
const { value, level } = node;
const text = value.substring(0, 1);
const value1 = `${text}${level + 1}1`;
const value2 = `${text}${level + 1}2`;
resolve([
{ value: value1, text: value1, leaf: level >= 2 },
{ value: value2, text: value2, leaf: level >= 1 }
]);
}, 500);
}
});
const events = {
change(...args: any) {
console.log('change', ...args);
},
pathChange(...args: any) {
console.log('pathChange', ...args);
},
};
return { state, events };
}
}
</script>
:::
If your data is a flat structure that can be converted into a tree structure, you can tell the component that automatic conversion is required through convertConfig, convertConfig accepts four parameters, topid is the parent ID of the top-level node, idkey is the unique ID of the node, pidkey is the attribute name pointing to the parent node ID, and if there is a sortkey, Array.prototype.sort() to sort at the same level.
:::demo
<template>
<nut-form>
<nut-form-item label="Select address" @click="state.visible = true">
<input
class="nut-input-text"
@click="state.visible = true"
:value="state.value"
readonly
placeholder="Please select an address"
type="text"
/>
<nut-cascader
title="Select address"
v-model:visible="state.visible"
v-model="state.value"
@change="events.change"
@path-change="events.pathChange"
:options="state.options"
:convertConfig="state.convertConfig"
></nut-cascader>
</nut-form-item>
</nut-form>
</template>
<script lang="ts">
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
visible: false,
value: ['广东省', '广州市'],
convertConfig: {
topId: null,
idKey: 'id',
pidKey: 'pid',
sortKey: ''
},
options: [
{ value: '北京', text: '北京', id: 1, pid: null },
{ value: '朝阳区', text: '朝阳区', id: 11, pid: 1 },
{ value: '亦庄', text: '亦庄', id: 111, pid: 11 },
{ value: '广东省', text: '广东省', id: 2, pid: null },
{ value: '广州市', text: '广州市', id: 21, pid: 2 }
]
});
const events = {
change(...args: any) {
console.log('change', ...args);
},
pathChange(...args: any) {
console.log('pathChange', ...args);
},
};
return { state, events };
}
}
</script>
:::
| Attribute | Description | Type | Default |
|---|---|---|---|
| v-model | Selected value, bidirectional binding | Array | - |
| options | Cascade data | Array | - |
| lazy | Whether to enable dynamic loading | Boolean | - |
| lazy-load | Dynamic loading callback, which takes effect when dynamic loading is enabled | Function | - |
| value-key | Customize the field of value in the options structure |
String | - |
| text-key | Customize the fields of text in the options structure |
String | - |
| children-key | Customize the fields of children in the options structure |
String | - |
| convert-config | When options is a flat structure that can be converted into a tree structure, configure the conversion rules | Object | - |
| title | Title | String | '' |
| close-icon-position | Cancel the button position and inherit the popup component | String | "top-right" |
| close-icon | Customize the close button and inherit the popup component | String | "close" |
| closeable | Whether to display the close button and inherit the popup component | Boolean | true |
| poppable | Whether to display the popup(After setting to false, the title is invalid) | Boolean | true |
| Event | Description | Arguments |
|---|---|---|
| change | Triggered when the selected value changes | (value, pathNodes) |
| path-change | Triggered when the selected item changes | (pathNodes) |
The component provides the following CSS variables, which can be used to customize styles. Please refer to ConfigProvider component.
| Name | Default Value | Description |
|---|---|---|
| --nut-cascader-font-size | var(--nut-font-size-2) | - |
| --nut-cascader-line-height | 22px | - |
| --nut-cascader-tabs-item-padding | 0 10px | - |
| --nut-cascader-bar-padding | 24px 20px 17px | - |
| --nut-cascader-bar-font-size | var(--nut-font-size-4) | - |
| --nut-cascader-bar-line-height | 20px | - |
| --nut-cascader-bar-color | var(--nut-title-color) | - |
| --nut-cascader-item-padding | 10px 20px | - |
| --nut-cascader-item-color | var(--nut-title-color) | - |
| --nut-cascader-item-font-size | var(--nut-font-size-2) | - |
| --nut-cascader-item-active-color | var(--nut-primary-color) | - |