- 子组件vue
<template> <!-- 长度为200px的IP输入框组件 --> <div class="ipBox"> <template v-for="(item, idx) in ipList"> <input :key="idx" :value="ipList[idx]" :ref="'ip' + idx" :disabled="disabled" v-number="{min: idx == 0 ? 1 : 0, max: 255}" :class="'el-input__inner ' + disabledClass" maxlength='3' placeholder="0" @change="handleChange(idx)" @paste="handlePaste(idx, $event)" @keyup="handleKeyup(idx, $event)" /> <span :key="idx + 'span'" v-if="idx < 3" class="dot">.</span> </template> <el-button type="text" icon="el-icon-close" :disabled="isEmpty || disabled" @click="handleClear"/> </div> </template> <script> import { validIP } from "@/utils/validate" export default { name: "IpInput", props: ['value','disabled'], computed: { ipList() { if(this.value == undefined || this.value == null || this.value == '') { return ["","","",""] } return this.value.split(".") }, isEmpty() { return this.ipList.every(val => val == null || val == '') }, disabledClass() { return this.disabled ? "is-disabled" : "" } }, methods: { //清除ip handleClear () { //重置ip输入框 this.changeAndEmit("") }, getDom(idx) { return this.$refs['ip'+idx][0] }, handleChange(idx) { const newValue = this.getDom(idx).value // 修改数组中指定索引的数据 this.ipList.splice(idx, 1, newValue) this.emitInput() }, handlePaste(idx, event) {// 粘贴 const e = event || window.event let pasteText = e.clipboardData.getData('Text') if (pasteText != null && pasteText != "" && validIP(pasteText)) { this.changeAndEmit(pasteText) } }, handleKeyup(idx, event) { if (idx < 3) { const val = this.$refs['ip'+idx][0].value if (val != null && val.length == 3) { const nextDom = this.getDom(idx + 1) this.$nextTick(() => { nextDom.focus(); }); } } }, changeAndEmit(val) { if (val == null || val == "") { for (let idx=0;idx<4;idx++) { this.ipList.splice(idx, 1, "") } this.$emit('input', "") } else { const arr = val.split(".") for (let idx=0;idx<4;idx++) { this.ipList.splice(idx, 1, arr[idx]) } this.emitInput() } }, emitInput() {// 回写父组件 // 数组所有数值非空 if (this.ipList.every(val => val != null && val !== '')) { this.$emit('input', this.ipList.join(".")) } } } } </script> <style scoped lang='less'> .dot { width: 5px; font-weight: bolder; font-size: 18px; } .ipBox{ width: 200px; border: 1px solid #ccc; border-radius: 5px; } ::v-deep .el-input__inner {// 样式强制覆盖 width: 40px; font-size: 14px; border: 0; text-align: center; padding: 0 8px; } .is-disabled {// 输入框禁用的样式 background-color: #F5F7FA; color: #C0C4CC; cursor: not-allowed; } </style>
-
IP校验src/utils/validate.js
/** * 校验IP * @param {string} ip * @returns {Boolean} */ export function validIP(ip) { const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ return reg.test(ip) }
-
自定义指令number
/* // 限制输入纯数字 <el-input v-model="form.groupInterval" v-number={min:30,max:300} maxlength="3" placeholder="范围:30~300"> <template slot="append">秒</template> </el-input> */ export default { bind(el, binding, vnode) { // 最大值,最小值,小数位 const { max = 999999999, min = 1 } = binding.value || {} const el0 = el.getElementsByTagName('input')[0] el0.addEventListener('blur', function() { let v = el0.value v = v.replace(/\D/g, '').replace(/^0{1,}/g, ''); // 纯数字 if (v.length > 0) { if (v < min) { v = min } else if (v > max) { v = max } } else { v = min } el0.value = v const number = parseInt(v) vnode.data.model.callback(number) }) } }
const install = function(Vue) { Vue.directive('number', number) } Vue.use(install)
-
父组件调用
<template> <div class="app-container"> <ip-input v-model="ip" :disabled="disabled"/> </div> </template> <script> import IpInput from "./IpInput"; export default { name:"我是父组件", @components: {IpInput}, data() { return { ip:"", disabled: false, } } } </script>
-
界面预览