input number类型去掉箭头且不能输入e和标点符号

本文介绍如何在使用InputNumber组件时去掉增减箭头,并阻止用户输入非数字字符如'e'和标点符号。通过监听键盘事件并过滤非数字输入,确保输入的有效性和准确性。
<template> <div :class="['talk-item', isLeft? 'left' : 'right']" :key="data.timestamp" v-if="isTemp == 1? true : text" > <!-- 遍历布局节点 --> <template v-for="it in layout[isLeft? 'left' : 'right']"> <!-- 头像部分 --> <div v-if="it === LayoutNode.AVATAR" :key="`${data.startFrame}-${it}`" class="talk-avatar" > <el-avatar class="avatar" size="large" :style="{ 'background-image': backgroundImg }" > <!-- avatar 用于展示头像 --> </el-avatar> </div> <!-- 文本段落部分 --> <div v-if="it === LayoutNode.PARAGRAPH" :key="`${data.startFrame}-${it}`" class="highlighted" :class="{ 'talk-paragraph': true, 'highlight': highlight, 'blink': isBlink }" > <!-- 时间其他操作按钮 --> <div class="time"> <!-- 左侧时间显示 --> <span v-if="isLeft" style="font-size: 12px;"> {{ timestamp | formatDate('hh:mm:ss') }} </span> <!-- 复制按钮 --> <i v-if="canCopy && data.text.length > 1" class="el-icon-s-claim" @click="setAnswer" ></i> <!--编辑按钮--> <el-tooltip v-if="canEdit" effect="dark" content="编辑" placement="top-start" class="item" > <i class="el-icon-edit" @click="changeEditStatus" v-if="(data.text.length > 0 && status == RealTimeStatus.History) || (data.text.length > 0 && status == RealTimeStatus.RealTime)" ></i> </el-tooltip> <!-- 右侧时间显示 --> <span v-if="!isLeft" style="font-size: 11px;"> {{ timestamp | formatDate('hh:mm:ss') }} </span> </div> <!-- 文本内容容器 --> <div :class="['text-container']" ref="textContainer" @dblclick="fetchTalkItem"> <!-- 统一前置 --> <i class="isIcon iconfont icon-yinbo"></i> <!-- 编辑模式下的文本框 --> <el-input v-if="isEdit" :class="['text-box',{highlighted: isPlaying }]" type="textarea" style="font-size: 16px;" :rows="3" v-model="data.text" @input="handleInput" ></el-input> <!-- 非编辑模式下的文本显示 --> <div v-else v-html="`${text}  `" :class="['text-box']" style="font-size: 16px;"></div> <!-- 段落进度条 --> <div class="progress-highlight" :style="{ width: progressWidth }"></div> </div> <!-- 命中标签 --> <div class="isHit" v-if="matchedHitRuleNames.length > 0"> <i style="color:#007bff;" class="el-icon-circle-check"></i> <span v-for="(name, index) in matchedHitRuleNames" :key="index">  {{ name }} </span> </div> </div> </template> </div> </template> <script lang="ts"> import { Message, MessageBox } from "element-ui"; import { Component, Prop, Vue, Watch } from "nuxt-property-decorator"; import { Keyword, TalkItem, TalkState } from "../../../types"; import * as dayjs from "dayjs"; import '../../../assets/iconFont/iconfont.css' // import img_police from "~/assets/img/anonymity-police.jpg" // 设置谈话人 被谈话人的位置 import img_police from "../../../assets/img/anonymity-telephonist.jpg"; import img_usr from "../../../assets/img/anonymity-square.png"; import { State } from "vuex-class"; const enum LayoutNode { AVATAR, PARAGRAPH, } /** * ZKer 设置谈话人是否在左边 */ const IsLeft = true; @Component({ name: "talkItem", components: {}, filters: { formatDate(value) { return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss"); }, }, }) export default class extends Vue { @Prop({ type: Object, required: true, default: {} }) data!: TalkItem; @Prop({ type: Boolean, required: true }) highlight: boolean; @Prop({ type: Boolean, required: true }) isPolice: boolean; @Prop({ type: Boolean, required: true }) canCopy: boolean; @Prop({ required: true }) canEdit; // 判断编辑是否可修改(历史谈话可/实时谈话) @Prop({ type: [], required: true }) RealTimeStatus; // 历史 实时谈话状态 @Prop({ required: true }) status; @Prop() busGroups!: any; isEdit: boolean = false; isLeft: boolean = false; isBlink: boolean = false; isTemp: any = null; // 判断用户删除(监听input输入事件时 证明在删除 否则反之) timestamp: string | number = " "; text: string = " "; backgroundImg: string = `url(${this.isPolice? img_police : img_usr}`; LayoutNode: any = LayoutNode; layout: any = { // 统计左(对话数据)右() left: [LayoutNode.AVATAR, LayoutNode.PARAGRAPH], right: [LayoutNode.PARAGRAPH, LayoutNode.AVATAR], }; @State talk!: TalkState; matchedHitRuleNames: string[] = []; // -=-= @Prop({ type: Boolean, default: false }) isPlaying!: boolean; progressWidth: string = '0%'; duration: number = null; // 播放完一段 animationFrameId: number | null = null; @Watch('isPlaying') onIsPlayingChange(isPlaying: boolean) { if (isPlaying) { this.startProgressAnimation(); } else { this.stopProgressAnimation(); } } startProgressAnimation() { const startTime = performance.now(); const animate = (now: number) => { const elapsed = now - startTime; const progress = Math.min(elapsed / this.duration, 1); this.progressWidth = `${progress * 100}%`; if (progress < 1) { this.animationFrameId = requestAnimationFrame(animate); } }; this.animationFrameId = requestAnimationFrame(animate); } stopProgressAnimation() { if (this.animationFrameId !== null) { cancelAnimationFrame(this.animationFrameId); this.animationFrameId = null; } this.progressWidth = '0%'; } beforeDestroy() { this.stopProgressAnimation(); } // -=-= @Watch("data", { deep: true, immediate: true }) onDataChange(newData: TalkItem) { // if (!newData.policy) { // this.console.debug(newData,newData.last, newData.text, JSON.stringify(newData.keywords), newData.startFrame) // } this.text = newData.text; this.setKeyword(true); } @Watch("canEdit") onCanEditChange(newValue: boolean) { if (newValue) { this.$store.dispatch("talk/FetchKeywords"); } } // handleClick(){//单击文本字段 // if (this.status == this.RealTimeStatus.History) { // this.$emit('jump', this.data) // console.log('this.newData',this.data); // // } // console.log(121212); // // } created() { // 对讲内容 // console.log(this.data, "opop"); // 命中次数 // console.log(this.busGroups.hitRules, "1212121"); } /** * 统一中英文标点符号为英文格式 */ normalizePunctuation(text: string): string { const punctuationMap: { [key: string]: string } = { ',': ',', '。': '.', '?': '?', '!': '!', ';': ';', ':': ':', '“': '"', '”': '"', '‘': "'", '’': "'", '(': '(', ')': ')', '【': '[', '】': ']', '《': '<', '》': '>', '、': '\\', '——': '-', '&hellip;': '...', '—': '-', '·': '.' }; return text.replace(/[^\u0000-\u00ff]/g, ch => punctuationMap[ch] || ch); } scrollToParagraph() {//添加 scrollToParagraph 方法,用于滚动到指定段落 const element = this.$el; element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } mounted() { this.text = this.data.text; this.isLeft = Boolean(Number(this.isPolice) ^ Number(IsLeft)); this.timestamp = this.data.timestamp; this.setKeyword(); if (this.data.startFrame && this.data.endFrame) { this.duration = this.data.endFrame - this.data.startFrame; // 动态计算段落的时间长度 } // **新增延迟逻辑:通过 $watch 监听 busGroups 变化** this.$watch('busGroups', (newGroups) => { if (newGroups && newGroups.hitRules) { this.matchHitRules(newGroups.hitRules); // 自定义标签匹配方法 } }, { deep: true, immediate: true }); } // 新增标签匹配方法 matchHitRules(hitRules: any[]) { const matchedRuleNamesSet = new Set<string>(); const normalizedDataText = this.normalizePunctuation(this.text).toLowerCase(); const currentSpeakerPrefix = this.data.policy ? '管教民警:' : '在押人员:'; hitRules.forEach(rule => { const sentences = this.splitSentences(rule.hitSentence); sentences.forEach(sentence => { const normalizedSentence = this.normalizePunctuation(sentence).toLowerCase(); if (normalizedSentence.startsWith(currentSpeakerPrefix.toLowerCase()) && normalizedSentence.includes(normalizedDataText)) { matchedRuleNamesSet.add(rule.hitRuleName); } }); }); this.matchedHitRuleNames = Array.from(matchedRuleNamesSet); } // 按管教民警或被监管人分割句子 splitSentences(text: string): string[] { const pattern = /(管教民警|被监管人):/g; const matches = text.match(pattern); const sentences: string[] = []; let startIndex = 0; if (matches) { matches.forEach((match, index) => { const endIndex = index === matches.length - 1 ? text.length : text.indexOf(matches[index + 1]); const sentence = text.substring(startIndex, endIndex).trim(); if (sentence) { sentences.push(sentence); } startIndex = endIndex; }); } return sentences; } handleInput(value) { this.isTemp = 1; // 如果输入框的输入发生改变证明在删除 赋值为1 {上面的判断证明如果输入框变化 为true 否则循环的text(文本)有值显示 没值不显示} // 监听input输入的文本长度 if (value.length == 1) { this.$message.error("输入字符长度至少1位"); // 阻止表单提交 } else { this.data.text = value; } } changeEditStatus() { const initialText = this.data.text; this.$prompt("", "文本修正", { confirmButtonText: "确定", cancelButtonText: "取消", inputPlaceholder: "", inputValue: initialText, // 设置$prompt的input初始值为编辑的文本 }) .then(({ value }) => { if (value.length < 1) { Message({ message: "最少保留1个字符内容!", type: "error" }); return; } else { // 正常输入 this.data.text = value; this.submitChange(); } }) .catch(() => { this.$message({ type: "info", message: "取消操作", }); }); } /** * 修改文本提交 */ async submitChange() { this.$emit("editContent", Number(this.data.startFrame), this.data.text, this.data.policy); this.setKeyword(false, this.talk.keywords.map((it: Keyword) => { return it.text; })); } /** * 关键字用label标签 */ setKeyword(forceUpdate: boolean = false, keywords: string[] = this.data.keywords) { // const keywords = this.canEdit? this.talk.keywords.map((it: Keyword) => { // return it.text // }) : this.data.keywords if (keywords == null || keywords.length == 0) { return; } if (this.data.policy /*|| !this.data.last*/) { return; } keywords.forEach((it) => { if (it.length == 0) { return; } this.text = this.text.replace(new RegExp(it, "gm"), `<label class='keyword'>${it}</label>`); }); if (forceUpdate) { this.$nextTick(() => { this.$forceUpdate(); }); } } /** * 搜索字用span标签 */ setSearchWord(word: string) { if (word == null || word.length == 0) { return; } this.text = this.text.replace(new RegExp(word, "gm"), `<span class='searched'>${word}</span>`); } setGaugesWord(word: string) { if (word == null || word.length == 0) { return; } this.text = this.text.replace(new RegExp(word, "gm"), `<span class='gauges'>${word}</span>`); } clearSearchWord() { this.text = this.text.replace(new RegExp("<span class='searched'>", "gm"), ""); this.text = this.text.replace(new RegExp("</span>", "gm"), ""); } copy() { this.$copyText(this.text) .then(() => { this.$notify({ title: "成功", message: "谈话内容已成功复制到粘贴板!", duration: 3000, type: "success", }); }) .catch(() => { this.$notify({ title: "失败", message: "谈话内容复制到粘贴板失败!", duration: 3000, type: "error", }); }); } fetchTalkItem() {//单个段落 console.log("this.data",this.data); // 确保有有效的startFrameendFrame if (this.data.startFrame && this.data.endFrame && this.data.endFrame - this.data.startFrame > 10) { // 最小10ms播放 this.$emit("fetchTalkItem", this.data); } else { console.warn("段落时间太短,不播放:", this.data); } } setAnswer() { this.$emit("setAnswer", this.data.text); } blink() { this.isBlink = true; this.console.debug(this); setTimeout(() => { this.isBlink = false; }, 1500); } } </script> <style lang="less" scoped> @import "../../../assets/styles/variables"; // 对讲内容是否命中 .isHit { font-size: 13px; color: #8b9199; margin: 8px 0 0 0; align-self: flex-start; } // 谈话框样式 公共配置 .talk-item { color: #47494e; padding: 0 0.5rem; .talk-avatar { display: inline-block; .el-avatar { position: relative; } .avatar { border-radius: 50%; background-size: 40px; } } .talk-paragraph { display: inline-block; padding: 0 1rem 10px 1rem!important; max-width: 70%!important; margin-bottom:8px!important; box-sizing: border-box; .time { padding-left: 1rem; padding-bottom: 0.3rem; font-size: 1rem; color: #ccc; /*min-height: 14px;*/ i { cursor: pointer; color: #7ea1de; } i:hover { color: slateblue; } } .progress-highlight{ position: absolute; top: 0; left: 0; border-radius: 8px; height: 93%; background-color: rgba(61, 111, 205, 0.5); /* 半透明蓝色 */ z-index: 0; transition: width 0.1s linear; } .text-container { display: flow-root; border-radius: 8px; min-width:120px; height: fit-content !important; overflow-x: hidden; .text-box { position: relative; display: inline-block; border-radius: 8px; padding: 10px; user-select: text; word-wrap: break-word; // 确保长单词换行 word-break: break-word; // 处理中文换行 overflow-wrap: break-word; // 处理长URL等 min-width:85%; max-width: 28ch; /* 限制最大宽度为大约28个字符的宽度包括符号(宽度自适应) */ overflow-x: hidden; /* 隐藏水平溢出 */ white-space: pre-wrap; /* 保留空白符序列,但正常地进行换行 */ } } } // -=-=-=-=-=-start播放命中高亮 .text-box.highlighted { background-color: #3d6fcd !important; color: white !important; transition: background-color 0.2s ease; } .talk-item.left .text-container:hover .isIcon.iconfont.icon-yinbo, .talk-item.right .text-container:hover .isIcon.iconfont.icon-yinbo, .text-container .isIcon.iconfont.icon-yinbo[style*="display: inline-block"] { display: inline-block !important; } // -=-=--=-=-end .talk-paragraph::before { display: inline-block; content: ""; width: 0; height: 0; line-height: normal; // border-width: 10px; // border-style: solid; // border-color: transparent; position: relative; top: 49px; } .highlight { .text-box { background-color: @talkItemHighlightBGColor !important; // background-color: #3d6fcd !important; // 原为 @talkItemHighlightBGColor,改为悬停色 // color: white !important; // 新增文字颜色 } } .blink { .text-box { background-color: @talkItemHighlightBGColor !important; animation: blink 0.5s 3; -webkit-animation-name: blink; -webkit-animation-duration: 500ms; -webkit-animation-iteration-count: 3; -webkit-animation-timing-function: ease-in-out; } } @keyframes blink { 0% { color: #fab4b4; } 25% { color: #fa6161; } 50% { color: #ff0000; } 75% { color: #fa6161; } 100% { color: #fab4b4; } } &:last-child { margin-bottom: 30px; } } ////////////////////////////////////////////////////////////////////////// // 左侧谈话框样式 .talk-item.left { display: flex; box-sizing: border-box; // &:hover { // width: 100% !important; // cursor: pointer; // border-radius: 10px; // background-color: #d7ecff !important; // border-left: 3px solid #409EFF !important; // transition: background-color 0.3s ease; // } .talk-avatar { .el-avatar { top: 38px; } } .talk-paragraph { .time { i { margin-left: 1rem; } } .text-container { position: relative; .isIcon.iconfont.icon-yinbo{ display: none; /* 默认隐藏 */ position: absolute; right: -28px; top: 8px; z-index: 1; font-size: 20px !important; border-radius: 50% !important; background: white !important; border: 1px solid rgb(219, 215, 215) !important; font-size: 20px !important; color: #3d6fcd !important; } &:hover .isIcon.iconfont.icon-yinbo { display: inline-block !important; /* 悬停时显示图标 */ } .text-box { background-color: @talkItemLeftBGColor; &:hover { cursor: pointer; color: white; background-color:#3d6fcd; } &:hover .isIcon.iconfont.icon-yinbo { display: inline-block; /* 悬停时显示图标 */ } } } } .talk-paragraph::before { border-right-width: 10px; border-right-color: @talkItemLeftBGColor; left: -19px; } .highlight::before, .blink::before { border-right-color: @talkItemHighlightBGColor !important; } } ////////////////////////////////////////////////////////////////////////// // 右侧谈话框样式 .talk-item.right { text-align: right; box-sizing: border-box; // &:hover { // width: 100% !important; // cursor: pointer; // border-radius: 10px; // background-color: #d7ecff !important; // border-left: 3px solid #409EFF !important; // transition: background-color 0.3s ease; // } .talk-avatar { float: right; .el-avatar { top: 36px; } } .talk-paragraph { .time { i { margin-right: 1rem; } } .text-container {//右侧谈话 position: relative; .isIcon.iconfont.icon-yinbo { display: none; /* 默认隐藏 */ position: absolute; left: -28px; top: 8px; z-index: 1; font-size: 20px !important; border-radius: 50% !important; background: white !important; border: 1px solid rgb(219, 215, 215) !important; font-size: 20px !important; color: #3d6fcd !important; } &:hover .isIcon.iconfont.icon-yinbo { display: inline-block !important; /* 悬停时显示图标 */ } .text-box { text-align: left; background-color: @talkItemRightBGColor; &:hover { cursor: pointer; color: white; background-color:#3d6fcd; } } } } .talk-paragraph::before { border-left-width: 10px; border-left-color: @talkItemRightBGColor; right: -19px; } .highlight::before, .blink::before { border-left-color: @talkItemHighlightBGColor !important; } } </style> <style lang="less"> .text-container { .text-box { .searched { color: #f54646; background-color: #f3f35d; } .keyword { color: red; font-weight: bold; } .gauges { color: #2fefd8; } } .text-box.el-input { padding: 5px !important; .el-input__inner { color: #560692; background: inherit; padding: 0; border-width: 0; } } .text-box.el-textarea { width: 350px; padding: 5px !important; .el-textarea__inner { color: #560692; background: inherit; padding: 0; border-width: 0; } } } .talk-item.right { .text-box.el-input, .text-box.el-textarea { float: right; right: 0px; } } </style> import jsonData from '../public/123.json' 基于引用数据来操作<template> <div class="main"> <div class="sec"> <div v-for="item in list" :key="item.timestamp"> {{ item.text }} </div> </div> </div> </template> <script lang="ts"> import { reactive, toRefs, onMounted } from 'vue' import { useRouter, useRoute } from 'vue-router' import jsonData from '../public/123.json' // 定义 content 中每项的类型 interface ContentItem { count: number policy: boolean speaker: string timestamp: number text: string startFrame: string endFrame: string emotions: null keywords: null last: boolean emotionSeg: Record<string, unknown> } export default { name: '', setup() { const router = useRouter() const route = useRoute() const data = reactive<{ list: ContentItem[] }>({ list: [] // 初始化为空数组但有明确类型 }) onMounted(() => { data.list = jsonData.data.content as ContentItem[] console.log(data.list) console.log(jsonData.data.content, 'jsonData') }) const refData = toRefs(data) return { ...refData } } } </script> <style lang="scss" scoped> .main{ width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; .sec{ width: 800px; height: 600px; border: 1px solid red; } } </style> 修复一下吧亲 基于我提供代码
最新发布
08-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值