1. 程式人生 > 實用技巧 >Vuejs知識點彙總

Vuejs知識點彙總

元件

  • 元件是可複用的 Vue 例項,且帶有一個名字
  • 每用一次元件,就會有一個它的新例項被建立
  • data 必須是一個函式
    data: function () {
      return {
        count: 0
      }
    }
    

1. 註冊元件

  • 全域性註冊

    可以用在任何新建立的 Vue 根例項的模板中。第一個引數是元件名

    Vue.component('my-component-name', {
      // ... options ...
    })
    
  • 區域性註冊

    即在哪註冊在哪用,這樣就不會過多的佔用記憶體,首先註冊一個區域性元件

    var ComponentA={
        props:['title'],
        template:`<h3>{{title}}</h3>`
    }
    

    然後例項的components物件中使用,屬性名就是元件名,屬性值就是你想傳入的元件

    new Vue({
      el: '#app',
      components:{
          'blog-title':ComponentA
      }
    })
    

注意:推薦使用kebab-case(短橫線分割命名)給元件命名,例如該例子中的<blog-title>,否則容易報錯:

注意:每個元件必須只有一個根元素,即template裡只能有一個根標籤

2. Prop

#prop大小寫

prop對大小寫不敏感,所以可以這樣使用:

Vue.component('blog', {
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<blog post-title="hello!"></blog>

#prop型別

一般情況下是以字串陣列形式列出的 prop:

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

也可以給每個prop指定值型別。屬性名是prop名稱,屬性值是prop型別

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}
//也可以是Data、Symbol

#傳遞prop

一個例子

Vue.component('blog-post', {
  props: ['title'],	//給元件定義一個屬性
  template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post> //傳值
  • 靜態傳遞

    # 傳入字串
    <blog-post title="My journey with Vue"></blog-post>
    
    #有時候需要用v-bind告訴vue這是一個js表示式而不是字串
    # 傳入布林值,
    <blog-post :is-published="false"></blog-post>
    # 傳入陣列
    <blog-post :comment-ids="[234, 266, 273]"></blog-post>
    # 傳入物件
    <blog-post :author="{name: 'Veronica',company: 'Veridian Dynamics'}"></blog-post>
    # 傳入一個物件所有的屬性
    
  • 動態傳遞

    new Vue({
      el: '#blog',
      data: {
        posts: [
          { id: 1, title: 'My journey with Vue' },
          { id: 2, title: 'Blogging with Vue' },
          { id: 3, title: 'Why Vue is so fun' }
        ]
      }
    })
    
    <blog-post v-for="post in posts" :key="post.id" :title="post.title" ></blog-post>
    

    當需要傳遞的屬性很多時,可以將這些屬性成合成一個。在這個例子中,可以把所有post所有的屬性如title、content寫在一個post 中:

  1. 重構元件

    原本子元件

    Vue.component('blog-post', {
      props: ['title','content'],
      template: `
        <div>
          <h3>{{ title }}</h3>
          <div v-html="content"></div>
        </div>
      `
    })
    

    現在子元件

    Vue.component('blog-post', {
      props: ['post'],
      template: `
        <div>
          <h3>{{ post.title }}</h3>
          <div v-html="post.content"></div>
        </div>
      `
    })
    
  2. 建立例項

    new Vue({
      el: '#blog',
      data: {
        posts: [
          { id: 1, title: 'My journey with Vue',content:'111' },
          { id: 2, title: 'Blogging with Vue',content:'222' },
          { id: 3, title: 'Why Vue is so fun',content:'333'}
        ]
      }
    })
    
  3. 在例項中使用元件

    原本父級

    <blog-post v-for="post in posts" :key="post.id" :title="post.title" :content="post.comtent"></blog-post>
    

    現在父級

    <blog-post v-for="post in posts" :key="post.id" :post="post"></blog-post>
    

#單項資料流

父級 prop 的更新會向下流動到子元件中,但是反過來則不行

#prop驗證

可以為元件的 prop 指定驗證要求。

  • 當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制檯的警告。
  • prop 會在一個元件例項建立之前進行驗證
Vue.component('my-component', {
  props: {
    //1. 基礎的型別檢查 (null和undefined會通過任何型別驗證)  
    propA: Number,
      
    //2. 多個可能的型別
    propB: [String, Number],
      
    //3. 必填的字串
    propC: {				 
      type: String,
      required: true
    },
      
    //4. 帶有預設值的數字
    propD: {				 
      type: Number,
      default: 100
    },
      
    //5.自定義驗證函式。下面例子表示必須匹配下列字串中的一個
    propF: {				  
      validator: function (value) {
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

3. 自定義事件

#事件名

推薦始終使用 kebab-case 的事件名

this.$emit('my-event')
<my-component @my-event="doSomething"></my-component>

#監聽子元件事件

  1. 建立例項

    new Vue({
      el: '#demo',
      data: {
        posts: [/* ... */],
        postFontSize: 1
      }
    })
    
  2. $emit給子元件新增事件

    Vue.component('blog-post', {
      props: ['post'],
      template: `
        //...
          <button @click="$emit('enlarge-text')">Enlarge</button>
         //...
      `
    })
    
  3. v-on監聽子元件事件。當子元件觸發時,開始響應

    <div id="demo">
      <div :style="{ fontSize: postFontSize + 'em' }">
        <blog-post 
          ...
          @enlarge-text="postFontSize += 0.1"
         ></blog-post>
     </div>
    </div>
    

$emit可以接收第二個引數

  1. 給子元件事件新增引數

    <button v-on:click="$emit('enlarge-text', 0.1)">Enlarge</button>
    
  2. 父級通過$event獲取整個引數值

    <blog-post
      ...
      @enlarge-text="postFontSize += $event"
    ></blog-post>
    

    第二種寫法:

    <blog-post
    ...
    @enlarge-text="enlargeText"
    ></blog-post>
    

    傳過來的引數值會作為該方法的第一個引數

    methods: {
       enlargeText: function (num) {
         this.postFontSize += num
       }
    }
    

#自定義事件中的v-model

  • 普通情況下自定義事件

    <input v-model="searchText">
    

    等價於

    <input :value="searchText" @input="searchText = $event.target.value">
    
  • 在元件上自定義事件

    <custom-input v-model="searchText"/>
    

    等價於

    <custom-input :value="searchText" @input="searchText = $event"/>
    

    這時候需要更改子元件,才能讓其正常運作。

    Vue.component('custom-input', {
      props: ['value'],
      template: `
        <input
          :value="value"
          @input="$emit('input', $event.target.value)"
        >
      `
    })
    

    解析:這時子元件的input觸發時,會丟擲$event.target.value,父級會監聽到並接收$event.target.value。此時父級的$event實際上就等於子元件丟擲的$event.target.value,變化後的searchText的值會繫結在父級的value上,然後通過props傳回子元件,子元件接收到這個props值後就繫結在input的value上,這時候就在頁面呈現出效果了

#繫結原生事件

使用 v-on.native 修飾符:

<base-input @focus.native="onFocus"></base-input>

注意.native監聽的是元件的根元素。如果想監聽到子元素,需要用到$listeners物件

4. 插槽

#一個例子

  1. 在子元件模板中加上一個插槽<slot></slot>

    Vue.component('alert-box', {
      template: `
        <div>
          <strong>Error!</strong>
          <slot></slot>
        </div>
      `
    })
    
  2. 在父級元件內新增內容後,內容就會自動放進插槽內

    <alert-box>Something bad happened.</alert-box>
    

注意:如果子的 template 中沒有包含一個 slot 元素,則該元件起始標籤和結束標籤之間的任何內容都會被拋棄

#預設內容

預設內容會在沒有提供內容的時候被渲染。只需要將內容放在slot中:

//在一個子元件的template中
<button>
  <slot>Submit</slot>
</button>
//1. 父級中沒有新增任何內容
<submit-button></submit-button>
//   渲染後備內容:
<button>Submit</button>
//2. 父級中有內容
<submit-button>Save</submit-button>
//   後備內容會被取代:
<button>Save</button>

#具名插槽

當我們需要多個插槽時,具名插槽很有用:

  1. 元件模板中,給slot新增name屬性

    //假設這是base-layout元件的模板,需要分別給header、main、footer新增插槽:
    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot> //這個插槽沒有名字,name的值預設為default
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    
  2. 父級中,用帶有v-slottemplate包裹內容,v-slot指定插槽名稱

    <base-layout>
      <template v-slot:header>
        <h1>I am a header</h1>
      </template>
    
      //任何沒有按規定包裹的內容都會被視為預設插槽的內容
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    
      <template v-slot:footer>
        <p>I am a footer</p>
      </template>
    </base-layout>
    

    v-slot可以縮寫:

    <template #header>
       <h1>I am a header</h1>
    </template>
    

#編譯作用域

插槽的作用域與例項相同。即能訪問到例項的資料,而不能訪問元件的資料

//可以訪問
<navigation-link url="/profile">{{ user.name }}</navigation-link>
//不可以訪問
<navigation-link url="/profile">{{ url }}</navigation-link>

#插槽作用域

如果想在父級插槽內容中訪問到子元件的資料

  1. 在子元件的slot中繫結資料

    Vue.component('user-info', {
        //user作為屬性繫結資料。在這裡user屬性被稱為插槽prop
        template: `<span><slot :user="userdata">{{userdata.current}}</slot></span>`,
        data:()=>({
            userdata:{
                before:'lihua',
                current:'xiaoming'
            }
        }),
    })
    
  2. v-slot 來定義插槽 prop 的名字。名字也可以是其他

    <user-info v-slot:default="slotProps">
        {{slotProps.user.before}}
    </user-info>
    

    由於指定的插槽是default,所以以上也可以簡寫成:注意不要與具名插槽混淆

    <user-info v-slot="slotProps">
        {{slotProps.user.before}}
    </user-info>
    

自 2.6.0 起有所更新。已廢棄的使用 slot-scope

# 動態插槽名

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

5. 動態元件

如果在一個多標籤介面實現元件切換,可以通過 Vue 的 <component> 元素加一個特殊的 is attribute 來實現::

<!-- 切換tab值 -->
<button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{tab}}</button>
<!-- 元件會在 `currentTabComponent` 改變時改變 -->
<component v-bind:is="currentTabComponent"></component>
Vue.component("com1", {
    template: "<div>com1</div>"
});
Vue.component("com2", {
    template: "<div>com2</div>"
});
Vue.component("com3", {
    template: "<div>com3</div>"
});

new Vue({
  el: '#app',
  data:{
    currentTab:"com1",
    tabs:["com1", "com2", "com3"]
  },
    computed: {
		//currentTabComponent可以是已註冊元件的名字,或一個元件的選項物件        
        currentTabComponent: function () {
            return this.currentTab
        }
    }
})