vue組件


關(guān)于vue組件的總結(jié)

注冊組件

vue中組件的注冊分為兩種:

  • 全局注冊
  • 局部注冊

全局注冊

  • 全局注冊的組件在任何vue實(shí)例中都能使用
  • 調(diào)用vue的component方法就可以全局注冊組件
  • component方法接收兩個(gè)參數(shù):
    • 參數(shù)一:組件名
    • 參數(shù)二:對象肛真,對象中包含了組件模板钾唬,data椭迎,methods等屬性焙矛,與vue實(shí)例相同
 Vue.component('g-div',{
    template: `<div>這是一個(gè)自定義組件</div>`,
    data () {
      return {
        message: 'hello world'
      }
    }
  })

上面代碼定義了一個(gè)名為g-div的自定義組件炼蹦,然后可以在DOM元素中的vue實(shí)例中使用它了

<div id="app">
    <g-div></g-div>
</div>

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

局部注冊

  • 局部注冊只能在vue實(shí)例中進(jìn)行
  • 局部注冊的組件只有它所在的vue實(shí)例可以使用
  • 在vue實(shí)例中定義component屬性就可以進(jìn)行局部注冊
let app = new Vue({
    el: '#app',
    data: {
    },
    components: {
      'my-component': {
        template: `<div>這是局部注冊的組件逮壁,只能在當(dāng)前Vue實(shí)例中使用</div>`,
      }
    }
  })

ps:組件的模板中只允許有一個(gè)根元素,所有的元素都必須由一個(gè)元素包裹徐矩,否則編譯時(shí)會(huì)報(bào)錯(cuò)


組件中的data

組件中的data必須是一個(gè)函數(shù)滞时,這個(gè)函數(shù)返回一個(gè)對象,對象里面就是你所寫的數(shù)據(jù)B说啤F夯!

為什么組件中的data必須是一個(gè)函數(shù)呢鳞骤?
因?yàn)樵陧撁嬷锌赡軙?huì)多次復(fù)用這個(gè)組件窒百,如果data是一個(gè)對象,那么所有組件共享這個(gè)對象豫尽,任一組件的data發(fā)生變化便會(huì)影響到其他組件篙梢。

若組件中的data是一個(gè)返回對象的函數(shù),那么每次使用組件時(shí)便會(huì)創(chuàng)建一個(gè)新的對象美旧,達(dá)到每個(gè)組件對應(yīng)一個(gè)對象庭猩,不會(huì)產(chǎn)生因數(shù)據(jù)共享而衍生的bug。


組件受限

在某些情況下我們無法正常的使用組件陈症,比如當(dāng)組件的父元素的ul蔼水、table時(shí),我們無法正常使用組件录肯,因?yàn)檫@些元素的內(nèi)部只能寫入特定的子元素趴腋,比如table中只允許存在tbodytd等子元素论咏。

可我就是想在這些元素內(nèi)部使用組件怎么辦优炬?
答:使用is屬性

<table>
    <tbody is="my-component"></tbody>
</table>

父組件與子組件的溝通:props

在很多場景下,我們需要父組件向子組件傳遞自身的數(shù)據(jù)厅贪,這個(gè)時(shí)候我們需要在子組件中定義props屬性來接收數(shù)據(jù)蠢护。
props傳遞數(shù)據(jù)是單向的,只能由父組件向子組件傳遞數(shù)據(jù)养涮。

<div id="app">
    <g-div :parent-message="parentMessage"><g-div>
</div>

<script>
Vue.component('g-div',{
    template: `<div>{{parentMessage}}</div>`,
    props: ['parentMessage']    //已經(jīng)得到了數(shù)據(jù)葵硕,可以直接使用
})
new Vue({
    el: '#app',
    data:{
        parentMessage: '我是父組件傳遞的數(shù)據(jù)'
    }
})
</script>

我們也可以將接收到的數(shù)據(jù)保存到子組件的data中眉抬。

Vue.component('g-div',{
    template: `<div>{{parentMessage}}</div>`,
    props: ['parentMessage'],
    data(){
        return {
            childMessage:this.parentMessage     //可以通過this.xxx來獲取接收到的數(shù)據(jù)
        }
    }
})

如果props作為需要被轉(zhuǎn)變的原始值傳入,這種情況下我們可以使用計(jì)算屬性

<div id="app">
  <input type="text" v-model="width">
  <g-div :width="width"></g-div>
</div>

<script>
Vue.component('g-div',{
  props:['width'],
  template: `<div :style="style">我的寬度是{{width}}px</div>`,
  data(){
    return{

    }
  },
  computed:{
    style(){
      return {
        width: this.width + 'px',
        background: 'red',
        height: '50px'
      }
    }
  }
})
new Vue({
  el: '#app',
  data:{
    width: 0
  }
})
</script>

大小寫的問題

在定義的組件懈凹,組件名若使用駝峰命名蜀变,在html中要使用短橫線命名。

<div id="app">
    <my-div></my-div>
    <!--如果使用<myDiv></myDiv>會(huì)報(bào)錯(cuò)-->
</div>

<script>
Vue.component('myDiv',{
  template:`<div>我是一個(gè)組件</div>`
})
new Vue({
  el: '#app'
})
</script>
  
 

在組件中介评,父組件給子組件傳遞數(shù)據(jù)必須使用短橫線库北,在template中使用文本插值的形式時(shí),只能使用駝峰们陆,其他書寫方式可能會(huì)產(chǎn)生錯(cuò)誤寒瓦。

在組件的data中,若是使用this.xxx接收數(shù)據(jù)坪仇,必須使用駝峰命名孵构,不能使用短橫線命名。


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

props可以驗(yàn)證傳遞進(jìn)來的數(shù)據(jù)類型

<div id="app">
    <my-component :a="a" :b="b"></my-component>
</div>

<script>
Vue.component('my-component',{
  props:{
    a: Number,
    //如果數(shù)據(jù)類型不相同烟很,頁面任然會(huì)渲染,同時(shí)控制臺會(huì)報(bào)錯(cuò)
    b: [String,Number],
    c: {
        type: [Boolean,Number,String,Array],
        required: true,     //指定為必傳蜡镶,不傳會(huì)報(bào)錯(cuò)
    },
    d: {
      type: String,
      default: 'hello vue'      //指定默認(rèn)值
    }
  },
  template:`<div>{{a}} {雾袱} {{c}} {lx8wolq}</div>`
})

new Vue({
  el: '#app',
  data:{
    a: 1,
    b: '123',
    c: 666,
    d: 'zink'
  }
})
</script>

當(dāng)你需要驗(yàn)證數(shù)據(jù)類型時(shí),props必須是對象官还。


自定義事件--子組件給父組件傳遞數(shù)據(jù)

使用v-on除了監(jiān)聽DOM事件外芹橡,還可以用于組件之間的自定義事件,
JS的設(shè)計(jì)模式——觀察者模式望伦,dispatchEventaddEventListentr這兩個(gè)方法林说,前者用于觸發(fā)事件,后者用于添加事件監(jiān)聽屯伞,vue組件也有與之類似的模式腿箩,子組件用$emit來觸發(fā)事件,父組件用$on來監(jiān)聽子組件事件劣摇。

<div id="app">
      當(dāng)前余額為:{{balance}}
      <son-component :sum="balance" @change="changeBalance"></son-component>
</div>

<script>
Vue.component('son-component',{
  props: ['sum'],
  template:`<div>
              <button @click="addNum">+1000</button>
              <button @click="reduceNum">-1000</button>
            </div>`,
  data(){
    return {
      number: this.sum
    }
  },
  methods:{
    addNum(){
      this.number += 1000
      this.$emit('change',this.number)
    },
    reduceNum(){
      this.number -= 1000
      this.$emit('change',this.number)
    }
  }
})

new Vue({
  el: '#app',
  data:{
    balance: 2000
  },
  methods:{
    changeBalance(value){
      this.balance = value
    }
  }
})
</script>

第一步:自定義事件
第二步:在子組件中用$emit觸發(fā)事件珠移,第一個(gè)參數(shù)為事件名,后面的參數(shù)為要傳遞的數(shù)據(jù)末融。
第三部:在父組件中監(jiān)聽這個(gè)事件


子組件間的通信

子組件之間的通信需要在根組件中定義一個(gè)新的vue實(shí)例作為我們的事件承載中心。

<div id="app">
     <a-component></a-component>
     <b-component></b-component>
</div>

<script>
Vue.component('a-component',{
  template: `
<button @click="delivery">點(diǎn)擊我向B中傳遞數(shù)據(jù)</button>
`,
  data(){
    return{
      msg: '這是來自A組件的數(shù)據(jù)'
    }
  },
  methods:{
    delivery(){
      this.$root.bus.$emit('test',this.msg)
    }
  }
})

Vue.component('b-component',{
  template:`<div>我是B組件,這是我接收到的數(shù)據(jù):{{msg}}</div>`,
  data(){
    return {
      msg: undefined
    }
  },
  created:function(){
    //這里要使用箭頭函數(shù)勾习,否則this指向的是bus,箭頭函數(shù)的this繼承作用域鏈父級
    this.$root.bus.$on('test',(value)=>{
      console.log(this)
      this.msg = value
    })
  }
})

let app = new Vue({
  el: '#app',
  data:{
    bus: new Vue()
  }
})
</script>

箭頭函數(shù)沒有this巧婶,只會(huì)從自己的作用域鏈的上一層繼承this

父鏈:this.$parent涂乌,在子組件中使用,可以獲取到父組件的內(nèi)容

<div id="app">
      <son-component></son-component>---{{msg}}
</div>

<script>
Vue.component('son-component',{
  template: `
<button @click="change">點(diǎn)擊我修改數(shù)據(jù)</button>
`,
  methods:{
    change(){
      this.$parent.msg = "數(shù)據(jù)已經(jīng)修改"
    }
  }
})

let app = new Vue({
  el: '#app',
  data:{
    msg: '數(shù)據(jù)還未修改'
  }
})
</script>

子鏈:this.$refs

<div id="app">
  <button @click="getSon">點(diǎn)擊我獲取子組件的內(nèi)容</button>---{{msg}}
  <a-component ref="a"></a-component>
  <b-component ref="b"></b-component>
  <c-component ref="c"></c-component>
</div>

<script>
Vue.component('a-component',{
  template: `
<div></div>
`,
  data(){
    return{
      msg:'我是子組件a的內(nèi)容'
    }
  }
})
Vue.component('b-component',{
  template: `
<div></div>
`,
  data(){
    return{
      msg:'我是子組件b的內(nèi)容'
    }
  }
})
Vue.component('c-component',{
  template: `
<div></div>
`,
  data(){
    return{
      msg:'我是子組件c的內(nèi)容'
    }
  }
})

let app = new Vue({
  el: '#app',
  data:{
    msg: '數(shù)據(jù)還未修改'
  },
  methods:{
    getSon(){
      console.log(this.$refs)
      this.msg = this.$refs.c.msg
      
    }
  }
})
</script>

插槽

為了讓組件可以組合骂倘,我們需要一種方式來混和父組件的內(nèi)容與子組件自己的模板巴席。這個(gè)過程被稱為內(nèi)容分發(fā)历涝,vue.js實(shí)現(xiàn)了一個(gè)內(nèi)容分發(fā)API,使用slot元素作為原始內(nèi)容的插槽漾唉。

首先我們需要明確內(nèi)容在那個(gè)作用域里編譯荧库,假設(shè)模板為

<div id="app">
  <my-component>
    {{msg}}
  </my-component>
</div>

msg是綁定到父組件的數(shù)據(jù)還是綁定到子組件的數(shù)據(jù)?答案是父組件赵刑。組件作用域簡單地說就是:

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

讓我們再回到上面的代碼分衫,所以此時(shí)app內(nèi)的所有內(nèi)容,都在父組件作用域內(nèi)

插槽的用法
插槽的作用:父組件的內(nèi)容和子組件相混合般此,從而彌補(bǔ)視圖的不足蚪战,說明白了就是子組件內(nèi)可以寫入父組件的內(nèi)容。

<div id="app">
  <my-component>
    {{msg}}
  </my-component>
</div>

<script>
Vue.component('my-component',{
  template:`<div>
<slot>如果父組件沒有插入內(nèi)容铐懊,我會(huì)默認(rèn)出現(xiàn)</slot>
</div>`,
  data(){
    return{
      msg: '我是子組件的內(nèi)容'
    }
  }
})

new Vue({
  el:'#app',
  data:{
    msg:"我是父組件的內(nèi)容"
  }
})
</script>

具名插槽
slot標(biāo)簽上添加name屬性邀桑,在插入的標(biāo)簽上添加slot="xxx"

<div id="app">
  <my-component>
    <h2 slot="header">我是標(biāo)題</h2>
    <p slot="main">我是正文</p>
    <p slot="main">正文第二部分</p>
    <span slot="footer">我是底部信息</span>
  </my-component>
</div>

<script>
Vue.component('my-component',{
  template:`<div>
<header>
  <slot name="header"></slot>
</header>
<main>
  <slot name="main"></slot>
</main>
<footer>
  <slot name="footer"></slot>
</footer>
</div>`,
  data(){
    return{
      msg: '我是子組件的內(nèi)容'
    }
  }
})

new Vue({
  el:'#app',
  data:{
    msg:"我是父組件的內(nèi)容"
  }
})
</script>

此時(shí)渲染出來的DOM結(jié)構(gòu)如下:


DOM結(jié)構(gòu)
DOM結(jié)構(gòu)

作用域插槽
作用:從子組件獲取數(shù)據(jù)

<div id="app">
  <my-component>
    <!--template不會(huì)被渲染,vue2.5.0之后不需要寫template標(biāo)簽了-->
    <template slot="son" slot-scope="prop">
      {{prop.text}}
      <!--無法拿到name-->
    </template>
  </my-component>
</div>

<script>
Vue.component('my-component',{
template:`
  <div>
    <slot name="son" text="hello vue">

    </slot>
  </div>
`
})

new Vue({
  el:'#app'
})
</script>

訪問slot
通過this.$slot訪問

<div id="app">
  <my-component>
    <h2 slot="header">我是標(biāo)題</h2>
    <p slot="main">我是正文</p>
    <p slot="main">正文第二部分</p>
    <span slot="footer">我是底部信息</span>
  </my-component>
</div>

<script>
Vue.component('my-component',{
  template:`<div>
<header>
  <slot name="header"></slot>
</header>
<main>
  <slot name="main"></slot>
</main>
<footer>
  <slot name="footer"></slot>
</footer>
</div>`,
  data(){
    return{
      msg: '我是子組件的內(nèi)容'
    }
  },
  mounted(){
    //訪問插槽
    let header = this.$slots.header
    let text = header[0].elm.innerText
    console.log(header)
    console.log(text)
  }
})

new Vue({
  el:'#app',
  data:{
    msg:"我是父組件的內(nèi)容"
  }
})
</script>

動(dòng)態(tài)組件

Vue給我們提供了一個(gè)元素叫component科乎,用來動(dòng)態(tài)的掛載不同的組件
實(shí)現(xiàn):使用is特性來實(shí)現(xiàn)

  <div id="app">
    <component :is="thisView"></component>
    <button @click="changeView('a')">a</button>
    <button @click="changeView('b')">b</button>
    <button @click="changeView('c')">c</button>
  </div>
  
  <script>
  Vue.component('a-component',{
  template:`<div>我是a組件的內(nèi)容</div>`
})
Vue.component('b-component',{
  template:`<div>我是b組件的內(nèi)容</div>`
})
Vue.component('c-component',{
  template:`<div>我是c組件的內(nèi)容</div>`
})

new Vue({
  el:'#app',
  data:{
    thisView: 'a-component'
  },
  methods:{
    changeView(value){
      this.thisView = value+'-component'
    }
  }
})
  </script>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壁畸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子茅茂,更是在濱河造成了極大的恐慌捏萍,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件空闲,死亡現(xiàn)場離奇詭異令杈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碴倾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門这揣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人影斑,你說我怎么就攤上這事给赞。” “怎么了矫户?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵片迅,是天一觀的道長。 經(jīng)常有香客問我皆辽,道長柑蛇,這世上最難降的妖魔是什么芥挣? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任空免,我火速辦了婚禮,結(jié)果婚禮上蹋砚,老公的妹妹穿的比我還像新娘坝咐。我一直安慰自己析恢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布泽篮。 她就那樣靜靜地躺著帽撑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪历恐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天蒸苇,我揣著相機(jī)與錄音溪烤,去河邊找鬼庇勃。 笑死责嚷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的揍异。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辱姨,長吁一口氣:“原來是場噩夢啊……” “哼雨涛!你這毒婦竟也來了渡处?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤侣肄,失蹤者是張志新(化名)和其女友劉穎稼锅,沒想到半個(gè)月后矩距,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怖竭,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痊臭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年广匙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸦致。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抗碰,死狀恐怖改含,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骤视,我是刑警寧澤专酗,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布祷肯,位于F島的核電站疗隶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蒋纬。R本人自食惡果不足惜坚弱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一荒叶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脂凶,春花似錦蚕钦、人聲如沸埋市。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泞当,卻和暖如春民珍,著一層夾襖步出監(jiān)牢的瞬間盗飒,已是汗流浹背逆趣。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工宣渗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梨州,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓鞍恢,卻偏偏與公主長得像有序,于是被迫代替她去往敵國和親岛请。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 此文基于官方文檔盅称,里面部分例子有改動(dòng)缩膝,加上了一些自己的理解 什么是組件岸霹? 組件(Component)是 Vue.j...
    陸志均閱讀 3,826評論 5 14
  • 組件(Component)是Vue.js最核心的功能贡避,也是整個(gè)架構(gòu)設(shè)計(jì)最精彩的地方,當(dāng)然也是最難掌握的湖饱。...
    六個(gè)周閱讀 5,606評論 0 32
  • 什么是Vue組件 組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一井厌。組件可以擴(kuò)展 HTML 元素,...
    bacbcc94613b閱讀 968評論 0 0
  • 1. 組件 a. 什么是組件 組件化開發(fā) 我們可以很直觀的把一個(gè)復(fù)雜的頁面分割成若干個(gè)獨(dú)立的組件器赞,每個(gè)組件包含...
    goodluckall閱讀 139評論 0 0
  • 月初拳魁,與朋友帶著家人一起去了一次江南—江潘懊、浙贿衍、滬,于是有了此游記释树。 第一天下午擎淤,我們一行十人乘坐高鐵來到無錫入住。...
    NapoleonHill閱讀 232評論 0 0