input输入日期时间,自动格式化组件/工具

news2024/12/23 10:48:11

input输入日期时间,自动格式化组件/工具

组件/工具使用说明

  • 只能输入日期时间,不能选择
  • 日期时间格式 yyyy-MM-dd HH:mm:ss
  • 基于VUE框架
  • 输入效果见下图
    在这里插入图片描述

组件/工具解决的痛点

  • 组件库日期时间组件,选日期时间很花时间
    • 例如想快速得到 2021-12-14 20:10:22,需要先选日期,然后再选时间
  • 可以快速输入目标日期和时间,不用关注日期和时间分隔符 - : 空格

组件/工具需要实现的功能

  • 只允许输入数字
  • 限制输入日期范围
  • 按键删除时自动补入合法数字
  • 输入数字自动删除后一位数字
  • 输入和删除时光标位置移动
  • 检测复制粘贴到输入框的内容
  • 输入完成时,按回车键自动失焦
  • 处理输入的不符合规则的日期

功能代码实现

  • HTML
<input 
    v-model="inOutTime"
    @focus="onFocus"
    @blur="onBlur"
    @input="inputDateTime($event)"
    @keydown="onKeydown"
    ref="inputDate"
    class="inputDate"
    :class="[`xxxx-${size}`]" />
<style scoped>
.inputDate {
  width: 100%;
  height: 40px;
  line-height: 40px;
  padding-left: 10px;
  border: none;
  outline: none;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
}
.inputDate:focus {
  border-color: #409eff;
}
.xxxx-default {
  height: 40px;
  line-height: 40px;
}
.xxxx-medium {
  height: 36px;
  line-height: 36px;
}
.xxxx-small {
  height: 32px;
  line-height: 32px;
}
.xxxx-mini {
  height: 28px;
  line-height: 28px;
}
</style>
  • 实时获取输入框值和光标位置
    function inputDateTime(ev) {
      // 输入框光标起始位置
      let selectionStart = this.$refs.inputDate.selectionStart;
      let selectionEnd = this.$refs.inputDate.selectionEnd;
      // 输入框的value
      console.log(ev.target.value);
    }
  
  • 处理输入框的值和光标位置的功能函数
// 格式化日期对象
function dateToStr(datetime) {
  if (!datetime) {
    return '';
  }
  let year = datetime.getFullYear();
  let month = datetime.getMonth() + 1;
  let date = datetime.getDate();
  let hour = datetime.getHours();
  let minutes = datetime.getMinutes();
  let second = datetime.getSeconds();
  if (month < 10) {
    month = "0" + month;
  }
  if (date < 10) {
    date = "0" + date;
  }
  if (hour < 10) {
    hour = "0" + hour;
  }
  if (minutes < 10) {
    minutes = "0" + minutes;
  }
  if (second < 10) {
    second = "0" + second;
  }
  let time = year + "-" + month + "-" + date + " " + hour + ":" + minutes + ":" + second;
  return time;
}
// 定义分割符位置对象
const del = {
  4: '-',
  7: '-',
  10: ' ',
  13: ':',
  16: ':'
}
/**
 * @param {*} str 日期字符串 2021-02-23 22:00:00
 * @param {*} selectionStart 输入光标起始位置 从1开始
 */
export function formatStringDate(str, selectionStart) {
  // 粘贴时间校验
  if (!/^[0-9-:\s]{18,20}$/.test(str) || str.length < 18) {
    return {newDate: dateToStr(new Date()), startB: 19};
  }
  // 校验纯数字是否小于13位
  let numStr = str.replace(/-|:|s|\s/g, '');
  if (numStr.length < 13) {
    return {newDate: dateToStr(new Date()), startB: 19};
  }
  // 校验当前输入的是不是数字
  const num = /^[0-9]$/;
  // 字符查询从0开始
  let startB = selectionStart;
  selectionStart = selectionStart - 1;
  let arrDate = str.split('');
  // 按键删除
  if (arrDate.length < 19) {
    if (del[startB]) {
      // 删除的是分隔符
      arrDate.splice(startB, 0, del[startB])
    } else {
      // 如果删除的是数字,补位1
      // 第一位补2 第二位补0
      let obj = {
        0: '2',
        1: '0',
        5: '0'
      }
      arrDate.splice(startB, 0, obj[startB] || '1')
    }
    str = arrDate.join('');
  } else {
    // 按键输入
    // 拿到输入的字符
    const str2 = str.slice(selectionStart, selectionStart + 1);
    if (!num.test(str2)) {
      // 删除非法字符
      arrDate.splice(selectionStart, 1);
      return {newDate: arrDate.join(''), startB};
    }
    // 输入的是数字,删除当前位置下一位数字,遇到- : 空格,往后移动一位
    const str3 = str.slice(selectionStart + 1, selectionStart + 2);
    const reg1 = /^(-|:|s|\s)$/;
    if (reg1.test(str3)) {
      // 下一位非数字,往后移动一位进行删除
      arrDate.splice(selectionStart + 2, 1);
      // 光标往后移动一位
      startB++;
    }
    // 下一位是数字
    if (num.test(str3)) {
      arrDate.splice(selectionStart + 1, 1);
    }
  }
  // 去除分隔符('2022-02-23 20:20:20')及空格
  let str1 = arrDate.join('').replace(/-|:|s|\s/g, '');
  // 年月日校验 2000 ~ 2099
  const regDate = /^20([0-9][0-9])-(0[1-9]|1[0-2])-([0-2][0-9]|3[01])$/;
  const regTime = /^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/;
  // 年月日
  let ymd = '';
  if (str1.length >= 8) {
    ymd = (str1).match(/(\d{4})(\d{2})(\d{2})/).filter((item, index) => index > 0).join('-');
  }
  if (!regDate.test(ymd)) {
    // 删除非法字符,返回原值
    const reArr = str.split('');
    reArr.splice(selectionStart, 1);
    return {newDate: reArr.join(''), startB};
  }
  // 时分秒
  let hmsStr = (str1).slice(8), hms;
  if (hmsStr.length >= 6) {
    hms = hmsStr.match(/(\d{2})(\d{2})(\d{2})/).filter((item, index) => index > 0).join(':');
  }
  if (!regTime.test(hms)) {
    // 删除非法字符,返回原值
    const reArr = str.split('');
    reArr.splice(selectionStart, 1);
    return {newDate: reArr.join(''), startB};
  }
  return {newDate: `${ymd} ${hms}`, startB};
}
  • 日期时间合法校验
function strDateTime(str) {
  var reg = /^(\d{4})(-|\/)(\d{2})\2(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
  var r = str.match(reg);
  if (r == null) return false;
  var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]);
  return (d.getFullYear() === Number(r[1]) && (d.getMonth() + 1) === Number(r[3]) && d.getDate() === Number(r[4]) && d.getHours() === Number(r[5]) && d.getMinutes() === Number(r[6]) && d.getSeconds() === Number(r[7]));
}
  • 设置光标位置
// 两个参数必传
this.$refs.inputDate.setSelectionRange(selectionStart, selectionStart);
  • 完整代码
<template>
  <div>
    <input 
          v-model="inOutTime"
          @focus="onFocus"
          @blur="onBlur"
          @input="inputDateTime($event)"
          @keydown="onKeydown"
          ref="inputDate"
          class="inputDate"
          :class="[`xxxx-${size}`]" />
  </div>
</template>
<script>
import { formatStringDate } from "utils";
import { dateToStr } from "public";
export default {
  props: {
    initTime: {
      type: String,
      required: true,
      default: dateToStr(new Date())
    },
    size: {
      type: String,
      default: 'small'
    }
  },
  data() {
    return {
      inOutTime: this.initTime
    }
  },
  methods: {
    inputDateTime(ev) {
      let selectionStart = this.$refs.inputDate.selectionStart;
      const options = formatStringDate(ev.target.value, selectionStart);
      this.inOutTime = options.newDate;
      if (options.startB !== selectionStart) {
        selectionStart = options.startB;
      }
      this.$nextTick(() => {
        this.$refs.inputDate.setSelectionRange(selectionStart, selectionStart);
      })
    },
    onFocus() {
    },
    onBlur() {
      if (!this.strDateTime(this.inOutTime)) {
        this.inOutTime = dateToStr(new Date());
      }
    },
    onKeydown(e) {
      let keyCode = window.event ? e.keyCode : e.which;
      // 回车键->输入框失焦
      if (keyCode === 13) {
        this.$refs.inputDate.blur();
        if (!this.strDateTime(this.inOutTime)) {
          this.inOutTime = dateToStr(new Date());
        }
        this.$emit('getTime', this.inOutTime);
      }
    },
    strDateTime(str) {
			var reg = /^(\d{4})(-|\/)(\d{2})\2(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
      var r = str.match(reg);
			if (r == null) return false;
			var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]);
			return (d.getFullYear() === Number(r[1]) && (d.getMonth() + 1) === Number(r[3]) && d.getDate() === Number(r[4]) && d.getHours() === Number(r[5]) && d.getMinutes() === Number(r[6]) && d.getSeconds() === Number(r[7]));
		}
  }
}
</script>

补充说明

  • 若需要实时获取处理之后的日期时间,可以在组件上使用v-model,具体代码请参考vue文档
  • 组件基于VUE编写,核心方法formatStringDate不依赖框架,原生JS、react均可使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/757932.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OJ练习第137题——有序链表转换二叉搜索树

有序链表转换二叉搜索树 力扣链接&#xff1a;109. 有序链表转换二叉搜索树 题目描述 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为高度平衡的二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右…

[golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务

本次内容需要 gin框架基础知识, golang微服务基础知识才能更好理解 一.Captcha验证码功能引入 在前面,讲解了微服务的架构等,这里,来讲解前面商城项目的 Captcha验证码 微服务 ,captcha验证码功能在前台,后端 都要用到 ,可以把它 抽离出来 ,做成微服务功能 编辑 编辑 这个验证码…

MySQL 第七天作业 nosql作业

作业一&#xff1a;string list hash结构中&#xff0c;每个至少完成5个命令&#xff0c;包含插入 修改 删除 查询&#xff0c;list 和hash还需要增加遍历的操作命令 1、 string类型数据的命令操作&#xff1a; &#xff08;1&#xff09; 设置键值&#xff1a; set key1 re…

C++基础与深度解析01——函数基本组成+函数传参的三种方法

0.前期准备 请安装Visual Studio 并学习基本的新建项目、新建CPP文件以及运行代码。 1.从Hello World 开始 1.1代码内容 函数功能&#xff1a;打印“Hello World” #include<iostream> int main() { std::cout << "Hello World" << std::endl…

学习babylon.js --- [1] 初次体验和安装

babylon.js是微软推出的Web3D库&#xff0c;本文写作时版本是6.x&#xff0c;官方介绍如下&#xff0c; 看这意思是6.x系列的版本大大提高了性能&#xff0c;并提供了很多新特性。其Github地址是https://github.com/BabylonJS/Babylon.js 本篇文章讲述使用babylon.js的初次体…

申请阿里云服务器并搭建公网可支持数据上传的HTTP服务器

1. 前言 拥有一台自己的云服务器可以做很多事情。阿里云服务器毫无疑问是国内最好的。 阿里云服务器可以用于各种互联网应用的搭建和运行&#xff0c;提供稳定、高性能的服务。 阿里云服务器的用途&#xff0c;包括但不限于以下几个方面&#xff1a; 网站托管&#xff1a;可以将…

常用adb命令整理

一、adb介绍 adb&#xff1a;Android Debug Bridge&#xff0c;Android 调试桥的缩写&#xff0c;adb 是一个 C/S 架构的命令行工具&#xff0c; 主要由 3 部分组成&#xff1a; 运行在 PC 端的 Client : 可以通过它对 Android 应用进行安装、卸载及调试运行在 PC 端的 Serv…

Python实现校园网自动连接

用过校园网的小伙伴可能深有体会&#xff0c;在连接上校园网之后&#xff0c;需要再进行一个用户认证&#xff0c;才算真正的连接成功。这就会带来一些问题&#xff0c;比如若在长时间内没有网络请求&#xff0c;用户认证就会失效&#xff0c;它会自动断开校园网&#xff0c;这…

Android 系统开发工具

Android 系统开发工具 1、SSH 服务与 Tabby Terminal1.1 配置 Ubuntu ssh 服务 2、Samba 服务器搭建3、Idegen Android Studio 查看源码3.1 修改android.iml文件 (可选) 4、AIdegen Android Studio 查看源码4.1 准备工作4.2 Android Studio 配置4.2.1 添加源码中的 jdk 和 sd…

两数之和

给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出和为目标值 target 的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。…

arcgis实现影像监督分类

1、打开ArcMap,右击空白处打开影像分类工具栏&#xff0c;如下&#xff1a; 2、打开影像&#xff0c;如下&#xff1a; 打开的影像由于未经处理&#xff0c;颜色看起来很昏暗&#xff0c;这时候可以拉伸一下。具体操作&#xff0c;右击图层选择属性&#xff0c;如下&#xff1a…

python使用websockets进行数据传输

背景说明&#xff1a; 最近在研究一个智能监控系统&#xff0c;后台通过rtsp读取摄像头视频流&#xff0c;使用yolov算法进行目标检测&#xff0c;然后将检测的视频帧通过字符串的方式抛转到前台html页面显示&#xff0c;需要用到前后台数据交互技术&#xff0c;查询资料发现w…

ShareX设置快捷键、自定义保存路径、取消上传等设置

让ShareX变成顺手的形状 设置篇ShareX设置快捷键ShareX设置自定义保存路径ShareX取消自动上传和打开OCR 使用篇OCR 设置篇 ShareX设置快捷键 ShareX设置自定义保存路径 ShareX取消自动上传和打开OCR 为什么取消上传功能&#xff1a;因为不需要自动把本地截图自动上传到远程服务…

Vue3 使用存储库Pinia(getters)

一、store.js创建getters import { defineStore } from "pinia"; export const useStore defineStore(main, {state() { // state表示这个store里的状态&#xff0c;也就是存放数据的地方return {name: 张三,age:26 }},actions: { // 和vue中的methods一样updateA…

前端必会的三种DIV+CSS布局

要开发网页&#xff0c;必须要搞懂这三种divcss布局技术&#xff01;&#xff08;1&#xff09;左右两列布局&#xff1b;&#xff08;2&#xff09;1行3列&#xff1b;&#xff08;3&#xff09;1行多列或多行多列布局&#xff1b;只要你掌握了这三种布局方式&#xff0c;那搭…

2核4G服务器腾讯云或阿里云能安装几个网站?性能如何?

2核4G服务器能安装多少个网站&#xff1f;2核4g配置能承载多少个网站&#xff1f;一台2核4G服务器可以安装多少个网站&#xff1f;阿腾云2核4G5M带宽服务器目前安装了14个网站&#xff0c;从技术角度是没有限制的&#xff0c;只要云服务器性能够用&#xff0c;想安装几个网站就…

java之maven专题

1、idea配置maven https://blog.csdn.net/hanmingjun/article/details/129977880 2、阿里云补充缺少的jar包 到官方下载好jar包到这里上传 maven中配置跳过单元测试 https://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-tests.html

记录--再也不用手动改package.json的版本号

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 本文的起因是有在代码仓库发包后&#xff0c;同事问我“为什么package.json 里的版本还是原来的&#xff0c;有没有更新&#xff1f;”&#xff0c;这个时候我意识到&#xff0c;我们完全没有必要在每…

lwip-2.1.3自带的httpd网页服务器使用教程(二)使用SSI动态生成网页部分内容

上一篇&#xff1a;lwip-2.1.3自带的httpd网页服务器使用教程&#xff08;一&#xff09;从SD卡读取网页文件并显示 通过全局数组定义TAG标签列表 &#xff08;本节例程名称&#xff1a;ssi_test&#xff09; 电脑上用的Web服务器采用ASP、PHP或JSP动态网页技术后&#xff0c…

Verdi之状态机状态查询nState

目录 5. nState 5.1如何打开状态机视图 5.2 如何在状态机视图中添加状态转移条件 5.3 如何查看状态机个状态对应的相关代码 5.4 查看具体的状态机状态转移时间点 5.5 查找自定义状态 5.6 查找某个状态执行的次数 5. nState 5.1如何打开状态机视图 1. 将设计文件导入Ver…