---
# System prepended metadata

title: Vue作品實戰班

---

# Vue作品實戰班
---
tags: Vue 實戰班
---
## 主課程
### 元件建立
- 為什麼需要元件?
    1. 避免單一個檔案過大
    2. 很多地方會用到的部分可以拉出來做重複使用，方便管理
    3. 元件的大小可依據範疇分類 views(整頁)/components(單一小區塊)
- 定義方式有什麼?
    ![](https://i.imgur.com/JBKw9s8.png)
    
     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 結構拉出來
     
     ![](https://i.imgur.com/SYAFAL5.png)
     
     ![](https://i.imgur.com/RPREyK3.png)



     ```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)
![](https://i.imgur.com/GyDeLkE.png)
```html=
<div id='app'>
<!--前面是名稱 後面是值-->
  <card outer='123'></card>
</div>
```
![](https://i.imgur.com/xfMFaQt.png =500x)

![](https://i.imgur.com/Jkudnb6.png =500x)
    
- 把 outer 傳進來，再賦予到 src 上面
![](https://i.imgur.com/aw6BPYo.png =500x)
- 把外部 img 傳到 outer 上的綁定方法，`:outer="img"`
![](https://i.imgur.com/JL83MNN.png)


- props有什麼限制?
     1.一旦傳入內層元件，內層元件不可以更改它的值(單向數據流)
     - 如果必須使用props的值，又需要更改，可以透過 created 存到 data 變數內
     ![](https://i.imgur.com/NiSBk1m.png)

     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
    	},
  	})
  	```
    
  ![](https://i.imgur.com/dMrTad5.png =400x)
  
  ![](https://i.imgur.com/YrDSSXk.png =400x)
  
  ![](https://i.imgur.com/iKv5STO.png =400x)
  [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)
    

---
![](https://i.imgur.com/J4ec9Bz.png)

- $emit事件是什麼?

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

    **外層**
    ![](https://i.imgur.com/jS4YdMX.png =500x)
    
    需要注意的是，不同於元件和 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 是跨元件傳遞。
    ![](https://i.imgur.com/xcTpTCC.png)
	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)