---
# System prepended metadata

title: Vue.js
tags: [Veu.js]

---

###### tags: `Veu.js`
# Vue.js


			
## Vue.js 運作從 MVVM 框架說起!

MVVM全名為 Model-View-ViewModel

M 代表 Model(存放資料)

V 代表 View(畫面顯示)

VM 稱作 ViewModel(資料與畫面互動)

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

View和 Model會藉由 ViewModel 來進行聯繫， ViewModel 透過雙向資料綁定來聯繫畫面與資料間的傳遞。

畫面改變時，會改變資料的狀態，資料狀態改變時，畫面也會跟著更動。
<br>
<br>
## New Vue

1. 引入 Vue.js
2. 建立一個變數，並且 new 一個 Vue 物件
3. 建立el (element)並指定範圍
4. data 內存放變數資料
```htmlmixed=

<!-- 1. 引入 Vue.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.2/vue.js"></script>

<div id="app">
	<h1>{{message}}</h1>  <!--與new vue裡的message做綁定-->
	<input type="text" v-model="message"> <!--也可以做雙向綁定-->
	<p>{{score *2 +5}}</p>//也可以運算
</div>
```
```javascript=
// 2.new 一個 Vue 物件
new Vue({

	el:'#app',//3.與標籤做綁定，不能綁body

	data:{ //4.變數都放這邊
		message: 'Hello VueJS!',
		score: 80,
	}

})


```

<br><br><br>
## v-text
除了用{{}}，還可以透過v-text綁定DOM元素
```htmlmixed=
<div id="app">
  <p v-text="message"></p>
</div>
```

```javascript=
var app = new Vue({
	el:'#app',//與標籤做綁定，不能綁body
	data:{ //變數都放這邊
		message: 'Hello VueJS!',
	}
})
```

</br></br>
## v-html
將標籤插入dom，類似javascript的innerHTML
```htmlmixed=
<div id="app">

	//v-html 綁定data裡的img
	<div v-html="img"></div>
	
</div>
```

```javascript=
new Vue({
  el: "#app",
  data: {
  	//img裡必須放的是html標籤的字串
	img: "<img src='https://i.imgur.com/iVSMcsv.png'>"
  }
});
```
</br></br>
## V-show<br>


可決定DOM元素是否顯示，使用的技術是display：none<br>
用法：  再標籤上加v-show=""data裡面需要綁定true or false
```htmlmixed=
<div id="app">
	<p v-show="loading">載入</p>
</div>
```
```javascript=
var app = new Vue({
	el:'#app',//與標籤做綁定，不能綁body
	data:{ //變數都放這邊
		loading: true,
	}
})
```

</br></br>
## v-if
HTML上的判斷式<br>
用法：  再標籤上加v-if=""

```htmlmixed=
<div id="app">
	<h1>輸入你的分數</h1>
	<input type="text" v-model="score"> //與score雙向綁定
	<p v-if="score > 70">Pass !</p> 
	<p v-else>Not Pass !</p>
</div>
```
```javascript=
var app = new Vue({
	el:'#app',//與標籤做綁定，不能綁body
	data:{ //變數都放這邊
		score: 0,
	}
})
```
</br></br>
## v-for
在HTML上跑回圈，動態產生DOM元素<br>
用法：  再標籤上加v-for=""
```htmlmixed=
<div id="app">
    <ul>
        //v-for裡格式 索引值 in 陣列，標籤裡用大括號包索引值
        <li v-for="color in colors">{{color}}</li>
    </ul>
    <ol>
        <li v-for="member in classmate">{{member.name}}-{{member.age}}</li>
    </ol>
</div>
```
```javascript=

var app = new Vue({
el:'#app',
  data:{
    colors: ['red','orange','yellow','green','blue','indigo','violet'],
    classmate: [{name:'Anan',age:16},{name:'Bella',age:18},{name:'Cathy',age:15},{name:'Dale',age:23}],
  }
})

```
</br></br>
## 進階用法 v-if & v-for
v-if 與 v-for 搭配使用
在第一個v-if上加上 v-for
```htmlmixed=
<p v-for="peopel in classmate" v-if="peopel.age > 18">{{peopel.name}}年紀大於18</p>
<p v-else-if="peopel.age < 18" >{{peopel.name}}年紀小於18</p>
<p v-else>{{peopel.name}}剛好18</p>
```
```javascript=
javascript 延續上一個 v-for 的 new vue
```
## v-bind
HTML上的屬性值，透過v-bind從Vue取得 ex：class、id。<br>
用法：  再屬性值上加 v-bind:
```htmlmixed=
<div id="app">
   <img v-bind:src="imgURL">
   <input type="text" v-bind:placeholder="message"> //v-bind可以縮寫成":"	
</div>
```
```javascript=
var app = new Vue({
   el:'#app',
   data:{
      message: 'Hello VueJS!',
      imgURL: '../img/img.png',
	}
 })

```
</br></br>
## v-on、methods
再HTML上綁定監聽事件<br>
用法： v-on:click="function"
```htmlmixed=
<div id="app">
	<ul>
		<li v-for="member in classmate" v-on:click="showData(member.name)">{{member.name}}</li>
		<li v-for="member in classmate" @click="showData(member.name)">{{member.name}}</li>
	</ul>
</div>
```
```javascript=

var app = new Vue({
   el:'#app',
   data:{
      classmate: [{name:'Anan',age:16},{name:'Bella',age:18},{name:'Cathy',age:15},{name:'Dale',age:23}],
   },
   methods:{//裡面都是放function
      showData(data){
         alert(data);
      }
   },
})


```
</br></br>
## this

this 通常在JavaScript裡通常只的是外層物件，所以再Vue function裡 通常指的是Vue這個物件
```htmlmixed=
<div id="app">
	<h1 @click="showThis()">showThis!!!</h1>
</div>
```
```javascript=

var app = new Vue({
   el:'#app',
   data:{
      message: 'Hello VueJS!',
   },
   methods:{
      showThis(){ 
         alert(this);// 再這邊alert出來會是物件
         alert(this.message); // Hello VueJS!
         alert(this.$data); // Hello VueJS!
      },
   },
 })


```

## computed
函數也可以放這裡! 但是放在這裡的函數不能傳參數，一定要有傳回值(return value)
```htmlmixed=
<div id="app">
	<h1>現在時間{{now}}</h1>
</div>
```
```javascript=

var app = new Vue({
   el:'#app',
   data:{
      height: 0,
      weight: 0,
   },
   methods:{
	
   },
   computed:{//不能傳參數，一定要有傳回值
      now(){
	  
         let today = new Date();
         return today.toTimeString();
		 
      },
      calculate(){
	  
         let BMI = this.weight / Math.pow((this.height / 100), 2);
         return BMI.toFixed(2);
		 
      },
   },
 })

```
</br></br>
## v-bind綁定class
透過v-bind 動態綁定class	
```css=
CSS

.theButton{
	background: #23c423;
	border: 0px ;
	color: #fff;
	border-radius: 5px;
	padding: 2px 5px;
}

.change{
	background: #888;
}
```

```htmlmixed=
<div id="app">  <!--HTML DOM template-->
    <input v-model="message">
	
	//：class 的btnClass從computed來
    <button v-bind:class="btnClass">Click me!</button>
</div>  
```

```javascript=

var app = new Vue({
   el:'#app',
   data:{
      message:'',
   },
   methods:{
	
   },
   computed:{//不能傳參數，一定要有傳回值
      btnClass(){
		
         // 方法1.回傳字串
         if(this.message == 0){
            return 'theButton change';
         }else{
            return 'theButton',
         }
			
         //方法2.回傳物件
         if(this.message == 0){
            return {
               theButton:true,
               change:true,
            };
         }else{
            return {
               theButton:true,
               change:false,
            };
         }
			
         //方法3.回傳物件"精簡版"
         return{
            theButton:true,
            change:this.message == 0,
         },
   },
 })

```
<br><br>
## toggle class
主要透過vue data布林值來控制class
```css=
.red{
  background-color: red;
}

.blue{
  background-color: blue;
}

a{
  display: block;
  width: 100px;
  height: 100px;
  border: 1px solid;
  margin-top: 50px;
}
```
```htmlmixed=
<div id="app">

  //＠click 主要反轉布零值
  <button @click="add_blue = !add_blue">toggle</button>
  
  //以下會看見兩個class，仔細看會發現一個是原生的，一個是從vue來的
  <a class="red" :class="{blue : add_blue}"></a>
  
</div>

```
```javascript=
new Vue({
  el: '#app',     //el: document.getElementById('app'),
  data: {         //變數都放這裡
      add_blue: false
  },
});
```
<br><br>
## v-bind綁定style
透過v-bind 動態綁定、修改style的值
```htmlmixed=
<div id="app">  <!--HTML DOM template-->
	<p>
		<button @click="shrink">縮小</button>
		<button @click="zoom">放大</button>
		<div :style="textChange">Lorem ipsum dolor sit amet.</div>
	</p>
</div>  
```

```javascript=

var app = new Vue({
	el:'#app',
	data:{
		size: 16,
	},
	methods:{
		shrink(){
			this.size -=2;
		},
		zoom(){
			this.size +=2;
		},
	},
	computed:{//不能傳參數，一定要有傳回值
		textChange(){
			return{
				fontSize:`${this.size}px`,
				color:'blue',
				textDecoration: 'underline',
			}

		};
	}
 })

```
## 表單處理
多個選單選扭綁定
```htmlmixed=
<div id="app">  <!--HTML DOM template-->
        <input type="radio" v-model="gender" value="male">Male
        <input type="radio" v-model="gender" value="female">Female
        <input type="radio" v-model="gender" value="others">Others
</div>  
```

```javascript=

var app = new Vue({
	el:'#app',
	data:{
		gender:'male',//一開始預設選擇會是male
	},
	methods:{
		
	},
	computed:{//不能傳參數，一定要有傳回值
		
	}
 })

```

## 表單處理-多選
將多選鈕的值，透過v-model放進陣列後雙向綁定渲染到Dom
```htmlmixed=
<div id="app">
	//v-model=""綁定interest，若勾選  會把資料送進綁定interest裡
	<input type="checkbox" v-model="interest" value="read">閱讀
	<input type="checkbox" v-model="interest" value="sleep">睡覺
	<input type="checkbox" v-model="interest" value="game">電動
	<input type="checkbox" v-model="interest" value="diving">潛水

	<p>{{interest}}</p>

	<input type="checkbox" v-model="agree">同意
</div>
```

```javascript=
new Vue({           //Vue instance(實例)
    el: '#app',     
    data: {
        interest: [],
        agree: false,
    },
    methods: {

    },
    computed: {
        
    },
});
```

## 表單處理-下拉式選單
使用v-model 、 v-for來產生日期下拉式選單
```htmlmixed=
<select v-model="selectedYear">
	<option v-for="year in years">{{year}}</option>
</select>

<select v-model="selectedMonth">
	<option v-for="month in 12">{{month}}</option>
</select>

<select v-model="selectedDate">
	<option v-for="day in 31">{{day}}</option>
</select>
```

```javascript=
new Vue({
	el: '#app',     
	data: {  
		years: [2016,2017,2018,2019,2020,2021,2022], //3
		selectedYear: new Date().getFullYear(),
		selectedMonth: new Date().getMonth() + 1,
		selectedDate: new Date().getDate(),
	},
});
```
表單處理-檔案
```htmlembedded=
<div id="app">
   <input type="file" @change="selectedFile">
   <p>{{image}}</p>
   <img :src="image">
</div>  
```

```javascript=
new Vue({           //Vue instance(實例)
	el: '#app',     
	data: {  
		image: '',
	},
	methods: {
		selectedFile(e){
			let file = e.target.files[0];

			let readFile = new FileReader();
			readFile.readAsDataURL(file);

			readFile.addEventListener('load',this.loadImage);
		},
		loadImage(e){
			this.image = e.target.result;
		},
	},
});
```

## v-model 修飾符
lazy: blur時才觸發事件
number:  parseInt()  將字串轉成整數值 ex 20px ===> 20
但1234.567 ===> 1234.567
但aaa123bb ===> aaa123bb
trim: 清除兩側空白
```htmlmixed=
<div id="app">  <!--HTML DOM template-->
   Message: <input v-model="message">
   <h1>{{message}}</h1>

   Message: <input v-model.lazy="message">
   <h1>{{message}}</h1>

   Number: <input v-model.number="num">
   <h1>{{num}}</h1>

   Name: <input v-model.trim="name">
   <h1>{{name}}</h1>
</div>  
```
```javascript=
new Vue({           //Vue instance(實例)
	el: '#app',     
	data: {  
		message: '',
		num: 0,
		name: '',
	},
	methods: {},
});
```
</br></br>
## 生命週期
如同生物一般， Vue 的實體物件從建立、掛載、更新，到銷毀移除，這一連串的過程，我們將它稱作生命週期。 在這個過程中， Vue.js 提供了開發者在這些週期階段做對應處理的 callback function， 這些 callback function 我們就稱它叫生命週期的 Hooks function。</br>

![](https://i.imgur.com/QnFTH6x.png)
```htmlmixed=
<div id="app">  <!--HTML DOM template-->
  <button @click="count++"> +1 </button>
  <button id="deleteButton"> Delete </button>
  <h1>{{count}}</h1>
</div>   
```
```javascript=
let vm = new Vue({    //Vue instance(實例)
	el: '#app',     
	data: {  
		count: 0,
	},
	methods: {
	
	},
	beforeCreate() {//整個New Vue未產生之前
		
		//這時候this.count 還未出生
		console.log(`beforeCreate() --> count: ${this.count}`);
		
	},
	created() { //New Vue產生，通常ajax都會掛在這邊
	
		//此時count 已經出世
		console.log(`created() --> count: ${this.count}`);
		
		//但＄el還沒出生
		console.log(`created() --> $el: ${this.$el}`);
		
	},
	beforeMount() {  //mount 掛載前
	
		//此時$el出生拉 ！
		console.log(`beforeMount() --> $el: ${this.$el}`);
		
	},
	mounted() { //已將new vue掛載到dom
	
		console.log(`mounted() --> $el: ${this.$el}`);
		
	},
	beforeUpdate() {//dom元素更新之後，會依序跑beforeUpdate、updated
	
		console.log(`beforeUpdate() --> count: ${this.count}`);
		
	},
	updated() {//dom元素更新之後，會依序跑beforeUpdate、updated
	
		console.log(`updated() --> count: ${this.count}`);
		
	},
	beforeDestroy() {  //銷燬前
	
		console.log(`beforeDestroy() --> count: ${this.count}`);
		
	},
	destroyed() {	//new vue 銷燬
	
		console.log(`destroyed() --> count: ${this.count}`);
		
	},
});

```
</br></br>
## 偵聽器Watch
watch主要用來監聽data與computed變化

```htmlmixed=
<div id="app">  <!--HTML DOM template-->
	<input v-model.lazy="num">
	<h2>{{numSquare}}</h2>
</div>
```

```javascript=
let vm = new Vue({    //Vue instance(實例)
  el: '#app',
  data: {  
    num: 0,
    message: '',
  },
  methods: {},
  computed: {
    numSquare(){
      return Math.pow(this.num, 2);
    },
  },
  watch: { //偵聽器:主要用來偵聽data和computed的變化
      // 1.宣告成方法
      // num(newNum,oldNum){
      //  console.log(`num: ${oldNum} ---> ${newNum}`);
      // },
    numSquare(newValue,oldValue){
      console.log(`numSquare: ${oldValue} ---> ${newValue}`);
    },
    message(newMsg,oldMsg){
      console.log(`message: ${oldMsg} ---> ${newMsg}`);
    },  
	
    // 2.宣告成物件 
    num: {
	
    handler(newNum,oldNum){ //handler是內定的function name
        console.log(`num: ${oldNum} ---> ${newNum}`);
    },
    immediate: true,    //false by default,當Vue instance一建立立刻執行watch
    deep: true,         //false by default,見下一個程式
    },
  },
});
```
</br></br>
## 使用v-for來操作陣列、物件
```htmlmixed=
<div id='app'>
   <button @click="run">button</button>
   <ul>
   
      // arr第一種寫法
      <li v-for='value in array'>{{value}}</li>
      // arr第二種寫法，()可以在取到index
      <li v-for='(value,index) in array'>index: {{index}} / value: {{vaule}}</li>
		
      // obj第一種寫法
      <li v-for="vlaue in obj">{{value}}</li>
      // obj第二種寫法，()可以取到key
      <li v-for="(value , key) in obj">key: {{key}} / value: {{value}}</li>
	  
  </ul>
</div>
```

```javascript=
new Vue({
  el:'#app',
  data:{
    array:[1,2,3,4,5,6,7,8,9],
    obj:{
      x: 5,
      y: 10,
      z: 15,
    },
  },
  methods:{
    run(){
      //push
      this.array.push(this.array.length + 1)
      
      //filter
      this.array = this.array.filter(function(data){
        return data % 2 == 0 ;
      })
	  
      //filter Arrow function
      this.array = this.array.filter(data => data % 2 ==0)
	  
	  //vue增加屬性、屬性值  必須用＄set
      this.$set(this.obj,'A',20)
    },
  },
})
```

## component組件
把重複、共用的結構拆開來，避免一樣的事情重複做
```htmlmixed=
<div id="app">
   //此處並不是真正的html標籤，而是VUE讀到後渲染上來
   <my-component></my-component>     
</div>
```

```javascript=


//註冊一個component，括號裡第一個參數是組件名稱，第二個就放data...，除了el  其他東西都可以放
Vue.component('my-component',{
   template:'<div>{{text}}</div>',
   data(){
      return{
         text:'組件內的data必須是function，return物件',
      }
   }
})

//組件必須先產生，才能夠掛載上去new vue，若new vue先產生
//會產生錯誤
new Vue({ 
   el:'#app',
   data:{},
})

```

</br></br>
## 動態切換組件
再button上監聽＠click事件，動態切換組件

```htmlmixed=
<div id="app">
	<button @click="content="list">List</button>
	<button @click="content="apply">Apply</button>
	<button @click="content="date">Date</button>
	
	//透過 component元素，去指定其屬性is進行v-bind
	<component :is="content"></component>
</div>
```

```javascript=
Vue.component('list',{
	template:`
		<ul>
			<li>HTML</li>		
			<li>CSS</li>
			<li>JavaScript</li>
			<li>jQuery</li>
			<li>HTML5</li>
			<li>VueJS</li>
		</ul>
	`
})

Vue.component('apply',{
	template:`
		<form>
			<textarea></textarea>
			<button>Submit</button>
		</form>
	`
})



Vue.component('date',{   
	template: `
		<p>
			<input type="checkbox"> Morning
			<input type="checkbox"> Afternoon
			<input type="checkbox"> Evening
		</p>
	`,
});

let vm = new Vue({   
	el: '#app',
	data: {
		content: 'list',
	},
});
```
</br></br>
## Keep Alive
當我們切換組件時，並操作dom元素後切換組件時，會發現dom上的資料被清空了

只要透過keep-alive把我們的組件包起來，切換組件時就可以保留當時的資料啦 ！！

```htmlmixed=
<div id="app">
	<button @click="content="list"> List </button>
	<button @click="content="apply"> Apply </button>
	<button @click="content="date"> Date </button>
	
	<keep-alive>
		<component :is="content"></component>
	</keep-alive>
	
	
</div>
```

</br></br>
##	資料從父層(New Vue)傳進子組件
當子組件的資料必須向赴層索取，必須透過props

```htmlmixed=
<div id="app">
   //方法一
   <my-component message="Hello" text="VueJS!"></my-component>
	
	//方法二  使用複合字
	<my-component the-message="Hello" the-text="VueJS!"></my-component>
	
</div>
```

```javascript=
Vue.component("my-component",{

  //使用props接收上層傳下的資料  子組件的tamplate才能使用


  //方法一 
  props:['message','text'],
  template:'<h1>{{message}} {{text}}</h1>',
  
  // 方法二  在template裡 必須使用camel case接收，不然會壞掉
  props:['the-message','the-text'],
  template:'<h1>{{theMessage}} {{theText}}</h1>',
})

new Vue({ 
  el:"#app",
  data:{
  },
})
```
</br></br>
## v-for動態綁定props - 陣列
使用v-for操作data裡的陣列，透過props傳到子組件
```htmlmixed=
<div id="app">
   //:the-text 是自定義的屬性
   <post v-for="message in messages" :the-text="message"></post>
</div>
```

```javascript=
let vm = new Vue({
   el:'#app',
   data:{
      messages: ['Hello', 'Props','World','!'],
   },
   components:{
      post:{
         props:['the-text'],
         template:`<h1>{{theText}}</h1>`,
      }
   },
})
```

## v-for動態綁定props 陣列-物件
使用v-for操作data裡的陣列中的物件，透過props傳到子組件
```htmlmixed=
<div id="app">
   //:the-text 是自定義的屬性
   <post v-for="text in messageObject" :the-text="text.message" :the-name="text.owner"></post>
</div>

```
```javascript=
let vm = new Vue({
   el:'#app',
   data:{
      messageObject: [
         {message: 'Hello',name: 'Andy'},
         {message: 'Props',name: 'Bella'},
         {message: 'World',name: 'Carl'},
      ],
   },
   components:{
      post:{
         props:['the-text','the-name'],
         template:`<h1>{{theName}} // {{theText}}</h1>`,
      }
   },
})

```
</br></br>
## v-for動態綁定props 陣列-物件 (進階用法)
```htmlmixed=
<div id="app">
   //進階用法的v-bind不能夠偷懶使用"："，直接v-bind='text'
   <post v-for="text in messageObject" v-bind="text"/>
</div>
```

```javascript=
let vm = new Vue({
   el:'#app',
   data:{
      messageObject: [
         {message: 'Hello',name: 'Andy'},
         {message: 'Props',name: 'Bella'},
         {message: 'World',name: 'Carl'},
      ],
   },
   components:{
      post:{
         //使用進階用法，可直接使用陣列物件的key props下來
         props:['message','name'],
         template:`<h1>{{message}}//{{name}}</h1>`,
      }
   }
})
```
</br></br>
## 使用$emit來傳送資料到父組件

父組件若需要向子組件拿取資料，必須透過$emit
```htmlmixed=
<div id="app">
   
   //這邊使用aaa來定義一個事件，透過這個事件來呼叫父組件的function
   <my-button @aaa="Parent"></my-button>
</div>
```

```javascript=
Vue.component("my-button",{
  template:'<button @click="click">Click Me !</button>',
  methods:{
    click(){
      //使用$emit()來跟aaa做綁定，綁定後才會知道Parent是什麼東西
      this.$emit('aaa');
		
      //帶參數
      this.$emit('aaa',100);
    },
  },
})

new Vue({ 
  el:"#app",
  methods:{
    Parent(x){
	 
      //無參數版
      alert('Parent');
		      
      //帶參數版
      alert(x);
		
    },
  },
}) 
```
</br></br>

## 子組件之間的溝通
若子組件還要互相傳遞資料、透過props $emit就顯得非常麻煩
所以透過event bus可以幫我們在子組件互相傳遞資料

```htmlmixed=
<div id="app">
 <my-button></my-button>
 <my-data></my-data>
</div>
```

```javascript=
//一開始必須let一個變數、並賦予他一個new vue
//這邊已bus來舉例
let bus = new Vue();


//透過這個組件的btn click+1 並把資料傳遞到另一個子組件
Vue.component('my-button',{
  template:"<button @click='click'>+1</button>",
  data(){
    return{
      count:0,
    }
  },
  methods: {
    click(){
      this.count ++;
		
      //count ++後，自定一個aaa事件，並把count傳遞出去
      bus.$emit('aaa',this.count)
    },
  },
})

Vue.component('my-data',{
  data(){
    return{
      num:0,
    }
  },
  template:"<h1>{{num}}</h1>",
  mounted() {
    //在生命週期的mounted 建立一個監聽aaa事件
    //監聽到aaa事件後，執行後面的functuon
    bus.$on('aaa', (x) => this.num = x);
  },
})

new Vue({
  el:"#app",
})
```