效果
使用
注意:使用element el-form el-form-item 包裹组件后,会自动添加范围校验规则。另由于我不需要其他功能,所以没有处理input的各种事件。
<el-form ref="volatilityFormRef" :disabled="!volatility.checked" label-width="7rem" :model="volatility.data" :rules="volatility.rules" size="medium">
<el-form-item label="波动范围" prop="range">
<input-number-range v-model="volatility.data.range" :disabled="!volatility.checked" unit="%"></input-number-range>
</el-form-item>
</el-form>
组件代码
<template>
<el-row v-auto-range-validate class="input-number-range" :class="{ 'is-disabled': disabled }" justify="space-between" type="flex">
<el-input v-model.trim="value[0]" v-q-number :disabled="disabled" placeholder="最小值" :size="size" type="text">
<template v-if="unit" v-slot:append>
<span>{{ unit }}</span>
</template>
</el-input>
<span :class="{ 'is-disabled': disabled }">{{ precision }}</span>
<el-input v-model.trim="value[1]" v-q-number :disabled="disabled" placeholder="最大值" :size="size" type="text">
<template v-if="unit" v-slot:append>
<span>{{ unit }}</span>
</template>
</el-input>
</el-row>
</template>
<script>
export default {
name: "InputNumberRange",
directives: {
"auto-range-validate": {
inserted(el, binding, vnode) {
const _this = vnode.context
let formItem = _this
while (formItem && formItem.$options.name !== "ElFormItem") {
formItem = formItem.$parent
if (!formItem) break
}
if (!formItem) return
const prop = formItem.prop
const form = formItem.$parent
if (!prop || !form) return
let rules = form.rules
if (!rules) form.rules = rules = { [prop]: [] }
if (!rules[prop]) rules[prop] = []
if (!Array.isArray(rules[prop])) rules[prop] = [rules[prop]]
rules[prop].push({
validator: (rule, value, callback) => {
const msg = _this.validate()
callback(msg ? new Error(msg) : "")
},
trigger: "blur",
})
},
},
},
model: {
prop: "value",
event: "onChange",
},
emits: ["onChange"],
props: {
value: {
type: [Array],
default: () => [null, null],
},
disabled: {
type: Boolean,
default: false,
},
size: {
type: String,
default: "medium",
validator: (val) => ["mini", "small", "medium"].includes(val),
},
separator: {
type: String,
default: "至",
},
unit: {
type: String,
default: "",
},
precision: {
type: Number,
default: null,
},
},
data() {
return {}
},
watch: {
value: {
handler(val) {
this.$nextTick(() => {
if (!Array.isArray(val) || val.length !== 2) {
// 第一次 修正value值
this.$emit("onChange", [null, null])
}
})
},
immediate: true,
},
},
methods: {
validate() {
const min = this.value[0]
const max = this.value[1]
if (!min && !max) return ""
if (!min) return "请输入最小值"
if (!max) return "请输入最大值"
if (parseFloat(min) > parseFloat(max)) return "最小值不能大于最大值"
if (this.precision !== 0 && !this.precision) return
this.$emit("onChange", [parseFloat(min).toFixed(this.precision), parseFloat(max).toFixed(this.precision)])
},
},
}
</script>
<style lang="stylus" scoped>
.input-number-range
background-color #fff
border 1px solid #dcdfe6
border-radius 4px
.is-disabled
background-color #eef0f6
border-color #e4e7ed
color #c0c4cc
cursor not-allowed
/deep/.el-input-group__append
background-color inherit
color inherit
// 取消element原有的input框样式
/deep/.el-input
.el-input__inner
border 0
margin 0
padding 0 15px
background-color transparent
text-align center
/deep/.el-input-group__append
background-color #fff
border unset
</style>
另一个自定义指令
// 输入框有理数 注意自行注册
export const QNumber = {
inserted: function (el) {
const inputEl = el.querySelector("input")
if (inputEl) {
inputEl.addEventListener("input", function () {
const reg = /^-?(0|[1-9]\d*)(.\d*)?$/
let value = inputEl.value
value = value.replace(/[^\d.-]/g, "")
if (!reg.test(value) && value !== "") {
inputEl.value = ""
} else {
inputEl.value = value
}
})
}
},
}