從零開始的vue學習筆記(四)

組件註冊

  • 組件名
    Vue.component('my-component-name', { /* ... */ })
    這裏的my-component-name就是組件名,組件名的取法能夠參考指南
    • kebab-case寫法(-鏈接單詞) 推薦的寫法 定義:javascript

      Vue.component('my-component-name', { /* ... */ })

      用法:html

      <my-component-name></my-component-name>
    • PascalCase寫法(單詞首字母大寫)vue

      Vue.component('MyComponentName', { /* ... */ })
  • 全局註冊
    Vue.component('my-component-name', { /* ... */ })
  • 局部註冊
    先用一個普通的 JavaScript 對象來定義組件:
    var ComponentA = { /* ... */ }
      var ComponentB = { /* ... */ }
    而後在 components 選項中定義你想要使用的組件:
    new Vue({
      el: '#app',
      components: {
          'component-a': ComponentA,
          'component-b': ComponentB
      }
      })
    對於 components 對象中的每一個屬性來講,其屬性名就是自定義元素的名字,其屬性值就是這個組件的選項對象。
    注意局部註冊的組件在其子組件中不可用。例如,若是你但願 ComponentA 在 ComponentB 中可用,則你須要這樣寫:
    var ComponentA = { /* ... */ }
    
      var ComponentB = {
      components: {
          'component-a': ComponentA
      },
      // ...
      }
    或者若是你經過 Babel 和 webpack 使用 ES2015 模塊,那麼代碼看起來更像:
    import ComponentA from './ComponentA.vue'
    
      export default {
      components: {
          ComponentA
      },
      // ...
      }
  • 模塊系統
    經過 import/require 使用一個模塊系統
    • 模塊系統中局部註冊
    import ComponentA from './ComponentA'
      import ComponentC from './ComponentC'
    
      export default {
      components: {
          ComponentA,
          ComponentC
      },
      // ...
      }

prop

  • prop大小寫(camelCase vs kebab-case)
    HTML 中的特性(屬性)名是大小寫不敏感的,因此瀏覽器會把全部大寫字符解釋爲小寫字符,camelCase (駝峯命名法) 的 prop 名須要使用其等價的 kebab-case (短橫線分隔命名) 命名:java

    Vue.component('blog-post', {
      // 在 JavaScript 中是 camelCase 的
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
      })
    <!-- 在 HTML 中是 kebab-case 的 -->
      <blog-post post-title="hello!"></blog-post>

    所以,強烈建議kebab-case寫法。webpack

  • prop 類型
    一般,以字符串數組形式列出 prop:git

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

    可是,一般你但願每一個 prop 都有指定的值類型。這時,你能夠以對象形式列出 prop,這些屬性的名稱和值分別是 prop 各自的名稱和類型:github

    props: {
          title: String,
          likes: Number,
          isPublished: Boolean,
          commentIds: Array,
          author: Object,
          callback: Function,
          contactsPromise: Promise // or any other constructor
      }
  • 傳遞靜態或動態prop
    傳遞靜態值:web

    <blog-post title="My journey with Vue"></blog-post>

    傳遞動態值數組

    <!-- 動態賦予一個變量的值 -->
      <blog-post v-bind:title="post.title"></blog-post>
    
      <!-- 動態賦予一個複雜表達式的值 -->
      <blog-post
      v-bind:title="post.title + ' by ' + post.author.name"
      ></blog-post>

    實際上,能傳遞的值包括:字符串、數字、布爾值、數組、對象、對象全部屬性。瀏覽器

  • 單向數據流

    全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。

  • prop驗證

    Vue.component('my-component', {
          props: {
              // 基礎的類型檢查 (`null` 和 `undefined` 會經過任何類型驗證)
              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 ['success', 'warning', 'danger'].indexOf(value) !== -1
              }
          }
          }
      })

    上面的type能夠是原生構造函數的一個:StringNumberBooleanArrayObjectDateFunctionSymbol

  • 非 Prop 的特性
    一個非 prop 特性是指傳向一個組件,可是該組件並無相應 prop 定義的特性。

    • 替換/合併已有的特性
      對於絕大多數特性來講,從外部提供給組件的值會替換掉組件內部設置好的值,classstyle 特性會稍微智能一些,即兩邊的值會被合併起來。
    • 禁用特性繼承
      組件的選項中設置 inheritAttrs: false ,適合配合實例的 $attrs 屬性使用:
      Vue.component('base-input', {
          inheritAttrs: false,
          props: ['label', 'value'],
          template: `
              <label>
              {{ label }}
              <input
                  v-bind="$attrs"
                  v-bind:value="value"
                  v-on:input="$emit('input', $event.target.value)"
              >
              </label>
          `
          })

自定義事件

  • 事件名
    不一樣於組件和 prop,事件名不存在任何自動化的大小寫轉換。而是觸發的事件名須要徹底匹配監聽這個事件所用的名稱:

    this.$emit('myEvent')

    則監聽這個名字的 kebab-case 版本是不會有任何效果的:

    <!-- 沒有效果 -->
      <my-component v-on:my-event="doSomething"></my-component>

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

  • 自定義組件的 v-model

    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)"
          >
      `
      })
    <base-checkbox v-model="lovingVue"></base-checkbox>
  • 將原生事件綁定到組件
    使用 v-on 的 .native 修飾符:

    <base-input v-on:focus.native="onFocus"></base-input>

    Vue 提供了一個 $listeners 屬性,它是一個對象,裏面包含了做用在這個組件上的全部監聽器。能夠配合 v-on="$listeners" 將全部的事件監聽器指向這個組件的某個特定的子元素。

    Vue.component('base-input', {
      inheritAttrs: false,
      props: ['label', 'value'],
      computed: {
          inputListeners: function () {
          var vm = this
          // `Object.assign` 將全部的對象合併爲一個新對象
          return Object.assign({},
              // 咱們從父級添加全部的監聽器
              this.$listeners,
              // 而後咱們添加自定義監聽器,
              // 或覆寫一些監聽器的行爲
              {
              // 這裏確保組件配合 `v-model` 的工做
              input: function (event) {
                  vm.$emit('input', event.target.value)
              }
              }
          )
          }
      },
      template: `
          <label>
          {{ label }}
          <input
              v-bind="$attrs"
              v-bind:value="value"
              v-on="inputListeners"
          >
          </label>
      `
      })
  • .sync 修飾符
    update:myPropName 的模式觸發事件

    this.$emit('update:title', newTitle)
    <text-document
      v-bind:title="doc.title"
      v-on:update:title="doc.title = $event"
      ></text-document>

    縮寫:

    <text-document v-bind:title.sync="doc.title"></text-document>

    同時設置多個 prop :

    <text-document v-bind.sync="doc"></text-document>

插槽

  • 插槽內容

    <navigation-link url="/profile">
      Your Profile
      </navigation-link>

    <navigation-link> 的模板中:

    <a v-bind:href="url" class="nav-link">
      <slot></slot>
      </a>

    Your Profile會替換<slot></slot>部分。Your Profile能夠是HTML代碼或者其餘插件。

  • 編譯做用域
    父級模板裏的全部內容都是在父級做用域中編譯的;子模板裏的全部內容都是在子做用域中編譯的。

    <navigation-link url="/profile">
      Clicking here will send you to: {{ url }}
      <!--
      這裏的 `url` 會是 undefined,由於 "/profile" 是
      _傳遞給_ <navigation-link> 的而不是
      在 <navigation-link> 組件內部定義的。
      -->
      </navigation-link>
  • 後備內容(默認值)

    <button type="submit">
        <slot>Submit</slot>
      </button>

    這裏的Submit就是默認值。

  • 具名插槽
    <slot> 元素有一個特殊的特性:name。這個特性能夠用來定義額外的插槽:

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

    一個不帶 name<slot> 出口會帶有隱含的名字「default」。
    在一個 <template> 元素上使用 v-slot 指令,並以 v-slot 的參數的形式提供其名稱:

    <base-layout>
      <template v-slot:header>
          <h1>Here might be a page title</h1>
      </template>
    
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    
      <template v-slot:footer>
          <p>Here's some contact info</p>
      </template>
      </base-layout>
  • 做用域插槽
    綁定在 <slot> 元素上的特性被稱爲插槽 prop。如今在父級做用域中,咱們能夠給 v-slot 帶一個值來定義咱們提供的插槽 prop 的名字:

    <current-user>
      <template v-slot:default="slotProps">
          {{ slotProps.user.firstName }}
      </template>
      </current-user>
    • 獨佔默認插槽的縮寫語法

      <current-user v-slot:default="slotProps">
          {{ slotProps.user.firstName }}
        </current-user>
    • 解構插槽 Prop

      <current-user v-slot="{ user }">
          {{ user.firstName }}
        </current-user>
  • 動態插槽名

    <base-layout>
      <template v-slot:[dynamicSlotName]>
          ...
      </template>
      </base-layout>
  • 具名插槽的縮寫

    (v-slot:) 替換爲字符 #

  • 其它示例(略)

動態組件&&異步組件

  • 在動態組件上使用 keep-alive
    曾經在一個多標籤的界面中使用 is 特性來切換不一樣的組件:

    <component v-bind:is="currentTabComponent"></component>

    能夠用一個 <keep-alive> 元素將其動態組件包裹起來,避免切換的時候從新渲染:

    <!-- 失活的組件將會被緩存!-->
      <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
      </keep-alive>
  • 異步組件(略)

處理邊界狀況

這些特殊場景和危險狀況須要留心~

  • 訪問元素 & 組件

    • 訪問根實例
      $root屬性
    • 訪問父級組件實例
      $parent屬性
    • 訪問子組件實例或子元素
      ref特性
    • 依賴注入
      新的實例選項:provideinject
  • 程序化的事件偵聽器

    • 經過 $on(eventName, eventHandler) 偵聽一個事件
    • 經過 $once(eventName, eventHandler) 一次性偵聽一個事件
    • 經過 $off(eventName, eventHandler) 中止偵聽一個事件
  • 循環引用

    • 遞歸組件
    • 組件之間的循環引用
  • 模板定義的替代品

    • 內聯模板
    • X-Template
  • 控制更新

    • 強制更新
      $forceUpdate
    • 經過 v-once 建立低開銷的靜態組件
相關文章
相關標籤/搜索