在作開發時,有一種需求是對輸入框(input,textarea)的字數作限制。若是按照JS的規定,字符串裏全部的字符,長度都是1。可是有時候咱們須要實現文本框中輸入中文長度是2(或是3),其餘非中文輸入是1。這個時候就須要本身寫一段代碼來判斷:html
function getStringLengthForChinese (val) { let str = val.toString() let bytesCount = 0 for (let i = 0, len = str.length; i < len; i++) { let c = str.charCodeAt(i) if ((c > 0x0001 && c <= 0x007e) || (c >= 0xff60 && c <= 0xff9f)) { //這裏是16進製表示,也能夠用十進制 bytesCount = bytesCount + 1 } else { bytesCount = bytesCount + 2 } } return bytesCount }
這樣就實現了獲取一段字符串的長度,中文爲2。vue
接下來就是對輸入的字符串長度進行限制:算法
在input和textarea中,輸入的長度限制須要添加maxlength屬性。一般狀況下,只要給maxlength一個固定的值就能解決問題。可是這裏因爲咱們的中文預設長度是2。因此maxlegth的值應該是動態設置的。
我用vue來寫,只要在模板中給maxlength綁定一個值:npm
<textarea :maxlength="maxlegth" @input="textareaChange($event)" ></textarea> <span>還能夠輸入{{codeNum}}個字符</span>
maxlegth須要給定一個預設值。
下面是限制字符輸入數量的方法:數組
function computedLen(str, totalLength, maxLength) { let rep = /[0-9a-zA-Z|\s]/ // 正則判斷字母數字 let strArr = str.split('') let totalLen = totalLength// 總的輸入長度 let maxLen = maxLength// input或textarea上maxlength的值,這裏因爲中文算2個佔位,因此傳入的maxLength應該爲totalLength的一半 let len = 0 // 已經輸入的字符數 let leftLen = 0 // 剩餘可輸入字符數 strArr.forEach((val,key) => { if (rep.test(val)) { leftLen = Math.ceil(totalLen - len * 2)// 剩餘輸入數等於總長 - 輸入數,乘以2是由於非中文的len只算0.5 if (leftLen === 0) { return false // 若是剩餘數是0,就退出循環,不能輸入了 } len = len + 0.5// 若是輸入非中文,算加半個字符,maxlengtrh也加0.5,這樣就實現了兩個非中文長度等於一箇中文 maxLen = maxLen + 0.5 } else { len = len + 1 } }) return { maxLen: Math.ceil(maxLen) // 返回咱們須要的maxlegt的值 } } function textareaChange (e) { setTimeout(() => { let count = this.computedLen(e.target.value, 30, 15) this.maxLength = count.maxLen }, 200) }
上面代碼的關鍵在於獲取maxlength的值。這個值是動態的,在只輸入中文的狀況下,這個值等於咱們的預設值,若是輸入兩個非中文,maxlength就會動態的加1。app
vue watch監聽剩餘字數,並截斷多出的字符。由於中文輸入法的在非正式輸入時,對於咱們這個算法,會出現剩餘字符數爲負值的狀況。因此須要增長如下代碼,在輸入數量超過期截斷。ui
watch: { 'title' () { this.codeNum = 30 - this.getStringLengthForChinese(this.title) if (getStringLengthForChinese(this.title) > 30) {//若是佔位數大於30 let arr = this.title.split('')// 輸入字符串轉爲數組,依次推出最後一位元素 for (let i = arr.length - 1; i >= 0; i--) { arr = arr.slice(0, i)// 每推出一個,將數組轉爲字符串,作一次佔位數判斷 this.title = arr.join('') if (getStringLengthForChinese(this.title) <= 30) { break } } } } }
最終效果:this
完整demo(vue寫的):spa
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <div id="app"> <textarea :maxlength="maxLength" v-model="title" @input="textareaChange($event)"></textarea> <span>還能輸入{{codeNum}}</span> </div> <body> </body> <script> new Vue({ el: '#app', data() { return { title: '', maxLength: 15, codeNum: 30 } }, methods: { getStringLengthForChinese(val) { let str = val.toString() let bytesCount = 0 for (let i = 0, len = str.length; i < len; i++) { let c = str.charCodeAt(i) if ((c > 0x0001 && c <= 0x007e) || (c >= 0xff60 && c <= 0xff9f)) { //這裏是16進製表示,也能夠用十進制 bytesCount = bytesCount + 1 } else { bytesCount = bytesCount + 2 } } return bytesCount }, textareaChange(e) { setTimeout(() => { let count = this.computedLen(e.target.value, 30, 15) this.maxLength = count.maxLen }, 200) }, computedLen(str, totalLength, maxLength) { let rep = /[0-9a-zA-Z|\s]/ // 正則判斷字母數字 let strArr = str.split('') let totalLen = totalLength // 總的輸入長度 let maxLen = maxLength // input或textarea上maxlength的值,這裏因爲中文算2個佔位,因此傳入的maxLength應該爲totalLength的一半 let len = 0 // 已經輸入的字符數 let leftLen = 0 // 剩餘可輸入字符數 strArr.forEach((val, key) => { if (rep.test(val)) { leftLen = Math.ceil(totalLen - len * 2) // 剩餘輸入數等於總長 - 輸入數,乘以2是由於非中文的len只算0.5 if (leftLen === 0) { return false // 若是剩餘數是0,就退出循環,不能輸入了 } len = len + 0.5 // 若是輸入非中文,算加半個字符,maxlengtrh也加0.5,這樣就實現了兩個非中文長度等於一箇中文 maxLen = maxLen + 0.5 } else { len = len + 1 } }) return { maxLen: Math.ceil(maxLen) // 返回咱們須要的maxlegt的值 } } }, watch: { 'title' () { this.codeNum = 30 - this.getStringLengthForChinese(this.title) if (getStringLengthForChinese(this.title) > 30) { //若是佔位數大於30 let arr = this.title.split('') // 輸入字符串轉爲數組,依次推出最後一位元素 for (let i = arr.length - 1; i >= 0; i--) { arr = arr.slice(0, i) // 每推出一個,將數組轉爲字符串,作一次佔位數判斷 this.title = arr.join('') if (getStringLengthForChinese(this.title) <= 30) { break } } } } } }) </script> </html>