Vue組件基礎詳解

Vue組件

一.概念

在vue裏,一個組件的本質上是一個擁有預定義選項的一個Vue實例

二.組件的使用

  • 定義(註冊)組件
  • 調用(使用)組件

將組件就看成是一個函數

1.組件的註冊

  • 全局組件註冊

    當前Vue項目中,任何組件中都可以去使用

        /**
         * componentName 組件的名字
         * componentOptions 組件的選項配置
        */
        Vue.component(componentName,componentOptions);

    	//com1 全局組件
        Vue.component('com1', {
            template: `<div>
                            我是hello組件
                       </div>`
        });
  • 局部組件註冊

    在哪個組件中註冊的,就只能使用在哪個組件中

 		
 		 /**
         * 局部組件註冊
         * 在組件的components配置選項中去定義
         * new Vue 構造函數 ,生成的實例,一般我們叫它根組件
         * componentName1 局部組件名字
         * componentOptions1 局部組件對應的選項
         * */
		new Vue({
            components:{
                componentName1:componentOptions1
                componentName2:componentOptions2
            }
        });

在組件的components配置選項中去定義

new Vue,生成的實例,一般我們叫它根組件

compontentOptions就是一個對象,裏面有配置與new Vue時類似,但有一些例外:

  1. 組件沒有el選項,因爲後續調用組件在哪裏,這個組件的掛載點就是哪裏
  2. 必須有template或者render選項,用來規定組件的模版內容
  3. data選項必須是一個函數返回對象的形式

2.組件的調用

將組件名當做自定義的html標籤使用即可

		//全局組件註冊   		
		Vue.component('hello', {
            // 注意:必須有template和render選項,用來規定組件的模版內容
            template: `<div>我是全局組件hello </div>`
        });

		 //根組件
        var vm = new Vue({
            el: '#app'
        });


		//調用組件 這個div可以看成是根組件的template
		<div id="app">
             <hello></hello>
        </div>

調用時,必須要在根組件裏面,我這裏的根組件的掛載點是 #app, 這個hello 組件放在了根組件的div中,實際上就是把hello組件的template渲染到了根組件上,那麼這裏就是 hello組件是 根組件Root的子組件

   		//com1 全局組件
        Vue.component('com1', {
            // 這裏,com3是不能用的,會報錯,因爲com3是com2的子組件,只能在com2中使用
            template: `<div>
                            我是hello組件
                       </div>`
        });

        //com2和com1是全局組件,任何組件都可以使用
        Vue.component('com2', {
            //com3和com4只能在com2中使用,局部組件,只屬於com3和com4的子組件
            template:
                `
                <div>
                    我是com2組件
                    <com3></com3>
                </div>`
            ,
            components: {
                'com3': {
                    template: `<div>我是com3組件,只能在com2中使用</div>`
                },
                'com4': {
                    template: `<div>我是com4組件,只能在com2中使用</div>`
                }
            }
        });

        //根組件
        var vm = new Vue({
            el: '#app'
        });

3.組件的複用

	<div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
 		<button-counter></button-counter>
        <button-counter></button-counter>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script>
        // 定義一個名爲 button-counter 的新組件
        Vue.component('button-counter', {
            data: function () {
                return {
                    count: 0
                }
            },
            template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
        })

        var vm = new Vue({
            el: '#app'
        });
    </script>

定義的全局組件可以在根組件下任意使用多個,進行組件的複用

注意

data必須是一個函數

爲什麼組件的data選項要寫成函數形式呢?

原因是組件是可以進行復用的,如果data直接寫成對象,那麼複用的時候,會造成數據污染(多個實例對象共用一個變量)

當我們點擊上面按鈕的時候,因爲使用了函數形式的返回data數據,所以每個組件都會各自獨立維護它的變量count,y因爲每用一個組件,就會有一個新的實例被創建.

4.組件名

組件名不能是現有的html標籤名,也不能是之前已經註冊過的組件(實際上是可以,只不過會覆蓋之前的)

        Vue.component('nav', {
            template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
        })

        var vm = new Vue({
            el: '#app'
        });

nav是html5的標籤名,這裏不能使用,會報錯.也不能是 a,button,div之類,總之不能使用現有的html標籤名.

組件名的規則:

可以使用短橫線寫法:

  • hello-world

可以使用駝峯寫法

  • HelloWorld

調用組件時,需要使用短橫線寫法 上述兩種,都可以使用hello-world

但是也有例外,以下三種情況可以無視這種規則

1.寫在template選項中

		//寫在template選項中,可以無視這種規則       
		Vue.component('com1', {
            template: 
           '<div>
               COM1
              <HelloWorld></HelloWorld>
           </div>'
        })

        Vue.component('HelloWorld', {
            template: '<div>HelloWorld</div>'
        })

		//這裏又template選項,會覆蓋頁面上的#app
		//駝峯命名的組件,這裏使用駝峯和短橫線都可以使用
        var vm = new Vue({
            el: '#app',
            template:
            `<div id='app'>
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
             </div>               `
        });

2.寫在裏面的

我們寫了組件這麼多代碼,特別是在寫template選項中的寫模版內容代碼時,發現非常的不方便,沒有語法高亮,也沒有代碼提示,這時可以將模版內容,放置在一個script標籤裏面

要注意:

  • 需要設置script 的type屬性爲text/x-template
  • 給這個script設置一個id

調用時,直接使用template:’#xxxx’即可

    <script id="appTemplate" type="text/x-template">
        <div id='app'>
            <HelloWorld></HelloWorld> 
            <hello-world></hello-world>
            <com1></com1>
         </div> 
    </script>
    <script>

        Vue.component('com1', {
            template: '<div>COM1<HelloWorld></HelloWorld></div>'
        })

        Vue.component('HelloWorld', {
            template: '<div>HelloWorld</div>'
        })

		//調用模版內容
        var vm = new Vue({
            template: `#appTemplate`
        });
    </script>

這種情況時,使用template選項中調用組件,可以無視上面的組件調用規則

3.vue後綴的單文件組件時

5.組件的注意事項

  1. 全局組件註冊時,必須要放置在new Vue之前

            Vue.component('com1', {
             template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
            })
    
    		//上面定義的全局組件,必須寫在new Vue之前,否則會報錯
            var vm = new Vue({
                el: '#app'
            });
    
    
    		//這是錯誤的寫法,報錯
            var vm = new Vue({
                el: '#app'
            });
    
     		Vue.component('com1', {
             template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
            })
    

    2.組件的template模版內容,必須只能有一個根元素.

     <script id="appTemplate" type="text/x-template">
            //調用組件時,必須只能有一個根組件
            <div id='app'>
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
             </div> 
        </script>
    
        <script id="appTemplate" type="text/x-template">
         		//這種情況會報錯,因爲必須只能有一個根元素
                <HelloWorld></HelloWorld> 
                <hello-world></hello-world>
                <com1></com1>
        </script>
    

三.Props選項

將組件看成是一個函數,props就是這個函數接收到的參數集合

prop就是props中具體的一個參數

//這樣理解props選項

//定義一個函數,接收props形參
function hello(props){
 
}

//調用hello函數 傳遞一個對象,給到參數
hello({name:liuqiao,age:18,sex:'男'});

//props指的就是這些個參數集合
props=>{name:liuqiao,age:18,sex:'男'}
name =>prop 這都是其中的一個prop
age  =>prop
sex  =>prop
1.props命名規則

HTML 中的 屬性 名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲小寫字符,

如果是在html中寫prop時,如果props設置時是使用駝峯命名法,則需要改用短橫線

```js
   Vue.component('hello', {
        props: ['postTitle'],
        template: '<div>  我的姓名是:{{ postTitle }} </div>'
    })

	<div id="app">
    	<hello post-title='liuqiao'></hello>
	</div>
```

注意,這裏的props命名規則與組件名命名的規則一樣,也有三種情況可以無視這種規則

  • 寫在template選項中
  • 寫在裏面的
  • vue後綴的單文件組件時

官網的說明是:使用字符串模板,那麼這個限制就不存在了。

2.設置props

組件定義時,如何設置形參?就是設置props選項

最簡單的方式就是:寫成數組形式,數組中每一項就是一個prop

定義的每一個prop,可以直接通過實例對象去訪問到,就像訪問data數據和computed數據一樣

 	Vue.component('hello', {
            //props選項:寫成數組形式,數組中每一項就是一個prop
            props: ['name', 'age', 'sex'],
        
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年齡:{{age}}
                    <button @click="hi('abc')">點我</button>
                </div>
               
            `,
            methods:{
                hi(a){
                    console.log(this.name+this.age+a);
                    console.log(this.sex);//不傳遞sex參數時,打印結果是undefined
                }
            }
        })

3.傳遞參數

調用組件時,在組件上的標籤上寫屬性即可

注意:調用時:不傳遞參數是沒有問題的

 		//調用模版內容
        var vm = new Vue({
            el:'#app',
            template: `
             <div id="app">
                <hello name='liuqiao' age='19'></hello>
             </div>
            `
        });

如:

​ hello組件上name就是liuqiao

​ hello組件上age就是19

​ hello組件上sex沒有傳遞,是undefined

4.props的默認值

如果調用組件時,沒有傳遞某個prop下來,那麼組織中的這個prop的值是undefined

設置props默認值:也就是調用時如果沒有傳遞某prop,那我就使用默認值

類似函數中es6的設置默認值

es6中函數設置默認值

funciton hello(name='liuqiao'){
    
}
hello();

在組件中給props設置默認值>關鍵點是:將數組格式的props改成對象格式

 	  props:{
            key1:{
                type:String,
                default:'liuqiao'
            },
            key2:{
                type:Number,
                default:18
            }
        }

key1,key2就是props的名字
type:是接收這個參數的數據類型
default:是這個prop的默認值

  	Vue.component('hello', {
            props: {
                'name':{
                    type:String,
                    default:'zhangsan'
                },
                'age':{
                    type:Number,
                    default:18
                }
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年齡:{{age}}
                </div>
				`
        })

        var vm = new Vue({
            el: '#app',
            template: `
             <div id="app">
                <hello></hello>
             </div>
            `
        });
5.props的校驗

如果調用組件時,我希望可以保證你傳過來的prop是有效的,所以需要設置 正確的數據類型

比如我在組件中規定,你需要傳遞string類型的參數,你就必須傳遞string類型,否則報錯

這叫做props的類型校驗

官網的例子是這樣的:

Vue.component('my-component', {
  props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
    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 ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

我這邊自己也就是總結了4中寫法:

​ 1.直接寫需要的類型

​ 2.寫成對象形式

​ 3.寫成數組形式(意思是string和number都可以接收)

 		props:{
            key:String  //第一種
            key:{
                type:String //第二種
            }
            key:[String,Number],//第三種
                
            //第四種,自定義驗證函數
            key:{
                abc:function(){
                    
                }
            }
        }

其中type類型可以有以下幾種:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

另外,傳遞prop的時候,默認都是字符串格式,需要轉化的話,只需加上 v-bind 即可

  Vue.component('hello', {
            props: {
                'name':String,
                'age':{
                    type:Number
                },
                'sex':[String,Number]
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年齡:{{age}}
                </div>
            `
        })


        //調用模版內容
        var vm = new Vue({
            el: '#app',
            template: `
             <div id="app">
                <hello name='liuqiao'></hello>
                <hello :age='18'></hello>
                <hello sex='男'></hello>
             </div>
            `
        });

v-bind可以省略,直接使用冒號 : 即可

6.傳遞動態的props

傳入一個對象所有需要的屬性

  		Vue.component('hello', {
            props: {
                name: String,
                age: Number
            },
            template: `
                <div> 
                    我的姓名是:{{ name }},我的年齡:{{age}}
                </div>
            `
        })


        //調用模版內容
        var vm = new Vue({
            el: '#app',
            data: {
                userinfo: {
                    name: 'liuqiao',
                    age: 28
                }
            },
            template: `<hello v-bind='userinfo'></hello>`
        });

調用組件時,直接屬性上寫v-bind=

<hello v-bind='userinfo'></hello>

實際上,這種寫法等價於

<hello v-bind:name='userinfo.name' v-bind:age='username.age'></hello>
7.Props單向數據流

單向數據流:props傳遞參數時,都是單向下行綁定的.父組件的prop會向下傳遞到子組件,反過來不行

所有的prop都使得其父子prop之間形成了一個單向下行綁定.父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態,從而導致你的應用的數據流向難以理解。

額外的,每次父級組件發生變更時,子組件中所有的 prop 都將會刷新爲最新的值。這意味着你應該在一個子組件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制檯中發出警告。

上面一段是官網的原話.總結一句話就是:不要去直接修改prop傳過來的數據

一般有兩種情況改變prop

  • 父組件傳過來的初始值 通過props傳過來的,子組件想作爲自己本地存儲

    props:{
        msg:{
            type:String,
            required:true
        }
    },
    data(){
        return{
            msgInfo:this.msg;
        }
    }
    

    這種方式,就是在本地聲明一個屬性,然後初始化去接收,作爲本地存儲,就不會修改prop了

  • 父組件傳過來的初始值,通過props傳過來,然後需要自己做轉換

    props:{
        msg:{
            type:String,
            required:true
        }
    },
    computed:{
        newMsg:function(){
            return this.msg.trim().toLowerCase()
        }
    }
    

    這種方式,就是通過一個計算屬性去處理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章