# Vue作品實戰班
---
tags: Vue 實戰班
---
## 主課程
### 元件建立
- 為什麼需要元件?
1. 避免單一個檔案過大
2. 很多地方會用到的部分可以拉出來做重複使用,方便管理
3. 元件的大小可依據範疇分類 views(整頁)/components(單一小區塊)
- 定義方式有什麼?

1. 全域元件
在整個Vue內其他元件都可以使用。可重複使用。
```javascript=
Vue.component('元件名稱',{
template: `html內容`
})
```
```html=
<div id='元件名稱'></div>
```
2. 區域元件
- 在任何元件下
- 在 #app 下也可以
- 只有當前註冊元件內才可以使用
```javascript=
var app = new Vue({
components: {
元件名稱:{
template: `html內容`,
}
}
})
```
- 元件模板應用方式
1. Template Literial
```javascript=
template: `html內容`
```
2.🌟 x-template
```html=
<script type="text/x-template" id="元件模板id">
html內容
</script>
```
- template: 中的程式碼可以拉出來,用 id 綁定,優點:可以把 html 結構拉出來


```javascript=
Vue.component('元件名稱',{
template: '#元件模板id'
})
```
```javascript=
//完整範例
//HTML
<card></card>
<div is="card"></div>
//下一行的寫法,意思同上一行,但兩個 data 是獨立的
//javascript
<script type="text/x-template" id="forCard">
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">{{ text }}</h5>
</div>
</div>
</script>
Vue.component('card',{
template: '#forCard'
})
```
3. vue file
共通重點:
> 元件下的模板最外層不可以有兩個節點(html element tag)
>
- 元件內 data 必須**使用 function 去傳送**
```javascript=
Vue.component('card',{
template: '#forCard',
//✨內層所有的 data 都必須使用 function return
data: function(){
return{
text: '這裡有一句話',
}
}
//以下為縮寫
data(){
return{
text: '這裡有一句話',
}
}
})
```
- import 的方式
```javascript=
//開一個 card.js 檔,寫入
export default{
template: '#forCard',
data: function(){
return{
text: '這裡有一句話',
}
}
}
//然後回 html 下的 script 區塊
import card2 from './card.js';
// body 內寫如下即可
<card2></card2>
```
- 呼叫 component 的2種方式
```javascript=
// 自定義標籤
<card></card>
// html 標籤
<div is="card"></div>
```
- 元件重點
- template
- data
- 雷點
```javascript=
//不能在外層暴露結構,也就是必須要有 div 包著 h5,否則會報錯
<script type="text/x-template" id="forCard">
<div>
<h5 class="card-title">{{ text }}</h5>
<h5 class="card-title">{{ text2 }}</h5>
</div>
</script>
```
- script type="module"
> ES module 可以匯入外部檔案。參考第二週的影片
### 🛠 學習方法
- 看過一次
- 動手做一次,並且寫成筆記
- 分享給其他人
### 元件資料傳遞
#### props是什麼?
- props是以資料形式,將資料由外層元件往內層元件傳遞
- 如果由內層元件到外層元件的資料傳遞,是以事件的形式傳遞資料($emit事件)
- 如果是同一層級的元件對元件,也是以事件的形式傳遞資料(\$on+$emit)

```html=
<div id='app'>
<!--前面是名稱 後面是值-->
<card outer='123'></card>
</div>
```


- 把 outer 傳進來,再賦予到 src 上面

- 把外部 img 傳到 outer 上的綁定方法,`:outer="img"`

- props有什麼限制?
1.一旦傳入內層元件,內層元件不可以更改它的值(單向數據流)
- 如果必須使用props的值,又需要更改,可以透過 created 存到 data 變數內

2. ~~首字一定要小寫,用大寫沒有用;但可以使用小寫駝峰命名法~~
查詢錄播 [第四週直播 - 下錄播14:57左右](https://courses.hexschool.com/courses/924133/lectures/22412010)
根據Vue官方文件的說明,如果不是使用Template Literial的方式撰寫Template時,props在html的attr上必須依循其不區分大小寫的限制(全部都會被當成小寫),不可使用camel-case(小寫駝峰)。
如果希望js環境內接值時,可以使用camel-case來接收,則html上的props attr必須使用kebab-case,如以下範例:
```html=
<mycomponent :product-list="something"></mycomponent>
```
```javascript=
Vue.component('mycomponent', {
template: '#mycomponentTemplate',
props: ['productList'],
data() {
return {}
},
created() {
console.log(this.productList) // something
},
})
```



[Ref. Vue.js Prop章節](https://cn.vuejs.org/v2/guide/components-props.html)
或是參考 [vue 官方 style guide](https://vuejs.org/v2/style-guide/#Prop-name-casing-strongly-recommended)
---

- $emit事件是什麼?

外到內是資料。內到外是事件
\$emit是以事件形式將資料由內層元件往外層元件推送傳遞。
內層元件使用$emit推到外層元件由事件接收
```javascript=
// 外層元件
// emit 推,外 methods 接收
// 心法口訣: 前內(emit),後外(method)
<card @pushsomething='getData'></card>
// 內層元件
methods:{
update(){
this.$emit('pushsomething', this.text)
}
}
```
**內層**

**外層**

需要注意的是,不同於元件和 props,$emit 不存在任何大小寫轉換,所以觸發的事件名稱,需要完全符合監聽這個事件所用的名稱。舉個例子,如果想觸發一個 camelCase (小駝峰) 名字的事件:
```javascript=
methods: {
update() {
this.$emit('myEvent')
// html 'E'會視為'e'讓 JS 讀不到, 可改用 myevent、my-event or my_event
}
}
```
則監聽這個名字的 kebab-case 版本是不會有任何效果的
```html=
<!-- 没有效果 無效! -->
<card @my-event="doSomething"></card>
```
不像元件和 props,事件名稱不會被用來當作一個 JS 的變數或 property 名稱,所以不需要使用駝峰式命名
[Ref. Vue.js $emit/自訂事件](https://cn.vuejs.org/v2/guide/components-custom-events.html)
- eventbus是什麼?
1. eventbus 是跨元件傳遞。

2. 利用bus的實體,以事件對事件的形式(完全不需要html屬性,只需要在\$emit和$on使用相同事件名稱即可),在同層級的元件傳遞資料
```javascript=
// 在外層先新增一個Vue實體
Vue.prototype.$bus = new Vue();
// card 1 (推資料)
Vue.component('card1',{
template:`<div @click='updateData'>{{text}}</div>`,
data(){
return {
text: 'card1的資料'
}
},
method(){
updateData(){
this.$bus.$emit('updateCard2', this.text)
}
}
})
// card 2 (收資料)
Vue.component('card2',{
template:`<div>{{anotherData}}</div>`,
data(){
return {
anotherData: '還未修改的資料'
}
},
created(){
// 接收
this.$bus.$on('updateCard2',function(para){
console.log('接收到的事件', para);
})
//如果想變更 this.anotherData 可以將函式改為箭頭函式
this.$bus.$on('updateCard2', para => {
console.log('接收到的事件', para)
this.anotherData = para
})
//updateCard2 為自訂名稱
//$bus 的缺點:很難除錯
}
})
```
由於eventbus使用相同名稱的事件名稱來傳遞,如果是在畫面上會重複出現的元件,就不建議使用這個方式做資料傳遞(有同樣接收器,無法區分是要傳遞給哪一個元件的資料),容易出錯。
使用時機:適合一對一的元件
### 元件生命週期
- 生命週期是什麼?
- 元件從建立到移除的過程。
- 如果想維持住生命週期,不希望元件重新循環生命週期,可使用`<keep-alive>`標籤包住
- 搭配 v-if 的問題 `<keep-alive>`
- 只有 v-if, v-for 才會觸發生命週期的事件, v-show 不會,v-show 是使用 display: none
- jQuery 為什麼會抓不到元素,mounted 後才抓得到元素
- 哪個重要:
1. created
- 資料建立之後
- 適合處理資料
2. mounted
- 元件渲染出html之後
- 適合處理 DOM
### 主線任務相關
1. 這禮拜一定要看影片才能順利做任務
2. 任務的登入驗證不用給帳號密碼
### 遇到困難的話...
#### 如果有以下情況
1. 看範例作品都會寫,蓋起來就不會
2. 老師直播時都懂,但要自己運用就卡卡的
3. 寫完作業好像失憶一般,再寫一次也不一定有把握
#### 請練習以下兩種方式
1. 寫自己的筆記
寫一次撰寫程式時,搭配筆記做紀錄
第二次撰寫的時候,只能看筆記
2. 練習拆解٩(ˊωˋ*)و✧
### 自閉合组件
- [HTML 并不支持自闭合的自定义元素](https://cn.vuejs.org/v2/style-guide/#%E8%87%AA%E9%97%AD%E5%90%88%E7%BB%84%E4%BB%B6%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90)