1. 程式人生 > >vue學習筆記(八)元件校驗&通訊

vue學習筆記(八)元件校驗&通訊

前言

在上一章部落格的內容中vue學習筆記(七)元件我們初步的認識了元件,並學會了如何定義區域性元件和全域性元件,上一篇內容僅僅只是對元件一個簡單的入門,並沒有深入的瞭解元件當中的其它機制,本篇部落格將會帶大家深入瞭解元件的其它知識,元件的校驗,元件的通訊等等。

本章目標

  • 學會元件簡單的校驗
  • 學會父元件向子元件傳遞資料
  • 學會子元件向父元件傳遞資料

父元件向子元件傳遞資料

父元件向子元件傳遞資料實現的方式特別簡單,只用使用props進行資料傳遞就可以了。

語法:props['屬性1',‘屬性2’,...]

我找了一張圖給大家參考一下

在 Vue.js 中,父子元件的關係可以總結為 props down, events up 。父元件通過 props 向下傳遞資料給子元件,子元件通過 events 給父元件傳送訊息

(1)簡單的父元件向子元件傳遞資訊

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>父元件向子元件傳遞資訊</title>
    </head>
    <body>
        <div id="app">
            <my-content :title='title' :content='content'></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    title:'標題',
                    content:'內容'
                },
                methods:{
                    
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        props:['title','content'],
                        template:`<div>
                            <h1>{{title}}</h1>
                            <p>{{content}}</p>
                        </div>`
                    }
                }
                
            })
            
        </script>
    </body>
</html>

結果:顯示標題和內容,最簡單的父元件向子元件傳遞資訊我們就實現了,但是裡面還有其它的小知識點我們沒有講解到,而且後期開發都是使用vue-cli來實現父元件向子元件傳遞資料的,所以這個知識點下一篇部落格會講解到,不會搭建vue-cli專案的朋友可以參考這篇部落格使用webstorm搭建vue-cli專案後續的許多文章都會使用vue-cli中的元件進行講解,而不是通過簡單的引入vue.js檔案了,所以強烈推薦大家一定要學會搭建vue-cli專案。

總結:父元件向子元件傳遞資料使用props

(2)props傳遞整個物件

假設父元件中的物件含有多個屬性,我們每一個屬性都需要進行傳遞,那麼是不是需要繫結每一個屬性呢?

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>props傳遞多個屬性</title>
    </head>
    <body>
        <div id="app">
            <my-content :title="attr.title" :content1="attr.content1" :content2="attr.content2"></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    attr:{
                        title:'新聞主題',
                        content1:'新聞內容1',
                        content2:'新聞內容2',
                    }
                },
                methods:{
                    
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        props:['title','content1','content2'],
                        template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
                    }
                }
                
            })
            
        </script>
    </body>
</html>

現在這個例項所表現出來的就是一個物件裡面有很多個屬性,現在僅僅只有三個屬性而已,我們的父元件繫結屬性的時候就需要繫結三個屬性,如果是100個或者1000個那麼繫結元件的那個標籤不是很長嗎?和同事一起開發的話,你的同事看到那麼長的程式碼肯定會懷疑人生的,所以為了解決這個問題我們將程式碼改寫下面那樣。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>props傳遞多個屬性</title>
    </head>
    <body>
        <div id="app">
            <my-content  v-bind="attr"></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    attr:{
                        title:'新聞主題',
                        content1:'新聞內容1',
                        content2:'新聞內容2',
                    }
                },
                methods:{
                    
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        props:['title','content1','content2'],
                        template:'<div><h4>{{title}}</h4><span>{{content1}}</span><span>{{content2}}</span></div>'
                    }
                }
                
            })
            
        </script>
    </body>
</html>

在這裡我們使用v-bind將整個物件打包傳遞過去,這樣一來就大大的減少了程式碼的冗餘度了,那麼你的同事肯定誇你小夥子不錯,你就等著被領導表揚吧!(自己腦補出來的)

data必須是函式

為什麼說data必須是一個函式呢?這個知識點在上一篇部落格中沒有提及到,現在的話我們來討論一下,這個案例就足夠說明了。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>data必須是函式</title>
    </head>
    <body>
        <div id="app">
            <my-content></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            Vue.component('myContent',{
                data:{
                    msg:'hello world'
                },
                template:'<span>{{msg}}</span>',
            });
            let vm=new Vue({
                el:'#app'
            })
        </script>
    </body>
</html>

結果:

 控制檯顯示vue.js給出的警告也是提出data必須是一個函式,好的既然規定data必須是一個函式,那我們就按照它說的來做。看看結果如何

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>data必須是函式</title>
    </head>
    <body>
        <div id="app">
            <my-content></my-content>
            <my-content></my-content>
            <my-content></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var data={
                count:1
            }
            Vue.component('myContent',{
                data:function(){
                    return data;
                },
                template:'<button @click="count+=1">{{count}}</button>',
            });
            let vm=new Vue({
                el:'#app'
            })
        </script>
    </body>
</html>

 

現在的話,我們的data是一個函式,但是解決一個問題的同時新的問題又出現了,點選任意一個按鈕的時候發現其它按鈕的值都會發生改變,這是因為我們引用了同一個物件,我們知道物件是引用傳遞的,所以為了改變這一種情況,我們讓每個元件內部都有自己的狀態而不會去幹涉其它元件。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>data必須是函式</title>
    </head>
    <body>
        <div id="app">
            <my-content></my-content>
            <my-content></my-content>
            <my-content></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            Vue.component('myContent',{
                data(){
                    return{
                        count:1
                    }
                },
                template:'<button @click="count+=1">{{count}}</button>',
            });
            let vm=new Vue({
                el:'#app'
            })
        </script>
    </body>
</html>

結果:

 我們在data中使用return返回新的物件,這樣一來每一個元件都有自己本身的狀態了,從而不會去影響其它的元件。

元件的校驗

元件的校驗從字面上看就是對父元件向子元件傳遞的資訊中,子元件對父元件傳遞過來的資訊進行驗證,一方面是為了資料的安全性,另一方面給他人使用的時候也可以限制他人傳遞過來的資料的驗證。

Vue.component('example', {
  props: {
    // 基礎型別檢測 (`null` 意思是任何型別都可以)
    propA: Number,
    // 多種型別
    propB: [String, Number],
    // 必傳且是字串
    propC: {
      type: String,
      required: true
    },
    // 數字,有預設值
    propD: {
      type: Number,
      default: 100
    },
    // 陣列/物件的預設值應當由一個工廠函式返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函式
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

type可選:

  • Sting
  • Number
  • Boolean
  • Function
  • Object
  • Array

(1)示例一

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>元件的校驗示例一</title>
    </head>
    <body>
        <div id="app">
            <my-content :name="name" :age="age" :sex="sex"></my-content>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    name:'小明',
                    age:18,
                    sex:'男'
                },
                methods:{
                    
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        props:{
                            name:{
                                type:Number,
                                required:true,
                            },
                            age:{
                                type:Number,
                                default:20,
                            },
                            sex:{
                                type:String,
                                default:'女'
                            }
                        },
                        template:'<div><span>{{name}}</span><span>{{age}}</span><span>{{sex}}</span></div>'
                    }
                }
                
            })
            
        </script>
    </body>
</html>

結果:

我們對name做了驗證規定,name的型別必須是Number,而傳遞過來的卻是String,所以vue.js給出了警告,對name屬性也要求是必須傳遞的引數,required:true,對sex給定預設值,當我們沒有傳遞sex的時候,子元件中的sex預設值是女的,所以有了元件的這一校驗,大大提高的資料的安全性。

(2)示例二

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>元件的校驗示例二</title>
    </head>
    <body>
        <div id="app">
            <my-content name="喜馬拉雅" :size="8848" :is-boy="false" address="中國西藏"></my-content>
        </div>
        <script type="text/template" id="template1">
            <div>姓名:{{name}}身高:{{size}}是否是男生:{{isBoy}}位置:{{address}}重量:{{weight.ton}}億噸</div>
        </script>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            Vue.component('myContent',{
                template:'#template1',
                props:{
                    name:{
                        type:String,    //型別
                        required:true,    //規定必填
                    },
                    size:Number,    //規定整形
                    isBoy:Boolean,    //規定布林值
                    age:[Number,String],//    多種型別
                    address:{
                        type:String,
                        default:'中國',
                        validator:function(value){
                            return value.indexOf('中國')>=0
                        }
                    },
                    weight:{
                        type:Object,
                        default:function(){
                            return {ton:999999999}
                        }
                    },
                }
                
            })
            let vm=new Vue({
                el:'#app',
                data:{
                    
                },
                methods:{
                    
                },
                computed:{
                    
                }
                
            })
            
        </script>
    </body>
</html>

結果:

子元件向父元件傳遞資料

我們知道,父元件是使用 props 傳遞資料給子元件,但如果子元件要把資料傳遞回去,應該怎樣做?那就是自定義事件!每個 Vue 例項都實現了事件介面(Events interface),即:

  • 使用 $on(eventName) 監聽事件
  • 使用 $emit(eventName) 觸發事件

接下來我們一步一步對子元件向父元件傳遞資料進行講解,先來看下一個特別簡單的示例,這個需求是這樣的,當我們改變子元件的count的時候,父元件的count也需要改變

(1)子元件實現功能

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>子元件向父元件傳遞資料</title>
    </head>
    <body>
        <div id="app">
            <my-content :count="count"></my-content>
            父元件的count:<span>{{count}}</span>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    count:1
                },
                methods:{
                    
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        data(){
                            return{
                                ownCount:this.count
                            }
                        },
                        props:['count'],
                        template:'<div>子元件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                        methods:{
                            handleClick(){
                                this.ownCount++;
                            }
                        }
                    }
                }
                
            })
            
        </script>
    </body>
</html>

我們通過父元件向子元件傳遞了count值,然後子元件中的count值在點選之後會發生改變,但是這僅僅實現了子元件的值改變,並沒有實現父元件中的count改變

(2)向父元件傳遞資訊

需要向父元件傳遞資訊的話,我們就需要子元件通知父元件,然後父元件在做相應的處理,而需要通知父元件我們就i需要用到this.$emit('事件名稱',值)。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>子元件向父元件傳遞資料</title>
    </head>
    <body>
        <div id="app">
            <my-content :count="count" @add="handleAdd"></my-content>
            父元件的count:<span>{{count}}</span>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    count:1
                },
                methods:{
                    handleAdd(count){
                        this.count=count;
                    }
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        data(){
                            return{
                                ownCount:this.count
                            }
                        },
                        props:['count'],
                        template:'<div>子元件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                        methods:{
                            handleClick(){
                                this.ownCount+=10;
                                this.$emit('add',this.ownCount);
                            }
                        }
                    }
                }
                
            })
            
        </script>
    </body>
</html>

結果:

我們在子元件點選按鈕的時候添加了this.$emit()來通知父元件,然後將需要註冊的事件和每次改變的值傳遞了過去,這時父元件註冊子元件傳遞過來的事件和值,然後將父元件中的值替換子元件傳遞過來的就可以了。

(3)優化子元件向父元件傳遞資訊

其實我們可以做到讓父元件來控制子元件中count值的變化,假設我們每次讓子元件增加10,我們先來一個小案例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>子元件向父元件傳遞資料</title>
    </head>
    <body>
        <div id="app">
            <my-content :count="count" @add="handleAdd" v-bind="info"></my-content>
            父元件的count:<span>{{count}}</span>
            <button @click="handleClick">點選</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    count:1,
                    info:{
                        name:'男',
                        age:18
                    }
                },
                methods:{
                    handleAdd(count){
                        this.count=count;
                    },
                    handleClick(){
                        this.info.name='女'
                    }
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        data(){
                            return{
                                ownCount:this.count
                            }
                        },
                        props:['count','name','age'],
                        template:'<div><span>姓名:{{name}}</span><br/>子元件的count:<span>{{ownCount}}</span><button @click="handleClick">add</button></div>',
                        methods:{
                            handleClick(){
                                this.ownCount+=10;
                                this.$emit('add',this.ownCount);
                            }
                        }
                    }
                }
                
            })
            
        </script>
    </body>
</html>

結果:

 

當我們點選按鈕的時候發現父元件傳遞給子元件的姓名發生了改變,那麼我們只要改變父元件中的count的值,那麼子元件中count的值也會發生改變

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>子元件向父元件傳遞資料</title>
    </head>
    <body>
        <div id="app">
            <my-content :count="count" @add="hanldeAdd"></my-content>
            父元件中的count<span>{{count}}</span>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            let vm=new Vue({
                el:'#app',
                data:{
                    count:1
                },
                methods:{
                    hanldeAdd(count){
                        this.count+=count;
                    }
                },
                computed:{
                    
                },
                components:{
                    'myContent':{
                        data(){
                            return{
                                //ownCount=this.count;
                            }
                        },
                        props:['count'],
                        template:'<div>子元件中的count<span>{{count}}</span><button @click="handleClick">add</button></div>',
                        methods:{
                            handleClick(){
                                this.$emit('add',10)
                            }
                        }
                    }
                }
                
            })
            
        </script>
    </body>
</html>

這樣一來父子元件的簡單通訊就全部講完了,接下來為了鞏固一下父子元件之前通訊的知識,我們來做一個任務清單

總結:子元件向父元件傳遞資訊this.$emit('事件名稱',值)

(4)任務清單

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>任務清單</title>
    </head>
    <body>
        <div id="app">
            任務:<input type="text" v-model="newTask" @keyup.enter="addNew" placeholder="請輸入您要完成的任務" />
            <ul>
                <li is="todoImte" v-for="(item,index) of tasks" :title="item" @remove="removeItem(index)"></li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            Vue.component('todoImte',{
                props:['title'],
                template:"<li>{{title}}<button @click='$emit(\"remove\")'>X</button></li>"
            });
            let vm=new Vue({
                el:'#app',
                data:{
                    newTask:'',
                    tasks:['買一本書','寫一次部落格','和朋友一起吃飯']
                },
                methods:{
                    addNew(){
                        this.tasks.unshift(this.newTask);
                        this.newTask='';
                    },
                    removeItem(index){
                        if(confirm('確定要刪除嗎?')){
                            this.tasks.splice(index);
                        }
                    }
                },
                computed:{
                    
                }
                
            })
            
        </script>
    </body>
</html>

結果:

 

 

任務清單中,首先有個新增任務的框,然後通過addNew方法將任務新增到任務清單中,子元件中通過this.$emit()告訴父元件執行相應的方法,任務清單中,我們可以新增任務清單也可以刪除任務清單,新增任務清單的話,沒有涉及元件通訊,二刪除任務清單的時候,子元件通知父元件需要刪除那個任務,然後將需要刪除任務的索引傳遞過去,父元件根據傳遞過來的index進行刪除。

總結

本篇部落格主要講了三個知識點,元件的校驗,父元件向子元件傳遞資訊(通過props),子元件向父元件傳遞資訊(通過this.$emit),本篇部落格講解的內容也比較簡單,但是我認為這僅僅也還是元件的開始,下一遍部落格我們將會講解vue-cli中的元件通訊,畢竟這個才是重點,現在的元件通訊也才是入門。歡迎大家在部落格下方評論,我們一起交