Vue-(十一)組件

11-1.Vue組件的註冊與使用(影片)

Vue 的組件(component)是Vue的強大功能之一,Vue 組件預先定義好模組內容,可包含html 的視覺元素、資料、偵聽器等等,將來模組就可以重複使用,方便在開發過程的時候聚焦於一小區塊功能,在維護也比較方便。

全域組件

  1. 首先用Vue.component()方法
  2. 第一個參數是component的名字(component 命名用全小寫以 dash 分隔)
  3. 第二個參數是一個物件,其中用 templete 的字串定義組件的視覺元素(直接定義html的內容)
  4. 有個重點! component的宣告必須在 vue 實例 new之前!
1
2
3
4
5
6
7
8
9
10
11
// Global component
Vue.component('my-component',{
template:'<div>Here is content in my-component</div>'
});

new Vue({
el:'#app1',
});
new Vue({
el:'#app2',
});
  1. 因為是Global component,所以在html中,可以不受限Vue實例範圍,就可以用<my-component></my-component>去使用自定義的component
1
2
3
4
5
6
<div id='app1'>
<my-component></my-component>
</div>
<div id='app2'>
<my-component></my-component>
</div>

區域組件

local component 只能在該 Vue 實例中被使用

  1. 首先new出一個 Vue 實例
  2. 定義其中的 compinents 屬性,值為一個物件
  3. 在該物件中用key pair 作component 的命名及內容定義
  4. 下方案例中,key字串my-component為該 component 的名字
  5. 再其中的 template 屬性用字串定義組件的視覺元素(直接定義html的內容)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Local component
    new Vue({
    el:'#app',
    components:{
    'my-component':{
    template:'<div>Here is content in my-component</div>',
    }
    }
    });
  6. 接下來在html中,就可以用<my-component></my-component>去使用自定義的component

    1
    2
    3
    <div id='app'>
    <my-component></my-component>
    </div>

11-2.DOM模板解析事項(影片)

HTML解析流程

假設將<option>tag中的<option>內容額外包成一個component,如下述的寫法:

  1. 首先,元素會先經過html瀏覽器的解析,再交給Vue實例使用。

    1
    2
    3
    4
    5
    6
    7
    Vue.component('my-component',{
    template:'<option>AAA</option>'
    });

    new Vue({
    el:'#app',
    })
  2. 所以一開始當html在解讀元素時,會因為解析到不合規範的標籤,而略過。
    在此例中,也就是說當html解讀到<select>,會預想接下來是<option>,然而卻得到<my-component></my-component>,因此被判定為不合法的情況,導致畫面無法正常如願顯示。

    1
    2
    3
    4
    5
    <div id='app'>
    <select>
    <my-component></my-component>
    </select>
    </div>

解決辦法:在templete中定義

讓瀏覽器在解讀html時,可以先略過該元素,將不合法的元素先移除,避免出現錯誤。因此:

  1. 僅給予一個元素,綁定 Vue實例

    1
    2
    <div id='app'> 
    </div>
  2. 讓html內容直接定義在templete中,避免經過html解析的流程

    1
    2
    3
    4
    new Vue({
    el:'#app',
    template:'<select><option>AAA</option><option>CCC</option></select>'
    })
  3. 綁定了Vue實例,抓取其中templete的內容,並作顯示

codepan-範例結果

類似使用時機

1
2
3
4
5
<ul>
<li></li>
<li></li>
...
</ul>
1
2
3
4
5
6
7
8
9
<table>
<tr/>
<td></td>
<td></td>
<td></td>
...
<tr/>
...
</ul>

11-3.data必須是函數(影片)

Vue 實例的data是一個物件,然而,Vue 組件的 data 必須是函數。這個設計邏輯的概念是,每呼叫使用一次組件,組件中的data應該是要各自獨立,所以用函數的方式可以每次都獨立新增一個獨立的data個體。

Vue實例,data共用

假設我需要有兩個計數器,若使用下述方法,因為data資料共用,所以兩個計數器的count會互相影響,無法獨立

1
2
3
4
5
6
new Vue({
el:'#app',
data:{
count:0,
}
})

1
2
3
4
5
6
<div id='app'>
<h1>{{count}}</h1>
<button @click='count+=1'>+click</button>
<h1>{{count}}</h1>
<button @click='count+=1'>+click</button>
</div>

善用組件,達到獨立data

將計數器功能拆分出來成為一個組件,Vue.component()等同於每次都會重新創造一個新的component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Vue.component('counter-component',{
data(){
return{
count:0,
}
},
template:`
<div>
<h1>{{count}}</h1>
<button v-on:click='count+=1''>+click</button>
</div>
`,
})

new Vue({
el:'#app',
})

即是多次呼叫<counter-component></counter-component>重複使用component,其中的data也會是各自獨立

1
2
3
4
<div id='app'>
<counter-component></counter-component>
<counter-component></counter-component>
</div>

最終的執行效果,會是兩個資料獨立的計數器

11-4.合體!組件組合(影片)

資料網內傳(父傳子)

  1. 定義最外層的 todo-list 組件
  2. 因為要將資料傳進內層資料,第11行使用自定義屬性:label='todo',意思是這裡獲取出的todo資料要以label(可以使用自定義其他命名)屬性往內傳,屆時內層可以用label取出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Vue.component('todo-list',{
    data(){
    return{
    todos:['a','b','c']
    };
    },
    template:`
    <div>
    <todo-input></todo-input>
    <ul>
    <todo-item v-for='todo in todos' :label='todo'></todo-item>
    </ul>
    </div>
    `
    });
  3. 定義to-item 組件

  4. 第2行定義屬性,代表外層會以label屬性傳入資料
  5. 第4行一樣可以用大括號取用資料

    1
    2
    3
    4
    5
    6
    Vue.component('todo-item',{
    props:['label'],
    template:`
    <li>{{label}}</li>
    `
    });
  6. 定義 todo-input 組件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Vue.component('todo-input',{
    data(){
    return{
    text:'',
    }
    },
    template:`
    <form>
    <input type='text' v-model='text'/>
    <button type='submit'>Submit</button>
    </form>
    `
    });
  7. new 出 Vue 實例

    1
    2
    3
    new Vue({
    el:'#app',
    })
  8. 撰寫html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <div id='app'>
    <todo-list></todo-list>
    </div>
    ```
    ### 資料往外傳(子傳父)
    欲將內層 todo-input 的資料,往外層 todo-list 傳遞
    ![](https://i.imgur.com/wkQ4vk9.png)


    7. 第14行`@submit.prevent='submit'`用意是讓提交事件不再重載頁面
    8. 重點在第9行,用`$emit`方法,定義透過這個事件傳資料至外層(父層)
    9. `$emit`方法的兩個參數,第一個代表自定義的事件命名`input`(自定義命名),第二個代表要傳遞的資料

    ```javascript=
    Vue.component('todo-input',{
    data(){
    return{
    text:'',
    }
    },
    methods:{
    submit(){
    this.$emit('input',this.text);
    this.text = '';
    },
    },
    template:`
    <form @submit.prevent='submit'>
    <input type='text' v-model='text'/>
    <button type='submit'>Submit</button>
    </form>
    `
    });
  9. 第14行,在外層(父層)templete的內層組件標籤中,用@input接受事件

  10. 在第8行,addToDo方法中的參數,就是內層傳來的資料,因此可以將之做後續處理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    Vue.component('todo-list',{
    data(){
    return{
    todos:['a','b','c']
    };
    },
    methods:{
    addTodo(text){
    this.todos.push(text);
    }
    },
    template:`
    <div>
    <todo-input @input='addTodo'></todo-input>
    <ul>
    <todo-item v-for='todo in todos' :label='todo'></todo-item>
    </ul>
    </div>
    `
    });
    ```
    結果呈現,[codepen成果](https://codepen.io/leah-lin/pen/gJjmmY)

    ## 11-5.動態組件組合[(影片)](https://hiskio.com/courses/145/lectures/5401)

    當我們在某個位置,需要有彈性地放置component,也就是說需要依據判斷值,決定該處要顯示哪個component時,則可以使用動態組件的寫法:

    1. 先創建多個conpoment,此案例中先創建了`lesson-component`以及`apply-component`這兩個組件
    2. 各自定義組件中的templete內容
    ```javascript=
    Vue.component('lesson-component',{
    template:`
    <div>
    <ul>
    <li>課程</li>
    <li>老師</li>
    <li>費用</li>
    </ul>
    </div>
    `,
    });

    Vue.component('apply-component',{
    template:`
    <form>
    <textarea></textarea>
    <button>Submit</button>
    <form>
    `
    })
  11. 創建完 component 之後,接著 new 出一個 Vue 實例

  12. Vue 實例中有一個 data 作為判斷依准,此案例中先以content作為判斷值,並且給予一個初始值

    1
    2
    3
    4
    5
    6
    new Vue({
    el:'#app',
    data:{
    content:'lesson-component',
    },
    })
  13. 接著在 html 中規劃視覺呈現,此案例中設計兩個按鈕,透過按鈕的 click 事件,下方空間會切換為不同的 component 的呈現

  14. 第4行中, :is判斷 content 當前的值,用來決定這裡要顯示什麼 component
    1
    2
    3
    4
    5
    <div id='app'>
    <button @click="content='lesson-component'">Lessons</button>
    <button @click="content='apply-component'">Apply</button>
    <component :is='content'></component>
    </div>

結果呈現,codepen成果

11-6.看不見但依舊存在的 keep-alive (影片)

接續11-5的動態組件,當前有兩個字定義的組件:lessons與apply,其中apply組件中是一個輸入框,假設在輸入框中先輸入訊息後,卻做了組件切換到lessons,之後再切換回apply時,會發現原先輸入的訊息會被清空。

如果希望當組件切換時,可以 keep 住訊息內容,則可以使用keep-alive標籤。
下方第4、6行就是用keep-alive標籤將第5行組件範圍包覆起來,讓組件中的內容可以不因組件切換而消失,反而會 keep 住訊息。

1
2
3
4
5
6
7
<div id='app'>
<button @click="content='lesson-component'">Lessons</button>
<button @click="content='apply-component'">Apply</button>
<keep-alive>
<component :is='content'></component>
</keep-alive>
</div>

結果呈現,codepen成果

11-7.組件命名學(影片)

1
2
3
4
5
6
// 三種命名方式
// 示範:my first component

my-first-component //kebab-case
myFirstComponent //camelCase
MyFirstComponent //PascalCase

在 html 中,只能使用 kebab-case 的命名法

  1. 假設在 Vue 中創建了一個組件,並使用「camelCase」的命名方式

    1
    2
    3
    4
    //vue.js
    Vue.component('myFirstComponent',{

    })
  2. 接著在html中呼叫使用組件,並需要轉換為「kebab-case」的命名方式才能夠辨識出組件

    1
    2
    3
    4
    <!-- html -->
    <div id='app'>
    <my-first-component></my-first-component>
    </div>

在 template 中使用,三種命名方式都可以

  1. 假設在 Vue 中創建了一個組件,並使用「camelCase」的命名方式

    1
    2
    3
    4
    //vue.js
    Vue.component('myFirstComponent',{

    })
  2. 在html中只是簡單綁定 Vue 實例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <div id='app'>
    </div>
    ```
    3. 接著在 Vue 實例中的 template 使用組件,此時要用何種命名方式都可以辨識
    ```javascript=
    new Vue({
    el:'#app',
    template:`
    <div >
    <myFirstComponent></myFirstComponent>
    </div>
    `
    })

補充:sefe-closing

  • 在 html 中,不能使用「self-closing tag 」, 僅能使用完整一組「star tag」+「end tag」

    1
    2
    3
    <div id='app'>
    <my-first-component></my-first-component>
    </div>
  • 不過在 template 中的字串模板,就可以使用「self-closing tag 」

    1
    2
    3
    4
    5
    6
    7
    8
    new Vue({
    el:'#app',
    template:`
    <div>
    <my-first-component/>
    </div>
    `
    })
© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero