当前位置: 首页 > news >正文

Vue3 + TypeScript + el-input 处理年份输入(最多只能输入四位数字,不能输入其他符号)

代码:

// 处理年份输入,最多只能输入四位数字,不能输入其他符号 const handleYearInput = (value: string) => { // 过滤掉所有非数字字符,只保留数字 const numbersOnly = value.replace(/[^\d]/g, ""); // 限制4位 const limitedValue = numbersOnly.slice(0, 4); // 转换为数字,空字符串设为0 localCapitalInfo.capitalYear = limitedValue === "" ? 0 : parseInt(limitedValue, 10); }; <el-input v-model="localCapitalInfo.capitalYear" clearable @input="handleYearInput" />

效果:


Vue3年份输入控制最佳实践

vue3中, // 处理年份输入,最多只能输入四位数字,不能输入其他符号 const handleYearInput = (value: string) => { // 过滤掉所有非数字字符,只保留数字 const numbersOnly = value.replace(/[^\d]/g, ""); // 限制4位 const limitedValue = numbersOnly.slice(0, 4); // 转换为数字,空字符串设为0 localCapitalInfo.capitalYear = limitedValue === "" ? 0 : parseInt(limitedValue, 10); }; ...... <el-row :gutter="10"> <el-col :span="12"> <el-form-item label="资金序号" label-position="right" prop="capitalNo"> <el-input v-model="localCapitalInfo.capitalNo" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="资金年份" label-position="right" prop="capitalYear"> <el-input v-model="localCapitalInfo.capitalYear" clearable @input="handleYearInput" /> </el-form-item> </el-col> </el-row> ...... <el-row :gutter="10"> <el-col :span="24"> <el-form-item label="资金年份" label-position="right"> <el-input v-model="capitalInfoStore.queryDTO.capitalYear" clearable /> </el-form-item> </el-col> </el-row> 如何更好地实现这两处资金年份的输入控制

在 Vue3 中,可以通过以下几种方式更好地实现年份输入控制:

方案一:使用计算属性 + 自定义指令(推荐)

1. 创建自定义指令

typescript

// directives/inputDirectives.ts import { Directive } from 'vue' // 只能输入数字的自定义指令 export const numberDirective: Directive = { mounted(el) { el.addEventListener('input', (e: Event) => { const input = e.target as HTMLInputElement input.value = input.value.replace(/[^\d]/g, '') }) } } // 限制最大长度的自定义指令 export const maxLengthDirective: Directive = { mounted(el, binding) { const maxLength = binding.value || 4 el.addEventListener('input', (e: Event) => { const input = e.target as HTMLInputElement if (input.value.length > maxLength) { input.value = input.value.slice(0, maxLength) } }) } }

2. 在组件中使用

vue

<template> <el-row :gutter="10"> <el-col :span="12"> <el-form-item label="资金年份" label-position="right" prop="capitalYear"> <el-input v-model.number="localCapitalInfo.capitalYear" :maxlength="4" clearable v-number v-max-length="4" @blur="validateYear" /> </el-form-item> </el-col> </el-row> </template> <script setup lang="ts"> import { ref, computed } from 'vue' import { numberDirective, maxLengthDirective } from '@/directives/inputDirectives' const vNumber = numberDirective const vMaxLength = maxLengthDirective // 使用计算属性处理年份 const localCapitalInfo = ref({ capitalYear: 0 }) // 年份计算属性 const yearValue = computed({ get() { return localCapitalInfo.value.capitalYear || '' }, set(value) { if (value === '') { localCapitalInfo.value.capitalYear = 0 } else { const num = parseInt(value, 10) if (!isNaN(num) && num >= 0) { localCapitalInfo.value.capitalYear = Math.min(num, 9999) } } } }) // 验证年份 const validateYear = () => { const year = localCapitalInfo.value.capitalYear if (year < 1900 || year > 2100) { // 可以添加错误提示 console.warn('请输入有效的年份(1900-2100)') } } </script>

方案二:创建可复用的 Composable

1. 创建 useYearInput Composable

typescript

// composables/useYearInput.ts import { ref, computed, watch } from 'vue' export function useYearInput(initialValue = 0, options = { min: 1900, max: 2100, maxLength: 4 }) { const rawValue = ref<string>(initialValue?.toString() || '') const error = ref<string>('') // 处理输入 const handleInput = (value: string) => { // 只保留数字 const numbersOnly = value.replace(/[^\d]/g, '') // 限制长度 rawValue.value = numbersOnly.slice(0, options.maxLength) // 验证 validate() } // 验证年份 const validate = () => { if (rawValue.value === '') { error.value = '' return true } const yearNum = parseInt(rawValue.value, 10) if (isNaN(yearNum)) { error.value = '请输入有效的年份' return false } if (yearNum < options.min || yearNum > options.max) { error.value = `年份范围:${options.min}-${options.max}` return false } error.value = '' return true } // 获取数字值 const yearNumber = computed(() => { if (rawValue.value === '') return 0 const num = parseInt(rawValue.value, 10) return isNaN(num) ? 0 : num }) // 获取显示值 const displayValue = computed({ get: () => rawValue.value, set: (value: string) => handleInput(value) }) return { rawValue, displayValue, yearNumber, error, handleInput, validate } }

2. 在组件中使用

vue

<template> <el-row :gutter="10"> <el-col :span="12"> <el-form-item label="资金年份" label-position="right" prop="capitalYear" :error="yearInput.error" > <el-input v-model="yearInput.displayValue" :maxlength="4" clearable placeholder="请输入年份" @blur="yearInput.validate" /> </el-form-item> </el-col> </el-row> </template> <script setup lang="ts"> import { useYearInput } from '@/composables/useYearInput' import { watch } from 'vue' const yearInput = useYearInput(2023, { min: 1900, max: 2100, maxLength: 4 }) // 如果需要,可以监听数值变化 watch(() => yearInput.yearNumber, (newVal) => { // 更新到 store 或父组件 }) </script>

方案三:创建 YearInput 组件(最推荐)

1. 创建 YearInput 组件

vue

<!-- components/YearInput.vue --> <template> <el-input :model-value="displayValue" :maxlength="4" :placeholder="placeholder" :clearable="clearable" :disabled="disabled" :error="!!errorMessage" @input="handleInput" @blur="handleBlur" > <template #append v-if="showSuffix">年</template> </el-input> <div v-if="errorMessage" class="error-message"> {{ errorMessage }} </div> </template> <script setup lang="ts"> import { ref, computed, watch } from 'vue' interface Props { modelValue?: number | string placeholder?: string clearable?: boolean disabled?: boolean showSuffix?: boolean minYear?: number maxYear?: number required?: boolean } const props = withDefaults(defineProps<Props>(), { modelValue: 0, placeholder: '请输入年份', clearable: true, disabled: false, showSuffix: true, minYear: 1900, maxYear: 2100, required: false }) const emit = defineEmits<{ 'update:modelValue': [value: number] 'change': [value: number] 'validate': [isValid: boolean] }>() const rawValue = ref<string>('') const errorMessage = ref<string>('') // 初始化 watch(() => props.modelValue, (value) => { if (value || value === 0) { rawValue.value = value.toString() } }, { immediate: true }) // 显示值 const displayValue = computed(() => rawValue.value) // 处理输入 const handleInput = (value: string) => { // 只保留数字 const numbersOnly = value.replace(/[^\d]/g, '') // 限制长度 rawValue.value = numbersOnly.slice(0, 4) // 实时更新 updateValue() } // 更新值 const updateValue = () => { if (rawValue.value === '') { emit('update:modelValue', 0) emit('change', 0) return } const yearNum = parseInt(rawValue.value, 10) if (!isNaN(yearNum)) { const finalValue = Math.min(Math.max(yearNum, 0), 9999) emit('update:modelValue', finalValue) emit('change', finalValue) } } // 验证 const handleBlur = () => { validate() } const validate = (): boolean => { errorMessage.value = '' if (props.required && !rawValue.value) { errorMessage.value = '年份不能为空' emit('validate', false) return false } if (!rawValue.value) { emit('validate', true) return true } const yearNum = parseInt(rawValue.value, 10) if (isNaN(yearNum)) { errorMessage.value = '请输入有效的年份' emit('validate', false) return false } if (yearNum < props.minYear || yearNum > props.maxYear) { errorMessage.value = `年份范围:${props.minYear}-${props.maxYear}` emit('validate', false) return false } emit('validate', true) return true } // 暴露方法 defineExpose({ validate, clear: () => { rawValue.value = '' updateValue() } }) </script> <style scoped> .error-message { color: #f56c6c; font-size: 12px; margin-top: 4px; } </style>

2. 在父组件中使用

vue

<template> <el-row :gutter="10"> <el-col :span="12"> <el-form-item label="资金年份" label-position="right" prop="capitalYear"> <YearInput v-model="localCapitalInfo.capitalYear" :min-year="2000" :max-year="2100" required /> </el-form-item> </el-col> </el-row> <el-row :gutter="10"> <el-col :span="24"> <el-form-item label="资金年份" label-position="right"> <YearInput v-model="capitalInfoStore.queryDTO.capitalYear" :clearable="true" /> </el-form-item> </el-col> </el-row> </template> <script setup lang="ts"> import YearInput from '@/components/YearInput.vue' import { ref } from 'vue' const localCapitalInfo = ref({ capitalYear: 2023 }) // 使用 store import { useCapitalInfoStore } from '@/stores/capitalInfo' const capitalInfoStore = useCapitalInfoStore() </script>

方案四:使用第三方库(如 v-mask)

bash

npm install vue-the-mask

vue

<template> <el-input v-model="yearValue" v-mask="'####'" placeholder="YYYY" clearable /> </template> <script setup lang="ts"> import { ref, watch } from 'vue' import { VueMaskDirective } from 'vue-the-mask' const vMask = VueMaskDirective const yearValue = ref('') </script>

总结建议

  1. 推荐方案三:创建YearInput组件,封装性好,可复用性强

  2. 次推荐方案二:使用 Composable,逻辑复用方便

  3. 简单场景:可以使用计算属性 + 自定义指令

  4. 优势

    • 统一处理逻辑,避免重复代码

    • 支持验证和错误提示

    • 易于维护和扩展

    • 类型安全(TypeScript)

根据项目复杂度和复用需求选择合适的方案,组件化方式更适合长期维护的项目。

http://www.jsqmd.com/news/333599/

相关文章:

  • MWGA让千亿行代码在Web端“复活”!
  • 2026年12mm按钮服务商厂家推荐,北京天波泰技术与服务双优 - 工业推荐榜
  • uniapp vue3 小程序 实现样式穿透
  • 河北炬恩丝网制品有限公司:口碑好的地铁盾构走道板、隧道走道板、地铁走道板厂家推荐,盾构走道板全系供应 - 品牌推荐官
  • oracle javascripts 学习
  • 2026洁净地漏生产厂家推荐:技术与品质双优的行业选择 - 品牌排行榜
  • 探讨盈尚环境工程有限公司服务商技术实力是否精湛,如何选择合适的 - 工业品牌热点
  • 实测YOLO-Master v2:MoE架构加持,检测+分割+计数联合推理延迟仅增7%(智慧零售实操全解析)
  • 小米电视 如何去掉开机老是打广告?
  • 汽车模具五轴加工中心企业口碑排行:聚焦AMU260,纳米涂层涂覆机/在线式真空等离子清洗机AMU260五轴加工中心公司 - 品牌推荐师
  • 当“意义”成为稀缺货币:为何顶尖决策者正从《意义对谈》寻找新的价值锚点
  • <span class=“js_title_inner“>别盯着参数看啦!2026年,AI 圈的“狂热”正转向“务实”</span>
  • Fastboot必须要用USB2.0的数据线!
  • 2026国内最新板材生产厂家top10推荐!优质环保/全屋定制/柜体/家装板材企业权威榜单发布,质优合规助力高品质家居 - 品牌推荐2026
  • YOLO26 核心改进解析:无NMS+移除DFL,边缘端推理速度飙升43%
  • 2026年万能材料拉力机厂家权威推荐:单柱/电子/万能/拉力试验机及检测仪源头厂家精选 - 品牌推荐官
  • 2026不锈钢洁净排水系统:技术标准与工程应用实践 - 品牌排行榜
  • 实测对比YOLO26 vs YOLOv13:三大硬件平台SOTA选型指南(速度/精度/部署成本全解析)
  • 高安市英语雅思培训机构推荐,2026权威测评出国雅思辅导机构口碑榜单 - 老周说教育
  • 2026年称重传感器十大品牌权威推荐与对比分析 - 品牌推荐大师1
  • 2026四川活动板房厂家权威榜单 适配多场景与各类需求 全景解析适配方案 - 深度智识库
  • 测试平台之reports应用的前世今生,以及django_filters的不同类型的字段如何使用,达到前端过滤的效果
  • 国产数控车床哪家强?高刚性、高效率、高光洁度:深度解析台茂精机的核心技术优势 - 品牌推荐大师1
  • 高安市英语雅思培训机构推荐:2026权威测评出国雅思辅导机构口碑榜单 - 老周说教育
  • Midscene.js
  • 2026年四川活动板房厂家哪家靠谱?聚焦品质与实用的靠谱之选 - 深度智识库
  • 激光切管机厂家常见问题解答(2026最新专家版) - 速递信息
  • 2026年山东地区靠谱的轻钢龙骨防火板吊顶源头工厂排名,哪家口碑好? - 工业品网
  • 30 天推歌挑战
  • Ubuntu安装TexLive