vue組件詳解

使用組件的原因

提高代碼的復(fù)用性

組件的使用方法

  1. 全局注冊
Vue.component('my-component',{
        template:'<div>我是組件的內(nèi)容</div>'
    })

占內(nèi)存

  1. 局部注冊
var app = new Vue({
        el: '#app',
        data: {

        },
        components: {
            'app-component': {
                template: '<div>app-component</div>'
    }
        }
    })
  1. 由于HTML標(biāo)簽的限制,如table中只能有tr、td、tbody,要想在table中使用組件就要用到is,這樣一來,tbody在文檔中就會被組件替換掉
<table>
        <tbody is="app-component"></tbody>
</table>

我們也可以利用這個屬性來干掉其他事,比如動態(tài)組件,也就是點(diǎn)一個按鈕就切換一個組件

組件使用的奇淫巧技

  1. 必須用連字符命名,如:my-compoent
  2. template中的內(nèi)容必須要用DOM元素包裹
// 正確寫法
template: '<div>app-component</div>'

// 錯誤寫法
template: 'app-component'
  1. 組件的定義中,還可以有data,methods,computed
  2. data必須是一個方法
components: {
            'plus-component': {
                template: '<button @click="count111++">{{count111}}</button>',
                data: function () {
                    return {
                        count111: 1
                    }
                }
            }
        }

使用props傳遞數(shù)據(jù) 父親向兒子傳遞數(shù)據(jù)

  1. 在子組件上聲明屬性msg,然后在子組件處用props來接收
<div id="app">
    我是爸爸
    <child-component :msg="fatherMsg"></child-component>
</div>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            'child-component': {
                // 從父組件和本身data傳入的數(shù)據(jù)在methods、template中都可以使用
                props: ['msg'],
                data: function(){
                    return {
                        count:1
                    }
                },
                template: '<div id="child">{{msg}}</div>',
            }
        }
    })
</script>
  1. 動態(tài)向子組件傳入信息,則用v-model
<div id="app">
    我是爸爸
    <input type="text" v-model="fatherMsg">
    <child-component :msg="fatherMsg"></child-component>
</div>
<script src="../vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            count: 1,
            fatherMsg: 'hello'
        },
        methods: {
            plus: function () {
                this.count++
            }
        },
        components: {
            'child-component': {
                // 從父組件和本身data傳入的數(shù)據(jù)在methods、template中都可以使用
                props: ['msg'],
                data: function(){
                    return {
                        count:1
                    }
                },
                template: '<div id="child">{{msg}}</div>',
            }
        }
    })
</script>
  1. ==在props中定義的屬性都可以在組件內(nèi)使用,可以在template、computed、methods中使用==

單向數(shù)據(jù)流

只能父組件向子組件傳遞信息,子組件不能向父組件傳遞信息

在組件中使用從props傳來的數(shù)據(jù)可以直接用this.xxx來獲取

 'child-component': {
                props: ['msg'],
                template: '<div id="child" >{{count}}</div>',
                data:function(){
                    // 組件中的data要返回一個函數(shù)
                    return {
                        count: this.msg
                    }
                }
            }
  1. 用v-bind來綁定style屬性的時(shí)候可以使用對象語法,注意
<div :style="xxx" id="div1"></div>
computed:{
            xxx: function () {
                return {
                    //這是用到了v-bind綁定style的對象語法
                    width: this.ccc + 'px',
                    'background-color': 'red',
                    height: 10 + 'px'
                }
            }
        }

數(shù)據(jù)驗(yàn)證

在HTML中絕對不允許使用駝峰,因?yàn)镠TML會把大寫全部轉(zhuǎn)化為小寫。在props中可以用駝峰或短橫線,在template和data、this.xxx中只能使用駝峰,這是因?yàn)樵趘ue中短橫線會被誤認(rèn)為減號,會報(bào)錯。
==總結(jié):在HTML中使用短橫線,在vue中使用駝峰==

  1. 對傳入的數(shù)據(jù)進(jìn)行數(shù)據(jù)驗(yàn)證

注意props不能再返回一個數(shù)組,而是一個對象

<div id="app">
    <child-component :a="a" :b="b" :c="c" :d="d" :e="e" :f="f"></child-component>
</div>
<script src="../vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            a: 'hello',
            b: 123,
            c: true,
            d: 123,
            e:[456],
            f: 15
        },
        components: {
            'child-component': {
                props: {
                    a: String,     // 驗(yàn)證字符串,如果不是字符串頁面會照常渲染但會報(bào)錯
                    b: [String,Number], // 意思是傳入的數(shù)據(jù)是String或是Number類型
                    c: {
                        type: Boolean,
                        default: false   // 默認(rèn)值為false
                    },
                    d: {
                        type: Number,
                        required: true   // 表示d是必須要傳入的值
                    },
                    e:{
                        // 如果是數(shù)組或?qū)ο螅J(rèn)值要用函數(shù)來返回
                        type: Array,
                        default: function () {
                            return [789]
                        }
                    },
                    f:{
                        // 自定義一個驗(yàn)證函數(shù)
                        validator: function(value){
                            return value>10
                        }
                    }
                 },
                template: '<div id="child" >{{a}}--{}--{{c}}--{u0z1t8os}--{{e}}--{{f}}</div>',
                data:function(){
                    // 組件中的data要返回一個函數(shù)
                    return {
                        count: this.msg
                    }
                }
            }
        }
    })
</script>

組件之間的通信

子組件給父組件傳遞信息

實(shí)現(xiàn)一個功能,點(diǎn)擊子組件的按鈕,改變父組件的數(shù)據(jù)

<div id="app">
    我的賬戶余額為:{{count}}
    <child-component @xxx="changeCount"></child-component>
</div>
<script src="../vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            count: 2000
        },
        methods: {
            changeCount: function (value) {
                this.count = value
            }
        },
        components: {
            'child-component': {
                // 注意這里template一定要有DOM元素包裹
                template: `<div>
                <button @click="handleIncrease">+1000</button>
                <button @click="handleReduce">-1000</button>
                </div>
                `,
                data:function(){
                    return {
                        count: 2000
                    }
                },
                methods: {
                    handleIncrease: function () {
                        this.count += 1000    // 這里的this.count是組件里面的count
                        this.$emit('xxx',this.count)   // emit表示向父組件通信,第一個參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個
                    },
                    handleReduce: function () {
                        this.count -= 1000
                        this.$emit('xxx',this.count)
                    }
                }
            }
        }
    })
</script>

子組件向父組件傳遞信息的步驟:

  1. 在父組件里寫入自定義事件名,事件名后面跟著的是要執(zhí)行的方法
  2. 子組件通過$emit向父組件傳遞信息,第一個參數(shù)是自定義的事件名,后面是要傳遞的參數(shù),可以接無限個

在組件中使用v-model

v-model其實(shí)也是一個語法糖:

  1. 它等于先用v-bind綁定一個值
  2. 監(jiān)聽v-on了一個input事件
    上述代碼又可以簡化成
<div id="app">
    我的賬戶余額為:{{total}}
    <child-component v-model="total"></child-component>
</div>
<script src="../vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            total: 2000
        },
        components: {
            'child-component': {
                template: `<div>
                <button @click="handleIncrease">+1000</button>
                <button @click="handleReduce">-1000</button>
                </div>
                `,
                data:function(){
                    return {
                        count: 2000
                    }
                },
                methods: {
                    handleIncrease: function () {
                        this.count += 1000    // 這里的this.count是組件里面的count
                        this.$emit('input',this.count)   // emit表示向父組件通信,第一個參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個
                    },
                    handleReduce: function () {
                        this.count -= 1000
                        this.$emit('input',this.count)
                    }
                }
            }
        }
    })
</script>

非父組件之間的通信

非父組件之間的通信需要一個bus作為中介
在父組件的data內(nèi)新建一個bus: new Vue()對象。
然后在A組件內(nèi)用this.$parent.bus.$emit('事件名',參數(shù))

Vue.component('a-component',{
        template: `
                <div>
                    <input type="text" v-model="text">
                </div>`,
        data:function () {
            return {
                text: '我是A組件'
            }
        },
        watch:{
            //watch的用法,key代表要監(jiān)聽的數(shù)據(jù),后面接操作
            text: function () {
                this.$root.bus.$emit('xxx',this.text)
            }
        }
    })

在B組件內(nèi),在對應(yīng)的鉤子事件中用this.$parent.bus.$on('事件名',參數(shù))

 Vue.component('b-component',{
        template: '<div>我是b組件---{{textb}}</div>',
        data:function () {
            return {
                textb: 'bbbbb'
            }
        },
        created: function () {
            var _this = this
            this.$root.bus.$on('xxx',function (value) {
                // alert('created')
                _this.textb = value
            })
        }
    })
  1. 修改父組件的數(shù)據(jù),父鏈
this.$parent.xxxx
  1. 修改兒子組件的數(shù)據(jù),子鏈
    在每個兒子組件上加上ref屬性
    <a-component ref="a"></a-component>
    <b-component ref="b"></b-component>
    <c-component ref="c"></c-component>

然后在父組件上使用:

this.$refs.a.count = 'aaa' // 修改a組件的數(shù)據(jù)

使用slot分發(fā)內(nèi)容

編譯的作用域

<div id="app">

    <child-component v-show="bool">
            {{message}}
    </child-component>
</div>

message屬于父組件的作用域
父組件模板內(nèi)的內(nèi)容在父組件內(nèi)編譯
子組件模板內(nèi)的內(nèi)容在子組件內(nèi)編譯

slot(插槽)的用法和作用

在下面這段代碼中

    <child-component v-show="bool">
            {{message}}
    </child-component>

message其實(shí)是渲染不出來的,盡管message的作用域在父組件,但我們想讓它子組件內(nèi)的template中渲染出來,這時(shí)我們就要使用到了slot功能。

slot的作用是混合父組件的內(nèi)容和子組件的模板,從而彌補(bǔ)視圖的不足

<div id="app">
    <child-component >
            <p>hello world</p>
    </child-component>
</div>
......
Vue.component('child-component',{
        template: `
         <div style="border: 1px solid red;">
                <slot>
                        如果父組件沒有內(nèi)容,我就是子組件的默認(rèn)內(nèi)容
                </slot>
         </div>

具名插槽

在要插入數(shù)據(jù)的標(biāo)簽使用slot屬性,在子組件的template處使用slot標(biāo)簽,并且寫上對應(yīng)的name

<child-component >
            <h1 slot="header">我是標(biāo)題</h1>
            <p>hello world</p>
</child-component>
... ...
 Vue.component('child-component',{
        template: `
         <div style="border: 1px solid red;">
             <div style="color: red;">
             <slot name="header">
                    這里是header的默認(rèn)內(nèi)容
                </slot>
                </div>

                <slot>
                        如果父組件沒有內(nèi)容,我就是子組件的默認(rèn)內(nèi)容
                </slot>
         </div>
        `,

作用域插槽

作用域插槽是一個特殊的插槽,可以從子組件的插槽中獲取數(shù)據(jù)。使用一個可以復(fù)用的模板來替換已經(jīng)渲染的元素
用法:先在子組件的slot標(biāo)簽上name屬性和自定義的屬性

Vue.component('child-component',{
        template: `
         <div style="border: 1px solid red;">
             <div style="color: red;">
                <slot name="header" text="我是子組件的數(shù)據(jù)">
                    這里是header的默認(rèn)內(nèi)容
                </slot>
              </div>
         </div>
        `,

然后在父組件上,用slot對應(yīng)其中的name,用slot-scope對應(yīng)的自定義名字來獲取從子組件傳來的數(shù)據(jù)

<child-component >
        <template slot="header" slot-scope="props">
            {{props.text}}
        </template>
    </child-component>

現(xiàn)在已經(jīng)可以不用template,可以直接使用標(biāo)簽如<p>

在子組件中訪問自己的slot

通過this.$slots.(NAME)來訪問

<div id="app">
    <child-component >
        <h1 slot="header">我是父組件的內(nèi)容</h1>
    </child-component>
</div>
Vue.component('child-component',{
        template: `
         <div style="border: 1px solid red;">
             <div style="color: red;">
             <slot name="header">
                    這里是header的默認(rèn)內(nèi)容
               </slot>
               </div>
         </div>
        `,
        data:function () {
            return {
                message: '我是子組件的內(nèi)容',
                bool: true
            }
        },
        mounted:function () {
            var header = this.$slots.header
            console.log(header)
            console.log(header[0].elm.innerText)
        }
    })

組件的高級用法-動態(tài)組件

所謂的動態(tài)組件就是通過is屬性來動態(tài)切換組件

<div id="app">
    <component-a :is="thisView"></component-a>
    <button @click="changeToA">第一句</button>
    <button @click="changeToB">第二句</button>
    <button @click="changeToC">第三句</button>
    <button @click="changeToD">第四句</button>
</div>
<script src="../vue.js"></script>
<script>
    Vue.component('componentA',{
       template: `<div>離離原上草</div>`
    })
    Vue.component('componentB',{
       template: `<div>一歲一枯榮</div>`
    })
    Vue.component('componentC',{
       template: `<div>野火燒不盡</div>`
    })
    Vue.component('componentD',{
       template: `<div>春風(fēng)吹又生</div>`
    })
    var app = new Vue({
        el: '#app',
        data: {
            thisView: 'componentA'
        },
        methods :{
            changeToA: function () {
                this.thisView = 'componentA'
            },
            changeToB: function () {
                this.thisView = 'componentB'
            },
            changeToC: function () {
                this.thisView = 'componentC'
            },
            changeToD: function () {
                this.thisView = 'componentD'
            }
        }
    })
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容