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中只能有trtd典唇、tbody偏化,要想在table中使用組件就要用到is,這樣一來毙石,tbody在文檔中就會(huì)被組件替換掉
<table>
        <tbody is="app-component"></tbody>
</table>

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

組件使用的奇淫巧技

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

// 錯(cuò)誤寫法
template: 'app-component'
  1. 組件的定義中,還可以有data易阳,methods附较,computed
  2. data必須是一個(gè)方法
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. 動(dòng)態(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要返回一個(gè)函數(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會(huì)把大寫全部轉(zhuǎn)化為小寫劝堪。在props中可以用駝峰或短橫線冀自,在template和data揉稚、this.xxx中只能使用駝峰,這是因?yàn)樵趘ue中短橫線會(huì)被誤認(rèn)為減號凡纳,會(huì)報(bào)錯(cuò)窃植。
==總結(jié):在HTML中使用短橫線,在vue中使用駝峰==

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

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

<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)證字符串巷怜,如果不是字符串頁面會(huì)照常渲染但會(huì)報(bào)錯(cuò)
                    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:{
                        // 自定義一個(gè)驗(yàn)證函數(shù)
                        validator: function(value){
                            return value>10
                        }
                    }
                 },
                template: '<div id="child" >{{a}}--{暴氏}--{{c}}--{7llww81}--{{e}}--{{f}}</div>',
                data:function(){
                    // 組件中的data要返回一個(gè)函數(shù)
                    return {
                        count: this.msg
                    }
                }
            }
        }
    })
</script>

組件之間的通信

子組件給父組件傳遞信息

實(shí)現(xiàn)一個(gè)功能延塑,點(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表示向父組件通信,第一個(gè)參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個(gè)
                    },
                    handleReduce: function () {
                        this.count -= 1000
                        this.$emit('xxx',this.count)
                    }
                }
            }
        }
    })
</script>

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

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

在組件中使用v-model

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

  1. 它等于先用v-bind綁定一個(gè)值
  2. 監(jiān)聽v-on了一個(gè)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表示向父組件通信,第一個(gè)參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個(gè)
                    },
                    handleReduce: function () {
                        this.count -= 1000
                        this.$emit('input',this.count)
                    }
                }
            }
        }
    })
</script>

非父組件之間的通信

非父組件之間的通信需要一個(gè)bus作為中介
在父組件的data內(nèi)新建一個(gè)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ù),子鏈
    在每個(gè)兒子組件上加上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>
        `,

作用域插槽

作用域插槽是一個(gè)特殊的插槽舞骆,可以從子組件的插槽中獲取數(shù)據(jù)灵嫌。使用一個(gè)可以復(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)
        }
    })

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

所謂的動(dòng)態(tài)組件就是通過is屬性來動(dòng)態(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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赂蠢,隨后出現(xiàn)的幾起案子绪穆,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玖院,死亡現(xiàn)場離奇詭異菠红,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)难菌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門试溯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人郊酒,你說我怎么就攤上這事遇绞。” “怎么了燎窘?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵摹闽,是天一觀的道長。 經(jīng)常有香客問我褐健,道長付鹿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任蚜迅,我火速辦了婚禮舵匾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谁不。我一直安慰自己纽匙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布拍谐。 她就那樣靜靜地躺著,像睡著了一般馏段。 火紅的嫁衣襯著肌膚如雪轩拨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天院喜,我揣著相機(jī)與錄音亡蓉,去河邊找鬼。 笑死喷舀,一個(gè)胖子當(dāng)著我的面吹牛砍濒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硫麻,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼爸邢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拿愧?” 一聲冷哼從身側(cè)響起杠河,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后券敌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唾戚,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年待诅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叹坦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卑雁,死狀恐怖募书,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情序厉,我是刑警寧澤锐膜,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站弛房,受9級特大地震影響道盏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜文捶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一荷逞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粹排,春花似錦种远、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至射富,卻和暖如春膝迎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胰耗。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工限次, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柴灯。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓卖漫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赠群。 傳聞我的和親對象是個(gè)殘疾皇子羊始,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355