Appearance
BizAddressInput 地址输入
收货 / 注册 / 工单地址的标准表单件:省市区级联 + 详细地址 + 邮编 三段组合,v-model 为结构化对象整体回写,表单提交无需拼装。区划数据由业务侧注入(透传 BizRegionCascader),组件零数据依赖。
基础用法
17 / 200
邮政编码
v-model:110000 / 110100 / 110108 · 中关村大街 1 号 A 座 8 层 · 100080
v-model 一处绑定,任一段变化整体回写;
zip 开启邮编输入(仅数字、6 位截断)。<script setup lang="ts">
/** 基础用法:省市区 + 详细地址组合录入,v-model 结构化整体回写 */
import { ref } from 'vue'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressValue, BizRegionNode } from 'vue3-ep-biz-lib'
/** 演示用区划树(生产请接 china-division 包或后端字典,透传 data 即可) */
const data: BizRegionNode[] = [
{
code: '110000',
name: '北京市',
children: [
{
code: '110100',
name: '北京市',
children: [
{ code: '110105', name: '朝阳区' },
{ code: '110108', name: '海淀区' },
],
},
],
},
{
code: '320000',
name: '江苏省',
children: [
{
code: '320100',
name: '南京市',
children: [
{ code: '320102', name: '玄武区' },
{ code: '320114', name: '雨花台区' },
],
},
],
},
]
const address = ref<BizAddressValue>({
region: ['110000', '110100', '110108'],
detail: '中关村大街 1 号 A 座 8 层',
zip: '100080',
})
</script>
<template>
<div>
<BizAddressInput v-model="address" :data="data" zip />
<div class="tip">
v-model:{{ address.region.join(' / ') }} · {{ address.detail }} · {{ address.zip }}
</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
word-break: break-all;
}
</style>
显示代码
级别裁剪 · 完整地址 · 清空
9 / 200
邮政编码
level=2 只选到市;邮编仅数字录入
level=2 只选到市;getFullText() 按区划树解析「省市区名 + 详细地址」完整文本,可直接用于展示与提交冗余字段。<script setup lang="ts">
/** 进阶:getFullText() 拼完整地址 + 只到市级(level=2)+ 受控清空 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressValue, BizRegionNode } from 'vue3-ep-biz-lib'
const data: BizRegionNode[] = [
{
code: '440000',
name: '广东省',
children: [
{
code: '440100',
name: '广州市',
children: [{ code: '440106', name: '天河区' }],
},
{
code: '440300',
name: '深圳市',
children: [{ code: '440305', name: '南山区' }],
},
],
},
]
const address = ref<BizAddressValue>({ region: ['440000', '440300'], detail: '科技园南区 6 栋', zip: '' })
const inputRef = ref<InstanceType<typeof BizAddressInput> | null>(null)
const showFull = (): void => {
ElMessage.success(`完整地址:${inputRef.value?.getFullText() ?? ''}`)
}
const reset = (): void => {
address.value = { region: [], detail: '', zip: '' }
}
</script>
<template>
<div>
<BizAddressInput ref="inputRef" v-model="address" :data="data" :level="2" zip />
<div class="ops">
<ElButton size="small" @click="showFull">getFullText() 完整地址</ElButton>
<ElButton size="small" @click="reset">清空</ElButton>
<span class="tip">level=2 只选到市;邮编仅数字录入</span>
</div>
</div>
</template>
<style scoped>
.ops {
display: flex;
align-items: center;
gap: 8px;
margin-top: 8px;
}
.tip {
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
表单校验集成
el-form rules 自定义校验器:区划与详细地址分别拦截,change 即触发。
<script setup lang="ts">
/** el-form 集成:地址必填校验(区划 + 详细地址分别校验) */
import { reactive, ref } from 'vue'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressValue } from 'vue3-ep-biz-lib'
const formRef = ref<FormInstance>()
const form = reactive<{ address: BizAddressValue }>({
address: { region: [], detail: '', zip: '' },
})
const rules: FormRules = {
address: [
{
validator: (_rule, value: BizAddressValue, callback) => {
if (value.region.length === 0) callback(new Error('请选择省市区'))
else if (value.detail.trim() === '') callback(new Error('请填写详细地址'))
else callback()
},
trigger: 'change',
},
],
}
const data = [
{ code: '110000', name: '北京市', children: [{ code: '110100', name: '北京市', children: [{ code: '110105', name: '朝阳区' }, { code: '110108', name: '海淀区' }] }] },
{ code: '440000', name: '广东省', children: [{ code: '440300', name: '深圳市', children: [{ code: '440305', name: '南山区' }] }] },
]
const submit = (): void => {
void formRef.value?.validate((valid) => {
if (valid) ElMessage.success('地址校验通过,可提交')
})
}
</script>
<template>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="80px">
<ElFormItem label="收货地址" prop="address">
<BizAddressInput v-model="form.address" :data="data" zip />
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="submit">提交校验</ElButton>
</ElFormItem>
</ElForm>
</template>
显示代码
详情异步回显
邮政编码
异步回显后禁用只读;完整地址:(点下方按钮生成)
接口晚到赋值 + disabled 只读态;getFullText() 生成完整地址冗余字段一并提交。
<script setup lang="ts">
/** 详情回显:异步赋值 + 禁用只读 + getFullText 拼完整地址冗余字段 */
import { onMounted, ref } from 'vue'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressInputInstance, BizAddressValue } from 'vue3-ep-biz-lib'
const data = [
{ code: '320000', name: '江苏省', children: [{ code: '320100', name: '南京市', children: [{ code: '320114', name: '雨花台区' }] }] },
]
const address = ref<BizAddressValue>({ region: [], detail: '', zip: '' })
const fullText = ref('')
const inputRef = ref<BizAddressInputInstance | null>(null)
/** 模拟详情接口 800ms 后返回(异步回显场景) */
onMounted(() => {
setTimeout(() => {
address.value = { region: ['320000', '320100', '320114'], detail: '软件大道 101 号 3 号楼', zip: '210012' }
}, 800)
})
</script>
<template>
<div>
<BizAddressInput ref="inputRef" v-model="address" :data="data" zip disabled />
<div class="tip">异步回显后禁用只读;完整地址:{{ fullText || '(点下方按钮生成)' }}</div>
<ElButton size="small" @click="fullText = inputRef?.getFullText() ?? ''">getFullText()</ElButton>
</div>
</template>
<style scoped>
.tip {
margin: 8px 0;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
省级裁剪
11 / 200
region 仅省级代码:440000
level=1 只选省(发货仓配置场景),detail 占位与提示可定制。
<script setup lang="ts">
/** 省级单选(level=1):发货仓配置只到省 */
import { ref } from 'vue'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressValue } from 'vue3-ep-biz-lib'
const data = [
{ code: '110000', name: '北京市' },
{ code: '310000', name: '上海市' },
{ code: '440000', name: '广东省' },
{ code: '510000', name: '四川省' },
]
const province = ref<BizAddressValue>({ region: ['440000'], detail: '广州仓 / 佛山仓双仓', zip: '' })
</script>
<template>
<div>
<BizAddressInput
v-model="province"
:data="data"
:level="1"
detail-placeholder="仓库备注(可留空)"
/>
<div class="tip">region 仅省级代码:{{ province.region.join(' / ') || '(未选)' }}</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
区划数据异步加载
区划字典来自后端(或 china-division 包本地引入),异步到位前骨架占位
data 由后端字典 / china-division 注入,到位前骨架占位,组件本身零数据依赖。
<script setup lang="ts">
/** 区划树异步加载:接口返回后再渲染(loading 占位) */
import { onMounted, ref } from 'vue'
import { BizAddressInput } from 'vue3-ep-biz-lib'
import type { BizAddressValue, BizRegionNode } from 'vue3-ep-biz-lib'
const data = ref<BizRegionNode[]>([])
const loading = ref(true)
const address = ref<BizAddressValue>({ region: [], detail: '', zip: '' })
onMounted(() => {
setTimeout(() => {
data.value = [
{ code: '330000', name: '浙江省', children: [{ code: '330100', name: '杭州市', children: [{ code: '330106', name: '西湖区' }] }] },
{ code: '500000', name: '重庆市', children: [{ code: '500100', name: '重庆市', children: [{ code: '500103', name: '渝中区' }] }] },
]
loading.value = false
}, 800)
})
</script>
<template>
<div>
<ElSkeleton v-if="loading" animated :rows="2" style="width: 320px" />
<BizAddressInput v-else v-model="address" :data="data" zip />
<div class="tip">区划字典来自后端(或 china-division 包本地引入),异步到位前骨架占位</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| model-value / v-model | BizAddressValue | — | 结构化地址值(region / detail / zip) |
| data | BizRegionNode[] | [] | 区划数据树(透传 BizRegionCascader) |
| level | 1 | 2 | 3 | 3 | 选择深度:省 / 市 / 区 |
| detail-placeholder | string | '街道、楼牌号等详细信息' | 详细地址占位文案 |
| zip | boolean | false | 显示邮政编码输入 |
| maxlength | number | 200 | 详细地址最大长度(带字数统计) |
| disabled | boolean | false | 禁用全部输入 |
| clearable | boolean | true | 区划可清空 |
BizAddressValue
| 字段 | 类型 | 说明 |
|---|---|---|
| region | string[] | 省市区代码路径(与 BizRegionCascader v-model 同构) |
| detail | string | 详细地址 |
| zip | string | 邮政编码(zip 开启时) |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| update:model-value | (value: BizAddressValue) | 地址任一段变化 |
| change | (value: BizAddressValue) | 同 update:model-value |
Slots
| 插槽名 | 说明 |
|---|---|
| — | 无插槽 |
Expose
| 属性/方法 | 说明 |
|---|---|
| getFullText | () => string 完整地址文本(区划名 + 详细地址;树未注入时代码占位) |