vue.js實現只能輸入數字的輸入框


如果只是一個輸入框,要實現就非常的簡單了,輸入框的內容和數據綁定,給數據加一個監聽器就可以了,代碼如下:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Vue</title>
    <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<body>
    <div id="div1">
        <input v-model="content">
    </div>
    <script>
        var mydata = new Vue({
            el: '#div1',
            data: {
                content: ''
            },
            watch: {
                content: function(val){
                    this.content = val.replace(/\D/g, '')
                }
            }
        })
    </script>
</body>
</html>

如果頁面或是系統里有很多這樣的輸入框,這樣做,就不是很好了。每個數據都加一個監聽器,然后某一天突然需求改了,可以輸入數字和字母了,那就要改得吐血了!而且這樣做,代碼也沒有可移植性,到了另一個系統里,還得重寫一遍,所以,就要寫一個通用的方法來實現這個需求。這個時候就要用到組件的功能,先新建一個js文件,我這里就叫num.js。然后num.js里面的代碼:

Vue.component('number', {
    template: '<input type="text" v-model="con">',
    data: function(){
            return {
                con: ''
            }
        },
    watch: {
        con: function(val){
            this.con = val.replace(/\D/g, '');
        }
    }
})

這樣就定義了一個組件number,組件里是一個輸入框,輸入框的內容與數據con綁定,監聽器控制con只能是數字。然后在html頁面里引入num.js,在頁面添加<number></number>標簽,在瀏覽器里,看到的就是一個輸入框,但是輸入框只能輸入數字。在頁面放置輸入框,是為了讓用戶輸入內容,輸入的內容是要給程序用的。那要怎么獲取輸入框的內容?如果是用jquery的話,那就是通過dom來獲取,但vue的設計理念是dom和數據分離,通過dom來獲取就不合適,所以就要讓輸入框與一個數據綁定起來。

 

 

現在頁面有三個輸入框,三個輸入框的內容要分別綁定到val1、val2、val3。該怎么弄?一開始,我的做法是在number標簽上定義一個方法,組件里con的監聽器監聽到con值有改變時,就調用這個方法,把con的值傳出來,而這個方法又會調用mydata里的一個方法,兩次傳遞,把值傳給對應的val。這邏輯,聽着是不是感覺很繞。很繞都不怕,重要的是,別人用起來很不方便,需要自己到mydata里定義一個方法來賦值。所以后來就再改,輸入框的內容不是要綁定一個數據嗎?那要綁定到哪個數據,得告訴我吧,所以在number標簽上,需要告訴我對象是哪個,屬性名是哪個,這樣,我就可以把輸入框的內容綁定到這個對象的這個屬性上。在這里,對象就是mydata,屬性名就是val1、val2、val3。把對象傳進去,傳的是字符串mydata,並不是一個對象,在組件里面,要怎么使用mydata這個對象?這個時候,就需要用到js里非常強大的一個函數eval,eval函數接收一個字符串參數,只能是字符串,然后函數會把這個字符串當作js代碼來解析並執行。代碼

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>vue</title>
        <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
        <script src="num.js"></script>
    </head>
    <body>
        <div id="div1">
            <number objname="mydata" keys="val1"></number>
            <number objname="mydata" keys="val2"></number>
            <number objname="mydata" keys="val3"></number>
            <p>第一個輸入框的內容是: {{val1}}</p>
            <p>第二個輸入框的內容是: {{val2}}</p>
            <p>第三個輸入框的內容是: {{val3}}</p>
        </div>
 
        <script>
            var mydata = new Vue({
                el: '#div1',
                data: {
                    val1: '',
                    val2: '',
                    val3: ''
                }
            })
        </script>
    </body>
</html>

num.js的代碼:

Vue.component('number', {
    props: ['objname', 'keys'],
    template: '<input type="text" v-model="con">',
    data: function(){
            return {
                con: ''
            }
        },
    watch: {
        con: function(val){
            this.con = val.replace(/\D/g, '');
            eval(this.objname+'[this.keys]=this.con');
        }
    },
})

運行效果圖:

 

 這樣,輸入框限制了只能輸入數字,也和數據綁字了,但這只是單向的綁字,輸入框的內容改變了,外面的數據會跟着改變,但外面的數據改變了,輸入框的內容不會跟着改變,所以,現在只是單向的綁定。在頁面下面再添加三個普通的輸入框,三個輸入框分別綁定val1、val2、val3

 

 這個時候到頁面上操作就會發現,上面的輸入框內容改變會影響下面的,但下面的輸入框內容改變了,就不會影響上面的輸入框的內容

 

 

這個時候,要實現反向的綁定,那就需要在組件里為外面的數據添加監聽器。有對象,有屬性名,為它加監聽器,是可以加的,但是外面的屬性要綁定哪個組件里的輸入框呢?所以組件上要再添加一個屬性ref,這個ref是vue定義的一個屬性,用來找子組件的。這樣,代碼最終就變成

<div id="div1">
            <number ref="val1" objname="mydata" keys="val1"></number>
            <number ref="val2" objname="mydata" keys="val2"></number>
            <number ref="val3" objname="mydata" keys="val3"></number>
            <p>第一個輸入框的內容是: {{val1}}</p>
            <p>第二個輸入框的內容是: {{val2}}</p>
            <p>第三個輸入框的內容是: {{val3}}</p>
            <input v-model="val1">
            <input v-model="val2">
            <input v-model="val3">
        </div>

num.js里面

Vue.component('number', {
    props: ['objname', 'keys'],
    template: '<input type="text" v-model="con">',
    data: function(){
            return {
                con: ''
            }
        },
    mounted: function(){
        var self = this;
        window.addEventListener('load', function(){
            //頁面加載完成,把父對象的數據賦值進來,相當於是做了一個初始化的操作
            eval(self.objname + '.$refs.' + self.keys + '.con=' + self.objname + '[\'' + self.keys + '\']');
            //為外面的數據,添加一個監聽器
            eval(self.objname+'.$watch(\''+self.keys+'\',function(val){this.$refs.'+self.keys+'.con=val})');
        })
    },
    watch: {
        con: function(val){
            this.con = val.replace(/\D/g, '');
            eval(this.objname+'[this.keys]=this.con');
        }
    },
})

這樣,數據就實現了雙向綁定。在mounted里面,addEventListener方法是有兼容問題的,IE8及以下版本沒有這個方法,我這里沒有做兼容處理。然后就是優化,看代碼就發現,在number標簽上,ref和keys實際上是一樣的,可不可以只用一個?經過實驗,在組件內部獲取ref的值獲取不到,這個我還不知道怎么獲取,學得不夠深吶。然后就是objname可不可以不傳,不傳的話就默認是組件的父對象,這個是可以實現的。最后,組件還可以進行一些擴展,比如再添加一個屬性mytype,mytype不傳則默認輸入框只能輸入數字,如果為word,則輸入框只能輸入字母和數字,如果為chinses,則只能輸入中文漢字等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM