Vue組件使用入門實例及常見錯誤解決

定義Vue組件名的方式有兩種:

使用 kebab-case

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

當使用 kebab-case (短橫線分隔命名) 定義一個組件時,必須在引用這個自定義元素時使用 kebab-case,例如 <my-component-name>

使用 PascalCase

Vue.component('MyComponentName', { /* ... */ })

當使用 PascalCase (首字母大寫命名) 定義一個組件時,在引用這個自定義元素時兩種命名法都可以使用。
也就是說 <my-component-name><MyComponentName> 都是合法的。
注意,儘管如此,直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case 是有效的。

Prop 的大小寫 (camelCase 和 kebab-case)

HTML 中的特性名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲小寫字符。
這意味着當使用 DOM 中的模板時,camelCase (駝峯命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

在HTML 中,需要將組件的屬性 postTitle 改成 post-title。

<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>

重申一次,如果使用字符串模板,那麼這個限制就不存在了。
即直接可以在 template 字符串中使用 postTitle 屬性.

 Vue.component('blog-post3', {
    props: ['postTitle'],
    template: `
    <div class="blog-post">
      <p> {{ postTitle }}</p>
    </div>
    `
})

錯誤1: component lists rendered with v-for should have explicit keys.

// cosole警告提示: 
vue.js:640 [Vue tip]: <blog-post-list2 v-for="postdetail in postList">: 
component lists rendered with v-for should have explicit keys. 
See https://vuejs.org/guide/list.html#key for more info.

(found in <Root>)

錯誤原因: 沒有爲循環的每一個項提供唯一 key 屬性

解決辦法: 需要爲 每項提供一個唯一 key 屬性,找個key可以使用字符串數值類型的值。

這裏是Vue文檔中給他說明:

爲了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要爲每項提供一個唯一 key 屬性:

<div v-for="item in items" v-bind:key="item.id">
	<!-- 內容 -->
</div>

建議儘可能在使用 v-for 時提供 key attribute,除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴默認行爲以獲取性能上的提升。

因爲它是 Vue 識別節點的一個通用機制,key 並不僅與 v-for 特別關聯

不要使用對象或數組之類的非基本類型值作爲 v-for 的 key。請用字符串或數值類型的值。

錯誤2:[Vue warn]Duplicate keys detected: 1. This may cause an update error.

// cosole報錯: 
[Vue warn]: Duplicate keys detected: '1'. This may cause an update error.
 (found in <Root>)

錯誤原因: 因爲在測試中,使用的同一個數據,因此再多個列表中,屬性key存在重複。

解決辦法: 修改每個循環中的key,給key值加個前綴,讓其不要重複即可。

列表1: 
<blog-post-list 
    v-for="postdetail in postList" 
    v-bind:key="'list1-' + postdetail.id"
    v-bind:postdetail="postdetail"
></blog-post-list> 

列表2: 
<blog-post-list2 
    v-for="post2 in postList" 
    v-bind:key="'list2-' + post2.id"
    v-bind:post2="post2"
></blog-post-list2>

錯誤3: camelCased props need to use their kebab-case equivalents when using in-DOM templates

[Vue tip]: Prop "postdetail" is passed to component <Anonymous>, but the declared prop name is "postDetail". 
Note that HTML attributes are case-insensitive 
and camelCased props need to use their kebab-case equivalents when using in-DOM templates. 
You should probably use "post-detail" instead of "postDetail".

錯誤原因: 直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case (短橫線分隔命名) 是有效的

解決辦法: 修改

<!-- 有效的 -->
<blog-post3 
    v-for="post3 in postList" 
    v-bind:key="'list3-' + post3.id"
    v-bind:post-detail="post3"
></blog-post3>

<!-- 無效的,postDetail 必須使用短橫線分隔命名,即改成 post-detail即可  -->
<blog-post3 
    v-for="post3 in postList" 
    v-bind:key="'list3-' + post3.id"
    v-bind:postDetail="post3"
></blog-post3>

完整的代碼實例如下:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,height=device-height">
    <title>Vue組件</title>
    <!-- 引入vue文件 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <!-- 引入element樣式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- 引入element組件庫 -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
    <hr/>
    <!-- 通過 Prop 向子組件傳遞數據 -->
    <!-- 一個 prop 被註冊之後,在調用組件模板是,可以將數據作爲一個自定義的屬性傳遞進來 -->
    <strong>使用組件1: 直接在模板屬性中傳入數據</strong> 
    <blog-post title="My journey with Vue1" author="作者1"></blog-post>
    <blog-post title="My journey with Vue2" author="作者2"></blog-post>
    <blog-post title="My journey with Vue3" author="作者3"></blog-post>

    <hr/>
    <!-- 使用 v-bind 綁定數據,一個屬性綁定一次(比較繁瑣,不推薦) -->
    <strong>使用組件1: 使用 v-bind 綁定數據</strong> 
    <blog-post
      v-for="post in postList"
      v-bind:key="post.id"
      v-bind:title="post.title"
      v-bind:author="post.author"
    ></blog-post>

    <hr/>
    <!-- 使用 v-bind 綁定數據,直接綁定一個對象(減少綁定屬性次數,推薦) -->
    <!-- 同時,注意該屬性綁定的key,增加了前綴,防止在循序數據是時報key值重複問題 -->
    <strong>使用組件2: 綁定一個對象</strong> 
    <blog-post2 
        v-for="post2 in postList" 
        v-bind:key="'list2-' + post2.id"
        v-bind:post2="post2"
    ></blog-post2>

    <hr/>
    <!-- 使用 v-bind 綁定數據,直接綁定一個對象(減少綁定屬性次數,推薦) -->
    <!-- 同時,注意該屬性綁定的key,增加了前綴,防止在循序數據是時報key值重複問題 -->
    <!-- 注意直接在 DOM (即非字符串的模板) 中只能使用 kebab-case (短橫線分隔命名) 格式 -->
    <strong>使用組件3: 綁定一個對象, DOM 中使用必須使用 kebab-case 格式 </strong> 
    <blog-post3 
        v-for="post3 in postList" 
        v-bind:key="'list3-' + post3.id"
        v-bind:post-detail="post3"
    ></blog-post3>
</div>

<script>
    // 組件1:該組件通過 props 可以傳遞兩個屬性值 'title' 和 'author'
    Vue.component('blog-post', {
        props: ['title', 'author'],
        template: '<p> {{ author }} : {{ title }} </p>'
    })
    // 組件2: 又一個組件
    // 該組件不是傳遞一個字符串值,該傳遞一個對象。
    // 這樣可以直接在模板裏使用對象,而不必一個一個屬性的傳入
    Vue.component('blog-post2', {
        props: ['post2'],
        template: `
        <div class="blog-post">
          <p> {{ post2.author}} : {{ post2.title }} </p> 
        </div>
        `
    })
    // 組件3: 再來一個組件
    // 該組件定義一個 postDetail 屬性,注意在DOM中綁定屬性時要使用 "v-bind:post-detail"
    Vue.component('blog-post3', {
        props: ['postDetail'],
        template: `
        <div class="blog-post">
          <p>{{ postDetail.author }} : {{ postDetail.title }}</p>
        </div>
        `
    })

    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!',
            postList: [
              { id: 1, title: 'My journey with Vue', author: "Author111"},
              { id: 2, title: 'Blogging with Vue', author: "Author222"},
              { id: 3, title: 'Why Vue is so fun', author: "Author333"},
            ]
        },
        mounted() {
            this.prepareComponent();
        },
        methods: {
            prepareComponent() {
                console.log('hi, vue component mounted.');
            }
        }
    })
</script>
</body>
</html>

[END]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章