<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>
