bm-bmt/components/DecimalInput/DecimalInput.vue

98 lines
3.1 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<input ref="InputRef" class="DecimalInput UI-FLEX-1 UI-P-L24 UI-FS28" type="text" inputmode="decimal"
:value="InnerValue" :placeholder="placeholder" :placeholder-style="placeholderStyle"
@input="HandleInput" />
</template>
<script>
import { limitDecimal } from '@/utils/index.js'
export default {
name: 'DecimalInput',
props: {
value: { type: [String, Number], default: '' },
digit: { type: Number, default: 2 },
allowNegative: { type: Boolean, default: false },
max: { type: [String, Number], default: null },
placeholder: { type: String, default: '' },
placeholderStyle: { type: String, default: '' }
},
data() {
return {
// 组件内部输入值
InnerValue: String(this.value === null || this.value === undefined ? '' : this.value)
}
},
watch: {
value(Val) {
const Str = String(Val === null || Val === undefined ? '' : Val)
if (Str !== this.InnerValue) {
this.InnerValue = Str
}
}
},
methods: {
/** 获取 uni-app input 组件内部的原生 input 节点 */
GetNativeInput(Target) {
if (Target && Target.tagName === 'INPUT') return Target
const ShadowInput = Target && Target.shadowRoot && typeof Target.shadowRoot.querySelector === 'function'
? Target.shadowRoot.querySelector('input')
: null
if (ShadowInput) return ShadowInput
const ChildInput = Target && typeof Target.querySelector === 'function'
? Target.querySelector('input')
: null
if (ChildInput) return ChildInput
const RootEl = this.$refs.InputRef && this.$refs.InputRef.$el
const RootInput = RootEl && typeof RootEl.querySelector === 'function'
? RootEl.querySelector('input')
: null
if (RootInput) return RootInput
// H5 兜底:正在输入时焦点元素就是原生 input
const ActiveInput = typeof document !== 'undefined' ? document.activeElement : null
if (ActiveInput && ActiveInput.tagName === 'INPUT') return ActiveInput
return null
},
/** 输入时实时限制小数位数与最大值 */
HandleInput(e) {
const NativeInput = this.GetNativeInput(e && e.target)
const DetailValue = e && e.detail ? e.detail.value : undefined
let Value = String(
DetailValue !== undefined && DetailValue !== null
? DetailValue
: (NativeInput ? NativeInput.value : '')
)
// 限制小数位数、过滤非法字符
Value = limitDecimal(Value, this.digit, this.allowNegative)
// 超过最大值时取最大值
const Max = Number(this.max)
if (Value !== '' && this.max !== null && !isNaN(Number(Value)) && !isNaN(Max) && Number(Value) > Max) {
Value = String(Max)
}
this.InnerValue = Value
this.$emit('input', Value)
// uni-app H5 中 input 被编译为 uni-input 组件,其内部 valueSync 仍是
// 未过滤的原始值Vue 重新渲染时会把原生 input 的值打回去。
// 因此等本轮 patch 结束后nextTick再强制纠正原生 input 的显示值。
this.$nextTick(() => {
const Target = this.GetNativeInput(e && e.target)
if (Target && Target.value !== Value) {
Target.value = Value
}
})
}
}
}
</script>
<style lang="scss" scoped>
.DecimalInput {
height: 100%;
}
</style>