2018年07月11日

基于vue的限制输入框可输入字节数的解决方案

需求:input输入框输入上限4个字节、达到上限则不能继续输入,其中1个英文表示1个字节、1个中文表示2个字节。

看到这个需求,第一个想到的就是input元素的maxlength属性。

MDN对input的maxlength属性的说明是:

如果 type 的值是 text, email, search, password, tel, 或 url,那么这个属性指明了用户最多可以输入的字符个数(按照Unicode编码方式计数);对于其他类型的输入框,该属性被忽略。它可以大于 size 属性的值。如果不指定这个属性,那么用户可以输入任意多的字符。如果指定为一个负值,那么元素表现出默认行为,即用户可以输入任意多的字符。本属性的约束规则,仅在元素的 value 属性发生变化时才会执行。译者注:ie10+

从中我们可以得知两个有用信息:

maxlength可以用来限制输入长度;

maxlength是按字符数进行限制的,不能区分中英文。

根据这两个信息,我们得到了实现此需求的基本方案:

在用户输入之后计算输入内容的字节数和剩余可输入字节数,并动态地改变input元素的maxlength属性值。

计算输入内容的字节数

将输入内容的每一个中文字符替换成两个英文字符,计算其字符长度:

// 返回字符串str的长度,其中中文占2个长度单位,英文等字符占1个长度单位

let length = (str) => {

var r = /[^\x00-\xff]/g

return str.replace(r, 'mm').length

}

动态地改变maxlength值

思考解决方法过程中,分别实现过 通过@input事件触发方法来修改maxlength、把处理方法放到mixin里、封装一个处理方法的指令 3种方式,考虑可移植性及修改作用域字段的可行性,最终采用指令方式。

下面对主要逻辑进行说明:

maxlength:input元素maxlength属性值

limit:限制字节数

中文多消耗的字节数中文字符个数maxlength = limit - 中文多消耗的字节数 = limit - 中文字符个数

当连续输入的内容的字节数超过limit时,需要对内容进行截断:

截断长度 = 一个一个输入的非中文字符串长度 + 允许输入的中文字符串长度 = 非中文字符长度 + Math.floor((limit - 非中文字符所占字节数) / 2)

截断后内容 = 截断前内容.substring(0, 截断长度)

当在两个非中文之间(非末尾)输入超过限制的中文时,截取长度会多1个字节,需要再次校准输入内容:

校准后内容 = 校准前内容.substring(0, 截断长度 - 1)

vue自定义指令的钩子update是在VNode更新时调用,所以我们的处理方法在update钩子中进行;

vue自定义指令钩子函数会被传入参数el、binding、vnode、oldVnode。我们可以通过el拿到指定绑定的DOM;通过binding拿到指令的绑定值和传入的参数等等;通过vnode可以拿到vue编译生成的虚拟节点,其中vnode.context是虚拟节点上下文、也就是this,通过它我们可以改变指令所在组件data的任一变量。

其他方案及其缺陷

input v-model 使用 computed

export default {

data () {

return {

contentStore: ''

}

},

computed: {

content: {

get () {

return this.contentStore

},

set (val) {

this.contentStore = maxlength(val, 4) // maxlength是截取字符串方法

}

}

}

}

问题:虽然变量长度被限制了,但输入框仍可继续输入。

打印input元素的value,得到:

双向数据绑定失效了。

从v-model双向数据绑定原理入手

方法1中双向数据绑定失效了,那么我们来研究下input双向数据绑定的实现原理,看看能否找到突破口。

input的v-model只是一个简化的指令,它的双向数据绑定原理如下:

msg = e.target.value">

msg = e.target.value">

改写双向数据绑定方法:

methods: {

maxlengthInput (e) {

this.contentStore = maxlength(e.target.value, 4) // maxlength是截取字符串方法

}

}

结果和方法1一样,输入框仍可继续输入。

这里input的value是根据contentStore进行改变的,那直接修改DOM是否可行呢?

直接修改DOM的value值

在方法2的基础上,修改maxlengthInput方法,通过DOM操作来直接修改input的value,并打印出input的value进行观察:

methods: {

maxlengthInput (e) {

let value = maxlength(e.target.value, 4)

this.contentStore = value

document.querySelector('.el-input__inner').value = value

console.log(document.querySelector('.el-input__inner').value)

}

}

根据打印出来的内容可以看到,实际上input的value被改变了,而输入框内仍可正常输入,原因可能是element-ui的处理顺序问题(用原生input元素没有这个问题),那我们把dom赋值操作延后到下一个tick:

maxlengthInput (e) {

let value = maxlength(e.target.value, 4)

this.contentStore = value

setTimeout(() => {

document.querySelector('.el-input__inner').value = value

console.log(document.querySelector('.el-input__inner').value)

}, 0)

}

结果是可行的:

所以结束了吗?来输入中文试试:

中文输入法的每个拼音字母都被认为是一个有效的输入,这个缺陷是致命的。

compositionend事件

输入中文时,会先后触发compositionstart(输入中文前)、compositionend(中文输入完成后)事件。所以可以利用compositionend事件解决方法3的问题。

但是,删除输入内容时是无法触发compositionend事件的,那么,就需要同时监听input事件。

input事件会比compositionend事件先触发,所以会出现方法3的无法输入中文的问题,不过只要把input事件处理延迟到compositionend之后(比如用setTimeout),这个问题也可以解决。随之而来的问题就是输入非中文字符时,input事件处理也会延迟,用户体验不太友好。

总结

对于区分中英文来限制输入框输入长度的需求,利用input元素的maxlength属性是比较便利和可行的方式;使用vue自定义指令可以提高方法的可用性(再把指令封装成插件,可以很大地提高方法的可移植性)。

当然,vue自定义指令方法有一个问题,当在非末尾输入超过limit的内容时,会截断末尾的字符、而不是截断正在输入的内容。解决这个问题需要比较输入前和输入后的字符串、再把diff出的字符串截断掉。虽然这个问题可以解决,但性价比不高,对于当前的需求也没有解决的必要。

参考

vue设置输入框输入长度_基于vue的限制输入框可输入字节数的解决方案相关推荐

  1. vue 移动到图片浮动_基于Vue实现拖拽升级(九宫格拖拽)

    前言 在本文中将会用Vue完成九宫格拖拽效果,同时介绍一下网格布局.具体代码以及demo可以点以下超链接进入 效果实例 Demo 简单了解Grid布局(网格布局) 什么是网格布局 CSS网格布局(又称 ...

  2. vue 文字上下循环滚动_基于 Vue 无缝滚动组件Vue-Seamless-Scroll

    今天给小伙伴们推荐一款超棒的Vue无缝滚动组件VueSeamlessScroll. vue-seamless-scroll 基于 vue.js 构建的简单实用的无缝滚动组件.满足丰富的配置需求,支持上 ...

  3. 移动端vue实现部门结构功能_基于Vue的组织架构树组件

    由于公司业务需求,需要开发一个展示组织架构的树组件(公司的项目是基于Vue).在GitHub上找了半天,这类组件不多,也没有符合业务需求的组件,所以决定自己造轮子! 分析 既然是树,那么每个节点都应该 ...

  4. 移动端vue实现部门结构功能_基于Vue制作组织架构树组件

    编程之家收集整理的这篇文章主要介绍了基于Vue制作组织架构树组件,编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考. 由于公司业务需求,需要开发一个展示组织架构的树组件(公司的项目是基于Vu ...

  5. vue设置textarea最大字数_【Vue 学习】 Vue常用系统指令

    1 v-on 指令 1.1 v-on:click 1.2 v-on:keydown 1.3 v-on:mouseover 1.4 事件修饰符 1.5 按键修饰符 2 v-text .v-html.v- ...

  6. 在vue中实现picker样式_基于Vue实现timepicker

    主要用到的还是Vue的基本知识而已,不过要想到的细节很多. 先放效果,点击上框,显示timepicker.而且可以根据点击的是时还是分来改变圆盘的数字. 这里我用了两个组件,和,这里的时和分的数值我挂 ...

  7. vue 移动到图片浮动_基于Vue实现图片在指定区域内移动

    当图片比要显示的区域大时,需要将多余的部分隐藏掉,我们可以通过绝对定位来实现,并通过动态修改图片的left值和top值从而实现图片的移动.具体实现效果如下图,如果我们移动的是div 实现思路相仿. 此 ...

  8. vue 移动端头像裁剪_基于vue的移动端图片裁剪压缩处理

    前端时间做Vue项目的时候,要用到图片压缩处理,网上查阅了资料后,发现并不能满足实际的业务需求:于是,自己结合网上的资料写了一个,有兴趣的小伙伴不妨试试~ 废话不多说,先上效果图,无图无真相嘛~ 效果 ...

  9. 在vue中实现picker样式_基于vue的颜色选择器vue-color-picker

    /** * author : alex * email : 961163829@qq.com*/exportdefault{ props:{/*由父组件传递的默认颜色*/defaultColor:{ ...

最新文章

  1. 第三十一篇:SOUI布局之相对于特定兄弟窗口
  2. ASP.NET 3.5技术专题发布
  3. python 链栈及基本操作
  4. wordpress语言文件.po.pot.mo简介及汉化
  5. 更新:让UpdatePanel支持上传文件
  6. 实现拼团_生鲜商家如何使用微信拼团小程序做水果生鲜拼团活动?
  7. ubuntu的home目录下,Desktop等目录消失不见
  8. php可变变量讲解,PHP可变变量实例详解
  9. java学习(58):私有内部类后访问
  10. HA机制的大数据集群的搭建过程
  11. 求出数组中超过一半的数
  12. 手游加速器原理分析和代码实现
  13. fedora安装字体
  14. Mac电脑专业音乐制作Logic Pro X中文
  15. 点餐小程序的数据库设计以及系统实现
  16. linux 极点五笔,Linux 安装ibus极点五笔输入法备忘录
  17. 小tips:页面滚动到关闭时的位置与不滚动
  18. Dubbo-Zookeeper注册中心;监控中心
  19. 【tph-yolov5】tph-Yolov5的Pytorch环境配置和运行错误记录
  20. Python利用Scrapy爬取智联招聘和前程无忧的招聘数据

热门文章

  1. RPnP算法原文及代码解析
  2. Win10系统下安装CAA二次开发程序,VS界面上不出现CAA菜单栏或菜单栏为灰色的
  3. 蓝桥杯往年真题(简单题)
  4. 20145202马超《网络对抗》Exp5MSF基础应用
  5. 微服务时代--service meshAGW
  6. 生化危机暗黑历代记汉化终于完成了
  7. inputstreamreader用法
  8. CAD二次开发--如何获取图面“组”对象及其内部实体(以南方CASS居民地-房屋为例)
  9. leetcode记录-524-通过删除字母匹配到字典里最长单词-双指针
  10. Android 仿今日头条的开源项目