VUE大神的成長之路--組件

組件是vue最強(qiáng)大的功能之一散罕,組件可以擴(kuò)展 HTML 元素分歇,封裝可重用的代碼。在較高層面上欧漱,組件是自定義元素职抡, Vue.js 的編譯器為它添加特殊功能。在有些情況下误甚,組件也可以是原生 HTML 元素的形式缚甩,以 is 特性擴(kuò)展。
(一)注冊一個全局組件:(對于自定義標(biāo)簽名窑邦,Vue.js不要求強(qiáng)制遵循W3C規(guī)則(小寫擅威,并且包含一個短杠),盡管遵循這個規(guī)則比較好)

Vue.component('my-component',{
    //內(nèi)容
})

組件在注冊之后冈钦,便可以在父實(shí)例的模塊中以自定義元素

<my-component></my-component>

的形式使用了郊丛,
重點(diǎn):必須要確保在初始化根實(shí)例之前注冊了組件

舉例:

<div id="app">
   <my-component></my-component>
</div>

//全局注冊
Vue.component('my-component', {
    template: '<div>A custom component!</div>'
})

//初始化根實(shí)例
new Vue({
    el: "#app",
    data: {

    }
});

渲染結(jié)果:

<div id="app">
  <div>A custom component!</div>
</div>

一般在項(xiàng)目中,不必在全局注冊每個組件瞧筛。通過使用組件實(shí)例選項(xiàng)注冊宾袜,可以使組件僅在另一個實(shí)例/組件的作用域中可用:

var Child = {
    template: '<div>A custom component!</div>'
}

new Vue({
    el: "#app",
    data: {

    },
    components: {
       'my-component': Child
    }
});

(二)DOM模板解析說明:
當(dāng)使用 DOM 作為模版時(例如,將 el 選項(xiàng)掛載到一個已存在的元素上), 你會受到 HTML 的一些限制驾窟,因?yàn)?Vue 只有在瀏覽器解析和標(biāo)準(zhǔn)化 HTML 后才能獲取模版內(nèi)容庆猫。尤其像這些元素 <ul> ,<ol>绅络,<table> 月培,<select> 限制了能被它包裹的元素, 而一些像 <option> 這樣的元素只能出現(xiàn)在某些其它元素內(nèi)部恩急。

在自定義組件中使用這些受限制的元素時會導(dǎo)致一些問題杉畜,例如:

<table>
   <my-row>...</my-row>
</table>

以上中,<mr-row>是會被認(rèn)為是無效內(nèi)容衷恭,因?yàn)閠able中只能包裹td,th,tr等元素此叠,變通方案是使用特殊的is屬性:

<table>
   <tr is="my-row"></tr>
</table>

(三)data必須是函數(shù)

我們先來看一個案例:

<div id="example-2">
  <simple-counter></simple-counter>
  <simple-counter></simple-counter>
  <simple-counter></simple-counter>
</div>

var data = { counter: 0 }
Vue.component('simple-counter', {
  template: '<button v-on:click="counter += 1">{{ counter }}</button>',
  data: function () {
    return data
  }
})

new Vue({
  el: '#example-2'
})

你會發(fā)現(xiàn),三個按鈕是聯(lián)動的K嬷椤C鹪!
因?yàn)樯厦嬷写翱矗琩ada是一個函數(shù)茸歧,我們返回給每個組件的實(shí)例引用了同一個data對象,由于這三個組件共享了同一個data显沈,因此增加一個counter會影響所有的組件

為了解決這個問題软瞎,我們需要將data設(shè)置為一個方法函數(shù)

data: function () {
  return {
    counter: 0
  }
}

接下來逢唤,每個按鈕都會有了自己的狀態(tài)了

(四)構(gòu)成組件
在Vue中,父子組件的關(guān)系可以總結(jié)為props down,events up涤浇。父組件通過props向下傳遞數(shù)據(jù)給子組件鳖藕,子組件通過events給父組件發(fā)送消息

先來看看prop
組件實(shí)例的作用域是孤立的。這意味著不能(也不應(yīng)該)在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù)只锭。要讓子組件使用父組件的數(shù)據(jù)吊奢,我們需要通過子組件的props選項(xiàng)。
還是舉例說明:
子組件要顯示的用props選項(xiàng)聲明它期待獲得的數(shù)據(jù):

Vue.component('my-component', {
    //聲明props
    props: ['message'],
    //就像data一樣纹烹,prop可以用在模板內(nèi)
    //同樣也可以在vm實(shí)例中像"this.message" 這樣使用
    template: '<div>{{ message }}</div>'
})

在使用時可以這樣傳入一個普通字符串

<div id="app">
   <my-component message="hello!"></my-component>
</div>

特別注意:

HTML 特性是不區(qū)分大小寫的页滚。所以,當(dāng)使用的不是字符串模版铺呵,camelCased (駝峰式) 命名的 prop 需要轉(zhuǎn)換為相對應(yīng)的 kebab-case (短橫線隔開式) 命名:

Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>

動態(tài)prop

在模板中裹驰,要動態(tài)地綁定父組件的數(shù)據(jù)到子模板的props,與綁定到任何普通的HTML特性相類似片挂,就是用 v-bind幻林。每當(dāng)父組件的數(shù)據(jù)變化時,該變化也會傳導(dǎo)給子組件:

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

var Child = {
     props: ['myMessage'],
     template: '<div>{{ myMessage }}</div>'
}

new Vue({
    el: "#app",
    data: {
        a:1
    },
    components: {
        'my-component': Child
    }
});

字面量語法VS動態(tài)語法

初學(xué)者常犯的一個錯誤就是使用字面量語法傳遞數(shù)值:

<!-- 傳遞了一個字符串 "1" -->
<comp some-prop="1"></comp>

因?yàn)樗且粋€字面 prop 音念,它的值是字符串 "1" 而不是number沪饺。如果想傳遞一個實(shí)際的number,需要使用 v-bind 闷愤,從而讓它的值被當(dāng)作 JavaScript 表達(dá)式計算:

<!-- 傳遞實(shí)際的 number -->
<comp v-bind:some-prop="1"></comp>

單項(xiàng)數(shù)據(jù)流

prop是單向綁定的:當(dāng)父組件的屬性變化時整葡,將傳導(dǎo)給子組件,但是不會反過來讥脐。這是為了防止子組件無意修改了父組件的狀態(tài)--這會讓應(yīng)用的數(shù)據(jù)流難以理解

另外遭居,每次父組件更新時,子組件的所有prop都會更新為最新值旬渠,這意味著你不應(yīng)該在子組件內(nèi)改變prop

對于為什么會有修改prop中數(shù)據(jù)的沖動俱萍,VUE官方給出的解釋:
1.prop 作為初始值傳入后,子組件想把它當(dāng)作局部數(shù)據(jù)來用告丢;
2.prop 作為初始值傳入枪蘑,由子組件處理成其它數(shù)據(jù)輸出。

對于這兩種原因岖免,正確的應(yīng)對方式時:
1.定義一個局部變量岳颇,并用prop的值初始化它:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

2.定義一個計算屬性,處理 prop 的值并返回觅捆。

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

注意在 JavaScript 中對象和數(shù)組是引用類型赦役,指向同一個內(nèi)存空間麻敌,如果 prop 是一個對象或數(shù)組栅炒,在子組件內(nèi)部改變它會影響父組件的狀態(tài)。

prop驗(yàn)證

我們可以為組件的props指定驗(yàn)證規(guī)格,如果傳入的數(shù)據(jù)不符合規(guī)格赢赊,vue會發(fā)出警告乙漓,當(dāng)組件給其他人使用時,這很有用释移。
要指定驗(yàn)證規(guī)格叭披,需要用對象的形式,而不能用字符串?dāng)?shù)組
比如:

Vue.component('example',{
    props: {
       //基礎(chǔ)類型檢測(null意思是任何類型都可以)
       propA:Number,
       //多種類型
       propB: [String,Number],
       //必傳且是字符串
       propC: {
           type: String,
           required: true
       },
       //數(shù)字玩讳,有默認(rèn)值
       propD: {
           type: Number,
           default: 100
       },
       //數(shù)組/對象的默認(rèn)值應(yīng)當(dāng)由一個工廠函數(shù)返回
       propE: {
          type: Object,
          default: function() {
              return {
                 message: 'hello'
              }
          }
       },
       //自定義驗(yàn)證函數(shù)
       propF: {
          validator: function(value) {
              return value > 10
          }
       }
    }
})

type可以使下面原生構(gòu)造器

String, Number, Boolean, Function, Object, Array

type也可以是一個自定義構(gòu)造器函數(shù)涩蜘,使用instanceof檢測。

(四)自定義事件
父組件是使用props傳遞數(shù)據(jù)給子組件熏纯,但是如果子組件要把數(shù)據(jù)傳遞回去同诫,應(yīng)該怎么做呢?那就是接下來要說的是自定義事件

使用v-on綁定自定義事件

來看一個例子
使用 $on(eventName) 監(jiān)聽事件
使用 $emit(eventName) 觸發(fā)事件

<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>

Vue.component('button-counter', {
    template: '<button v-on:click="increment">{{ counter }}</button>',
    data: function(){
       return {
          counter: 0
       }
    },
    methods: {
       increment: function() {
          this.counter += 1
          this.$emit('increment')
       }
    }
})
new Vue({
    el: '#counter-event-example',
    data: {
       total: 0
    },
    methods: {
       incrementTotal: function() {
           this.total += 1
       }
    }
})

在本例中樟澜,子組件已經(jīng)和它外部完全解耦了误窖。它所做的只是報告自己的內(nèi)部事件,至于父組件是否關(guān)心則與它無關(guān)秩贰。留意到這一點(diǎn)很重要霹俺。

使用自定義事件的表單輸入組件

自定義事件可以用來創(chuàng)建自定義的表單輸入組件,使用 v-model 來進(jìn)行數(shù)據(jù)雙向綁定

非父子組件通信

有時候兩個組件也需要通信(非父子關(guān)系)在簡單的場景下毒费,可以使用一個空的 Vue 實(shí)例作為中央事件總線:

var bus = new Vue()

// 觸發(fā)組件 A 中的事件

bus.$emit('id-selected', 1)

// 在組件 B 創(chuàng)建的鉤子中監(jiān)聽事件

bus.$on('id-selected', function (id) {
  // ...
})

(五)使用Slot分發(fā)內(nèi)容
為了讓組件可以組合丙唧,我們需要一種方式來混合父組件的內(nèi)容與子組件自己的模板,這個過程被稱作內(nèi)容分發(fā)
(1)編譯作用域
父組件模板的內(nèi)容在父組件作用域內(nèi)編譯觅玻;子組件模板的內(nèi)容在子組件作用域內(nèi)編譯艇棕。
如果要綁定作用域內(nèi)的指令到一個組件的根節(jié)點(diǎn),你應(yīng)當(dāng)在組件自己的模板上做:

Vue.component('child-component', {
    //有效串塑,因?yàn)槭窃谡_的作用域內(nèi)
    template: '<div v-show="someChildProperty">Child</div>',
    data: function() {
        return {
          someChildProperty: true
        }
    }
})

(2)單個Slot

--------未完待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沼琉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子桩匪,更是在濱河造成了極大的恐慌打瘪,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻昙,死亡現(xiàn)場離奇詭異闺骚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)妆档,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門僻爽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贾惦,你說我怎么就攤上這事胸梆《嘏酰” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵碰镜,是天一觀的道長兢卵。 經(jīng)常有香客問我,道長绪颖,這世上最難降的妖魔是什么秽荤? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮柠横,結(jié)果婚禮上窃款,老公的妹妹穿的比我還像新娘。我一直安慰自己牍氛,他們只是感情好雁乡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著糜俗,像睡著了一般踱稍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悠抹,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天珠月,我揣著相機(jī)與錄音,去河邊找鬼楔敌。 笑死啤挎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卵凑。 我是一名探鬼主播庆聘,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勺卢!你這毒婦竟也來了伙判?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤黑忱,失蹤者是張志新(化名)和其女友劉穎宴抚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甫煞,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菇曲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了抚吠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片常潮。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖楷力,靈堂內(nèi)的尸體忽然破棺而出喊式,到底是詐尸還是另有隱情孵户,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布垃帅,位于F島的核電站延届,受9級特大地震影響剪勿,放射性物質(zhì)發(fā)生泄漏贸诚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一厕吉、第九天 我趴在偏房一處隱蔽的房頂上張望酱固。 院中可真熱鬧,春花似錦头朱、人聲如沸运悲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽班眯。三九已至,卻和暖如春烁巫,著一層夾襖步出監(jiān)牢的瞬間署隘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工亚隙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留磁餐,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓阿弃,卻偏偏與公主長得像诊霹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子渣淳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容脾还,還有我對于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,045評論 0 29
  • 下載安裝搭建環(huán)境 可以選npm安裝入愧,或者簡單下載一個開發(fā)版的vue.js文件 瀏覽器打開加載有vue的文檔時荠呐,控制...
    冥冥2017閱讀 6,029評論 0 42
  • Vue 實(shí)例 屬性和方法 每個 Vue 實(shí)例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,202評論 0 6
  • 此文基于官方文檔,里面部分例子有改動砂客,加上了一些自己的理解 什么是組件泥张? 組件(Component)是 Vue.j...
    陸志均閱讀 3,805評論 5 14
  • 什么是組件 組件(Component)是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素鞠值,封裝可重用...
    angelwgh閱讀 777評論 0 0