Appearance
BizIpInput IP 地址输入
IPv4 四段式输入:每段 0-255 逐段校验、满 3 位自动跳段、退格空段回跳、方向键跨段移动、粘贴整段 IP 自动解析。v-model 为 'a.b.c.d' 字符串,运维 / 网管平台的服务器地址、网关、DNS 配置标准件。
端口段(v0.7 show-port):IP 末段满 3 位自动跳入端口(仅数字、1-65535 校验),v-model 变为 'a.b.c.d:port';粘贴 ip:port 整串自动分发,服务地址 / 中间件节点登记一步到位。
基础用法
···
v-model:192.168.1.10(满 3 位自动跳段,可直接粘贴整段 IP)
四段录入自动跳段;空段输出前按 0 补齐。
<script setup lang="ts">
/** 基础用法:四段录入 + 自动跳段 + 粘贴整段解析 */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const ip = ref('192.168.1.10')
</script>
<template>
<div>
<BizIpInput v-model="ip" />
<div class="tip">v-model:{{ ip }}(满 3 位自动跳段,可直接粘贴整段 IP)</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
校验 · 尺寸 · 禁用
···
禁用
validate() 编程式校验;css 变量 --biz-ip-input-width 控制宽度。<script setup lang="ts">
/** 进阶:编程式校验 + css 变量改宽 + 禁用 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizIpInput } from 'vue3-ep-biz-lib'
import type { BizIpInputInstance } from 'vue3-ep-biz-lib'
const ip = ref('')
const disabled = ref(false)
const inputRef = ref<BizIpInputInstance | null>(null)
const check = (): void => {
const result = inputRef.value?.validate()
if (result !== undefined && result.valid) {
ElMessage.success(`校验通过:${ip.value || '(空,视为通过)'}`)
}
}
</script>
<template>
<div>
<BizIpInput ref="inputRef" v-model="ip" :disabled="disabled" style="--biz-ip-input-width: 260px" />
<div class="ops">
<ElButton size="small" @click="check">validate() 校验</ElButton>
<ElSwitch v-model="disabled" active-text="禁用" />
</div>
</div>
</template>
<style scoped>
.ops {
display: flex;
align-items: center;
gap: 12px;
margin-top: 8px;
}
</style>
显示代码
起止 IP 网段
···
···
双输入联动:起始不得大于结束;validate() 组合业务校验(授权网段场景)。
<script setup lang="ts">
/** 起止 IP 联动:起始不得大于结束(网段授权场景) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizIpInput } from 'vue3-ep-biz-lib'
import type { BizIpInputInstance } from 'vue3-ep-biz-lib'
const start = ref('192.168.1.1')
const end = ref('192.168.1.50')
const startRef = ref<BizIpInputInstance | null>(null)
const endRef = ref<BizIpInputInstance | null>(null)
const toNumber = (ip: string): number =>
ip.split('.').reduce((sum, seg) => sum * 256 + Number(seg), 0)
const check = (): void => {
const a = startRef.value?.validate()
const b = endRef.value?.validate()
if (a?.valid === true && b?.valid === true) {
if (toNumber(start.value) > toNumber(end.value)) {
ElMessage.error('起始 IP 不能大于结束 IP')
return
}
ElMessage.success(`授权网段:${start.value} ~ ${end.value}(共 ${toNumber(end.value) - toNumber(start.value) + 1} 个地址)`)
}
}
</script>
<template>
<div>
<div class="range">
<BizIpInput ref="startRef" v-model="start" />
<span class="sep">~</span>
<BizIpInput ref="endRef" v-model="end" />
</div>
<ElButton size="small" style="margin-top: 10px" @click="check">校验网段</ElButton>
</div>
</template>
<style scoped>
.range {
display: flex;
align-items: center;
gap: 8px;
}
.sep {
color: var(--el-text-color-secondary);
}
</style>
显示代码
详情异步回显
···
详情加载中,1 秒后自动回显…
接口晚到赋值自动分发四段(1.0 优化点验证)。
<script setup lang="ts">
/** 异步回显:详情接口 1s 后赋值(优化后自动同步内部四段) */
import { onMounted, ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const ip = ref('')
const loaded = ref(false)
onMounted(() => {
setTimeout(() => {
ip.value = '10.20.30.40'
loaded.value = true
}, 1000)
})
</script>
<template>
<div>
<BizIpInput v-model="ip" />
<div class="tip">
{{ loaded ? `已回显:${ip}(外部赋值自动分发到四段)` : '详情加载中,1 秒后自动回显…' }}
</div>
</div>
</template>
<style scoped>
.tip {
margin-top: 8px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
</style>
显示代码
DNS 列表
DNS 1
···
DNS 2
···
多条 IP 动态增删,每条独立四段与失焦提示。
<script setup lang="ts">
/** DNS 列表:多条 IP 动态增删(每条独立校验提示) */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const dns = ref([
{ id: 1, ip: '223.5.5.5' },
{ id: 2, ip: '114.114.114.114' },
])
let seed = 2
const add = (): void => {
seed += 1
dns.value = [...dns.value, { id: seed, ip: '' }]
}
const remove = (id: number): void => {
dns.value = dns.value.filter((d) => d.id !== id)
}
</script>
<template>
<div class="list">
<div v-for="(item, i) in dns" :key="item.id" class="row">
<span class="lab">DNS {{ i + 1 }}</span>
<BizIpInput v-model="item.ip" />
<ElButton text type="danger" @click="remove(item.id)">删除</ElButton>
</div>
<ElButton size="small" dashed style="width: 100%" @click="add">+ 添加 DNS</ElButton>
</div>
</template>
<style scoped>
.row {
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 10px;
}
.lab {
width: 56px;
line-height: 32px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
.row :deep(.biz-ip-input__wrap) {
flex: 1;
}
</style>
显示代码
服务器登记表单
el-form 必填集成:IP + 端口 + 备注(运维资产登记)。
<script setup lang="ts">
/** 服务器登记表单:IP 必填 + 端口 + 备注(el-form 集成) */
import { reactive, ref } from 'vue'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { BizIpInput } from 'vue3-ep-biz-lib'
const formRef = ref<FormInstance>()
const form = reactive({ ip: '', port: 22, note: '' })
const rules: FormRules = {
ip: [{ required: true, message: '请填写服务器 IP', trigger: 'blur' }],
port: [{ required: true, message: '请填写端口', trigger: 'blur' }],
}
const submit = (): void => {
void formRef.value?.validate((valid) => {
if (valid) ElMessage.success(`登记成功:${form.ip}:${form.port}`)
})
}
</script>
<template>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="80px" style="max-width: 420px">
<ElFormItem label="服务器 IP" prop="ip">
<BizIpInput v-model="form.ip" />
</ElFormItem>
<ElFormItem label="端口" prop="port">
<ElInputNumber v-model="form.port" :min="1" :max="65535" />
</ElFormItem>
<ElFormItem label="备注">
<ElInput v-model="form.note" placeholder="机房 / 用途" />
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="submit">登记</ElButton>
</ElFormItem>
</ElForm>
</template>
显示代码
带端口基础
···:
show-port 追加端口段(仅数字、65535 截断);完整地址形如 192.168.1.100:8080, 末段满 3 位自动跳入端口输入。
show-port 追加端口段:末段满 3 位自动跳入端口,v-model 为
192.168.1.100:8080。<script setup lang="ts">
/** 场景:带端口基础——IP 末段满 3 位自动跳入端口,v-model 为 'ip:port' */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const addr = ref('192.168.1.100:8080')
</script>
<template>
<el-space direction="vertical" size="large">
<BizIpInput v-model="addr" show-port style="--biz-ip-input-width: 300px" />
<p style="margin: 0; font-size: 13px; color: var(--el-text-color-secondary)">
show-port 追加端口段(仅数字、65535 截断);完整地址形如 <code>192.168.1.100:8080</code>,
末段满 3 位自动跳入端口输入。
</p>
</el-space>
</template>
显示代码
端口校验
···:
show-port 开启时 IP 完整而端口缺失即报错(输入超 65535 自动截断到 65535,0 不合法);失焦触发。
IP 完整而端口缺失 / 端口为 0 即失焦报错;输入超 65535 自动截断。
<script setup lang="ts">
/** 场景:端口校验——缺端口 / 端口 0 越界报错(IP 段校验规则不变) */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const addr = ref('10.0.12.8:0')
</script>
<template>
<el-space direction="vertical" size="large">
<BizIpInput v-model="addr" show-port style="--biz-ip-input-width: 300px" />
<el-space>
<el-button size="small" @click="addr = '172.16.3.4'">填 IP 缺端口</el-button>
<el-button size="small" @click="addr = '172.16.3.4:0'">端口 0</el-button>
<el-button size="small" @click="addr = '172.16.3.4:65535'">端口 65535</el-button>
</el-space>
<p style="margin: 0; font-size: 13px; color: var(--el-text-color-secondary)">
show-port 开启时 IP 完整而端口缺失即报错(输入超 65535 自动截断到 65535,0 不合法);失焦触发。
</p>
</el-space>
</template>
显示代码
受控回显
···:
外部赋值 '172.16.8.66:9200' 自动拆分到四段 + 端口;本地编辑的等值不回流。
外部异步赋值
'172.16.8.66:9200' 自动分发到四段 + 端口;本地等值编辑不回流。<script setup lang="ts">
/** 场景:受控回显——外部异步赋值 'ip:port' 自动分发(详情晚到场景) */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const addr = ref('')
const fillRemote = (): void => {
setTimeout(() => {
addr.value = '172.16.8.66:9200'
}, 300)
}
</script>
<template>
<el-space direction="vertical" size="large">
<BizIpInput v-model="addr" show-port style="--biz-ip-input-width: 300px" />
<el-button size="small" type="primary" @click="fillRemote">模拟接口回显(ES 节点)</el-button>
<p style="margin: 0; font-size: 13px; color: var(--el-text-color-secondary)">
外部赋值 <code>'172.16.8.66:9200'</code> 自动拆分到四段 + 端口;本地编辑的等值不回流。
</p>
</el-space>
</template>
显示代码
粘贴解析
···:
粘贴 ip:port 或纯 IP 均自动分发(端口聚焦待改);非地址文本不拦截正常粘贴。 当前值:(空)
粘贴
ip:port 整串(或纯 IP)自动分发,从工单 / 文档拷地址的常见动线。<script setup lang="ts">
/** 场景:粘贴解析——整段 'ip:port' 一键分发(从运维工单 / 文档拷贝地址的动线) */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizIpInput } from 'vue3-ep-biz-lib'
const addr = ref('')
const onPasteHint = (): void => {
ElMessage.info('复制下方任一地址后,在输入框内 Ctrl+V 粘贴')
}
const samples = ['192.168.0.1:443', '10.10.10.10:3306', '203.0.113.7:22']
</script>
<template>
<el-space direction="vertical" size="large">
<BizIpInput v-model="addr" show-port style="--biz-ip-input-width: 300px" />
<el-space wrap>
<el-button v-for="s in samples" :key="s" size="small" @click="onPasteHint">{{ s }}</el-button>
</el-space>
<p style="margin: 0; font-size: 13px; color: var(--el-text-color-secondary)">
粘贴 <code>ip:port</code> 或纯 IP 均自动分发(端口聚焦待改);非地址文本不拦截正常粘贴。
当前值:<code>{{ addr === '' ? '(空)' : addr }}</code>
</p>
</el-space>
</template>
显示代码
禁用只读
禁用
···:
禁用态五段(含端口)均不可编辑;常用于生产环境地址的只读回显。
生产地址只读回显:五段(含端口)一并禁用。
<script setup lang="ts">
/** 场景:禁用态——只读展示服务地址(详情页 / 权限收口) */
import { ref } from 'vue'
import { BizIpInput } from 'vue3-ep-biz-lib'
const addr = ref('47.98.193.21:443')
const disabled = ref(true)
</script>
<template>
<el-space direction="vertical" size="large">
<el-switch v-model="disabled" active-text="禁用" />
<BizIpInput v-model="addr" show-port :disabled="disabled" style="--biz-ip-input-width: 300px" />
<p style="margin: 0; font-size: 13px; color: var(--el-text-color-secondary)">
禁用态五段(含端口)均不可编辑;常用于生产环境地址的只读回显。
</p>
</el-space>
</template>
显示代码
服务地址表单集成
登记中间件节点
中间件节点登记:名称 / 类型 / 地址(ip:port)+ expose validate() 一起提交。
<script setup lang="ts">
/** 场景:服务地址表单集成——中间件节点登记(地址 + 端口 + 类型一起提交) */
import { reactive, ref } from 'vue'
import { ElMessage, type FormInstance } from 'element-plus'
import { BizIpInput } from 'vue3-ep-biz-lib'
const formRef = ref<FormInstance>()
const ipRef = ref()
const form = reactive({
name: 'redis-master',
kind: 'redis',
addr: '10.2.30.14:6379',
})
const onSubmit = (): void => {
const ipResult = ipRef.value?.validate()
if (form.name === '') {
ElMessage.warning('请输入节点名称')
return
}
if (ipResult === undefined || !ipResult.valid) {
ElMessage.warning(ipResult?.message ?? '地址不合法')
return
}
ElMessage.success(`节点已登记:${form.name} → ${form.addr}`)
}
</script>
<template>
<el-card shadow="never" style="width: 480px">
<template #header>登记中间件节点</template>
<el-form ref="formRef" :model="form" label-width="80px">
<el-form-item label="节点名称">
<el-input v-model="form.name" maxlength="32" />
</el-form-item>
<el-form-item label="节点类型">
<el-select v-model="form.kind" style="width: 140px">
<el-option value="redis" label="Redis" />
<el-option value="mysql" label="MySQL" />
<el-option value="es" label="Elasticsearch" />
</el-select>
</el-form-item>
<el-form-item label="服务地址">
<BizIpInput ref="ipRef" v-model="form.addr" show-port style="--biz-ip-input-width: 100%" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交登记</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| model-value / v-model | string | '' | IPv4 地址字符串(show-port 时为 'a.b.c.d:port') |
| placeholder | string | '0' | 每段占位 |
| disabled | boolean | false | 禁用 |
| show-error | boolean | true | 失焦校验失败展示原因 |
| show-port | boolean | false | 追加端口段(1-65535 校验),v-model 变为 'a.b.c.d:port' |
宽度经 css 变量
--biz-ip-input-width(默认 220px)调整;其余属性透传根节点。
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| update:model-value | (value: string) | 地址变化 |
| change | (value: string) | 同 update |
| blur | (valid: boolean) | 失焦校验结论 |
Slots
| 插槽名 | 说明 |
|---|---|
| — | 无插槽 |
Expose
| 属性/方法 | 说明 |
|---|---|
| validate | () => { valid, message } 编程式校验 |
| focus | () => void 聚焦第一段 |