vue組件之事件

自定義事件

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

<div id="app3">
    <my-component v-on:myclick="onClick"></my-component>
</div>
<script>
  Vue.component('my-component', {
    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

點擊按鈕 控制檯打印出以下
vue

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

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

this.$emit('myclick', '這是我暴露出去的數據', '這是我暴露出去的數據2')

第一個參數是自定義事件的名字
後面的參數是依次想要發送出去的數據
父組件利用v-on爲事件綁定處理器app

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

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

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

綁定原生事件

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

<my-component v-on:click.native="doTheThing"></my-component>
探究v-model

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

<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>

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

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

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

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

理解了v-model的內幕,也就能夠把這個效果用在自定義表單組件上了。
一個組件上的 v-model 默認會利用名爲 value 的 prop 和名爲 input 的事件,可是像單選框、複選框等類型的輸入控件可能會將 value 特性用於不一樣的目的。model 選項能夠用來避免這樣的衝突:

<div id="app5">
        <base-checkbox v-model="lovingVue"></base-checkbox>
        <div>{{lovingVue}}</div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('base-checkbox', {
            model: {
                prop: 'checked',
                event: 'change'
                },
            props: {
                checked: Boolean
            },
            template: `<input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)"> `
        })
        var vm = new Vue({
            el: "#app5",
            data: {
                lovingVue: false
            }
        })
    </script>

這裏的 lovingVue 的值將會傳入這個名爲 checked 的 prop。同時當 觸發一個 change 事件並附帶一個新的值的時候,這個 lovingVue 的屬性將會被更新。

注意 你仍然須要在組件的 props 選項裏聲明 checked 這個 prop。

動態組件

經過使用保留的 元素,動態地綁定到它的 is 特性,可讓多個組件使用同一個掛載點,並動態切換

<div id="app6">
                <select v-model="currentComponent">
                  <option value="home">home</option>
                  <option value="posts">post</option>
                  <option value="archive">about</option>
                </select>
                <component :is="currentComponent"></component>
              </div>
              <script src="https://cdn.jsdelivr.net/npm/vue"></script>
              <script>
                  new Vue({
                    el: '#app6',
                    data: {
                      currentComponent: 'home'
                    },
                    components: {
                      home: {
                        template: `<header>這是home組件</header>`
                      },
                      posts: {
                        template: `<header>這是posts組件</header>`
                      },
                      archive: {
                        template: `<header>這是archive組件</header>`
                      }
                    }
                  })
            </script>
保留切換出去的組件,避免從新渲染

若是把切換出去的組件保留在內存中,能夠保留它的狀態或避免從新渲染。爲此能夠添加一個 keep-alive 指令參數:

<!-- 失活的組件將會被緩存!-->
<keep-alive>
  <component :is="currentComponent">
   
  </component>
</keep-alive>
插槽
單個slot

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

<component></component>

也就是說組件中是空的,沒有放置任何文本或元素。可是原生的html元素都是能夠進行嵌套的,div裏面放table
什麼的。自定義組件開閉標籤之間也能夠放置內容,不過須要在定義組件時使用slot。
slot至關於子組件設置了一個地方,若是在調用它的時候,往它的開閉標籤之間放了東西,那麼它就把這些東西放到slot中。

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

列子

<div id="app"> //父組件模板:
        <h1>我是父組件的標題</h1>
        <my-component>
            <p>這是一些初始內容</p>
        </my-component>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el: "#app",
            data: {},
            components: {
                'my-component': {
                    template: `
                    <div>//子組件的模板
                        <h2>我是子組件的標題</h2>
                        <slot>
                            只有在沒有要分發的內容時纔會顯示。
                        </slot>
                    </div> `
                }
            }
        })
    </script>

渲染 結果:

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

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

注意

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

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

<div id="app">
        <app-layout>
            <h1 slot="header">這裏多是一個頁面標題</h1>
            <p>主要內容的一個段落。</p>
            <p>另外一個主要段落。</p>
            <p slot="footer">這裏有一些聯繫信息</p>
        </app-layout>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el: "#app",
            data: {},
            components: {
                'my-component': {
                    template: `
                    <div class="container">
                        <header>
                            <slot name="header"></slot>
                        </header>
                        <main>
                            <slot></slot>
                        </main>
                        <footer>
                            <slot name="footer"></slot>
                        </footer>
                    </div> `
                }
            }
        })
          </script>

渲染結果:

<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>

4.Vue支持將做用域插槽的屬性解構。因此上述代碼能夠簡寫爲:

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

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

相關文章
相關標籤/搜索