第十一課時: 關於Vue組件一些注意的地方

組件的基本使用

註冊組件

1.註冊組件就是利用Vue.component()方法
2.能夠理解爲一個vue文件就是一個組件html

模板要求

組件的模板中只能有一個根元素vue

組件中的data必須是函數

var app = new Vue({
    data () {
      return {
        message: 'hello world'
      }
    }
})

組件的屬性和事件

例,一個父組件:數組

<my-component v-bind:foo="baz" v-on:event-a="doThis(arg1,...arg2)"></my-component>

上面代碼app

  • foo<my-component>組件內部定義的一個prop屬性,baz是父組件的一個data屬性,
  • event-a是子組件定義的一個事件,doThis是父組件的一個方法

執行過程應該是這樣的:函數

  • 父組件把baz數據經過prop傳遞給子組件的foo
  • 子組件內部獲得foo的值,就能夠進行相應的操做;
  • 當子組件內部發生了一些變化,但願父組件能知道時,就利用代碼觸發event-a事件,把一些數據發送出去
  • 父組件把這個事件處理器綁定爲doThis方法,子組件發送的數據,就做爲doThis方法的參數被傳進來
  • 而後父組件就能夠根據這些數據,進行相應的操做

屬性Props

Vue組件經過props屬性來聲明一個本身的屬性,而後父組件就能夠往裏面傳遞數據。ui

Vue.component('mycomponent',{
    template: '<div>這是一個自定義組件,父組件傳給個人內容是:{{myMessage}}</div>',
    props: ['myMessage'],
    data () {
      return {
        message: 'hello world'
      }
    }
  })

而後調用該組件this

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

注意,因爲HTML特性是不區分大小寫的,因此傳遞屬性值時,myMessage應該轉換成 kebab-case (短橫線隔開式)my-message="hello"spa

v-bind綁定屬性值

<div attr="message">hello</div>

上面這樣,div元素的attr特性值就是message。而這樣雙向綁定

<div v-bind:attr="message">hello</div>

這裏的message應該是Vue實例的data的一個屬性,這樣div元素的attr特性值就是message這個屬性的值。
之因此說是通常狀況,是由於classstyle特性並非這樣。用v-bind:classclass傳入正常的類名,效果是同樣的,由於對於這兩個特性,Vue採用了合併而不是替換的原則。code

子組件但願對傳入的prop進行操做

根據上面,想要把父組件的屬性綁定到子組件,應該使用v-bind,這樣,父組件中數據改變時能反映到子組件。
注意 在子組件中最好不要更改父組件傳入的值,若是非要更改的話,加上.sync修飾符

例父組件

<my-component :child-array.sync="parentArray"></my-component>

子組件

methods: {
     changeArray () {
       this.counter++
       this.$emit('update:childArray', this.counter)
     }
}

給子組件傳遞正確類型的值

一樣是上面的緣由,靜態的給子組件的特性傳遞值,它都會把他當作一個字符串。

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

子組件中,特性的值是字符串 "1" 而不是 number 1。若是想傳遞正確的數值,應該使用v-bind傳遞,這樣就能把傳遞的值當作一個表達式來處理,而不是字符串。

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

Prop驗證

咱們能夠給組件的props屬性添加驗證,當傳入的數據不符合要求時,Vue會發出警告。

Vue.component('example', {
  props: {
    // 基礎類型檢測 (`null` 意思是任何類型均可以)
    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 value > 10
      }
    }
  }
})

type 能夠是下面原生構造器:

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

type 也能夠是一個自定義構造器函數

自定義事件

經過prop屬性,父組件能夠向子組件傳遞數據,而自定義事件就是用來將子組件的內部數據報告給父組件的。

<div id="app3">
    <my-component2 v-on:myclick="onClick"></my-component2>
</div>
<script>
  Vue.component('my-component2', {
    template: `<div>
    <button type="button" @click="childClick">點擊我觸發自定義事件</button>
    </div>`,
    methods: {
      childClick () {
        this.$emit('myclick', '這是我暴露出去的數據', '這是我暴露出去的數據2')
      }
    }
  })
  new Vue({
    el: '#app3',
    methods: {
      onClick () {
        console.log(arguments)
      }
    }
  })
</script>

如上所示,共分爲如下步驟:

  1. 子組件在本身的方法中將自定義事件以及須要發出的數據經過如下代碼發送出去

    this.$emit('myclick', '這是我暴露出去的數據', '這是我暴露出去的數據2')
    第一個參數是自定義事件的名字
    後面的參數是依次想要發送出去的數據
  2. 父組件利用v-on爲事件綁定處理器

    <my-component2 v-on:myclick="onClick"></my-component2>

    這樣,在Vue實例的methods方法中就能夠調用傳進來的參數了

注意: 在使用v-on綁定事件處理方法時,不該該傳進任何參數,而是直接寫v-on:myclick="onClick",否則,子組件暴露出來的數據就沒法獲取到了

綁定原生事件

若是想在某個組件的根元素上監聽一個原生事件。可使用 .native 修飾 v-on

探究v-model

v-model能夠對錶單控件實現數據的雙向綁定,它的原理就是利用了綁定屬性和事件來實現的。好比input控件。不使用v-model,能夠這樣實現數據的雙向綁定:

<div id="app4">
    <input type="text" v-bind:value="text" v-on:input="changeValue($event.target.value)">
    {{text}}
</div>
<script>
  new Vue({
    el: '#app4',
    data: {
      text: '444'
    },
    methods: {
      changeValue (value) {
        this.text = value
      }
    }
  })
</script>

上面的代碼一樣實現了數據的雙向綁定。其本質就是:

  • inputvalue特性綁定到Vue實例的屬性text上,text改變,input中的內容也會改變
  • 而後把表單的input事件處理函數設置爲Vue實例的一個方法,這個方法會根據輸入參數改變Vue中text的值
  • 相應的,在input中輸入內容時,觸發了input事件,把event.target.value傳給這個方法,最後就實現了改變綁定的數據的效果。

v-model就是上面這種方式的語法糖,也就是把上面的寫法封裝了一下,方便咱們使用。

使用slot分發內容

單個slot

上面用到的不少組件的使用方式是這樣的:

<component></component>

也就是說組件中是空的,沒有放置任何文本或元素。可是原生的html元素都是能夠進行嵌套的,div裏面放table什麼的。自定義組件開閉標籤之間也能夠放置內容,不過須要在定義組件時使用slot

slot至關於子組件設置了一個地方,若是在調用它的時候,往它的開閉標籤之間放了東西,那麼它就把這些東西放到slot中。

  1. 當子組件中沒有slot時,父組件放在子組件標籤內的東西將被丟棄;
  2. 子組件的slot標籤內能夠放置內容,當父組件沒有放置內容在子組件標籤內時,slot中的內容會渲染出來;
  3. 當父組件在子組件標籤內放置了內容時,slot中的內容被丟棄

子組件的模板:

<div>
  <h2>我是子組件的標題</h2>
  <slot>
    只有在沒有要分發的內容時纔會顯示。
  </slot>
</div>

父組件模板:

<div>
  <h1>我是父組件的標題</h1>
  <my-component>
    <p>這是一些初始內容</p>
  </my-component>
</div>

渲染結果:

<div>
  <h1>我是父組件的標題</h1>
  <div>
    <h2>我是子組件的標題</h2>
    <p>這是一些初始內容</p>
  </div>
</div>

具名slot

slot能夠有不少個。那麼子組件對於父組件放置的多餘的內容如何放到各個slot中呢?方法就是子組件給每一個slot起一個名字name,父組件放置多餘的元素時,給每一個元素的slot屬性分配一個表明slot的名字。到時候,多餘的內容就會根據本身的slot屬性去找具備對應名字的slot元素。

注意:

  1. 子組件能夠有一個匿名的slot,當分發的多餘內容找不到對應的slot時,就會進入這裏面
  2. 若是子組件沒有匿名的slot,當分發的多餘內容找不到對應的slot時,就會被丟棄

例如,假定咱們有一個 app-layout 組件,它的模板爲:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

父組件模版:

<app-layout>
  <h1 slot="header">這裏多是一個頁面標題</h1>
  <p>主要內容的一個段落。</p>
  <p>另外一個主要段落。</p>
  <p slot="footer">這裏有一些聯繫信息</p>
</app-layout>

渲染結果爲:

<div class="container">
  <header>
    <h1>這裏多是一個頁面標題</h1>
  </header>
  <main>
    <p>主要內容的一個段落。</p>
    <p>另外一個主要段落。</p>
  </main>
  <footer>
    <p>這裏有一些聯繫信息</p>
  </footer>
</div>

做用域插槽

做用域插槽也是一個插槽slot,可是他能夠把數據傳遞給到父組件的特定元素內,而後有父組件決定如何渲染這些數據。

  1. 首先,子組件的slot須要有一些特性(prop)

    Vue.component('my-component4', {
         template: `<div>
           <slot :text="hello" message="world"></slot>
         </div>`,
         data () {
           return {
             hello: [1,'2']
           }
         }
       })
  2. 父組件在調用子組件時,須要在裏面添加一個template元素,而且這個template元素具備scope特性

    <div id="app7">
      <my-component4>
        <template scope="props">
        </template>
      </my-component4>
     </div>

    scope特性的值,就表明了全部子組件傳過來的數據組成的對象。至關於

    props = {
        text: '',
       message: ''
    }
  3. 最後,父組件就能夠在template中渲染子組件傳過來的數據了

    <div id="app7">
       <my-component4>
         <template slot-scope="props">
           <span>{{props.text}}</span>
           <span>{{props.message}}</span>
         </template>
       </my-component4>
      </div>

    做用域插槽也是插槽,只不過是多加了些特性,而後父組件多進行了些處理。

相關文章
相關標籤/搜索