---
# System prepended metadata

title: Vue JS 2 Tutorial part 1
tags: ['Javascript, Vue.js']

---

#  Vue JS 2 Tutorial part 1

###### tags: `Javascript, Vue.js`


# Introduction

## What is Vue.js

* 前端框架
* 可以創造以JS引擎為主的網頁APP
* 在瀏覽器中使用
* 不需要為了重整頁面，跑伺服器端

## Why Vue.js

* 非常輕量
* 高執行期表現

## Installation

建議把script放在body tag內

[CDN 連結](https://vuejs.org/v2/guide/installation.html)

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


## Before You Start

前置知識:

JavaScript
HTML(&CSS)


# Vue Instance

Vue實體做的事情:

1. 控制整個app功能或是部分元件的功能
2. 儲存不同的功能在option裡面像是data, methods
3. 控制template並呈現在DOM上


我們使用在html上面的tag並不會直接被使用，而是Vue.js會創造一個template並且是JS的格式並連接我們想要呈現的data並且結果會以html程式碼的方式呈現最後呈現到HTML DOM上面


## 範例

```javascript=

// 這個部分就是Vue實體

new Vue({
    el: '#vue-app',
    data: {
        name: 'Shaun',
    }
});
```

```htmlembedded=
<body>

<div id="vue-app">
        <h1>{{name}}</h1>
</div>

</body>
```

印出結果:
![](https://i.imgur.com/Bk8iiR0.png)


# Data & Methods



```javascript=
new Vue({
    el: '#vue-app',
    data: {
        name: 'Shaun',
        job: 'Ninja'
    },
    methods: {
        greet: function (time) {
            return 'Good' + time + ' ' + this.name;
        }
    }
});
```

```htmlembedded=
<div id="vue-app">
        <h1>{{greet(' afternoon')}}</h1>
        <p>name: {{name}}</p>
        <p>job: {{job}}</p>
</div>
```

## data

data的操作不需要做`this.data.name`

而是可以直接取得name或是job

`this.name`
`this.job`


## Methods

1. 可以在內部定義函式，並且return 的內容可以包含data
1. 使用this取得Vue實體後並操作返回的內容
2. 呼叫的方式`<h1>{{greet()}}</h1>`並可以在內部輸入參數


* 需要注意的點

位於Vue實體外面的`{{}}`是無法操作的要注意！


# Data Binding

## v-bind

把資料綁定上特定的html tag讓其可以讀取Vue實體內部的改動


新增一個website的data內容
```javascript=
new Vue({
    el: '#vue-app',
    data: {
        name: 'Shaun',
        job: 'Ninja',
        website: 'http://www.google.com'
    },
    methods: {
        greet: function (time) {
            return 'Good' + time + ' ' + this.name;
        }
    }
});
```

* 如果要綁定tag的屬性的話則必須使用v-bind:並且在要使用的data要使用雙引號包裹住
* 也可以使用縮寫 :href 這樣使用也可以喔
```htmlembedded=
<div id="vue-app">
        <h1>Data Binding</h1>
        <a v-bind:href="website">Google</a>
</div>
```

就可以綁訂在a tag上面的屬性搂!(但不只是href可以綁定其他屬性也可以)
![](https://i.imgur.com/KbyOIf1.png)


* 這邊示範綁訂在input的value屬性上面並且呈現出data裡面的name的值呈現在DOM上

```htmlembedded=
<div id="vue-app">
        <h1>Data Binding</h1>
        <a v-bind:href="website">Google</a>
        <input type="text" v-bind:value="name">
</div>
```

印出結果會把Shaun 放在value的位置
![](https://i.imgur.com/LqFofet.png)


## v-html

如果想要綁定完整的html tag上去DOM上面可以使用

```javascript=
<div id="vue-app">
        <p v-html="websiteTag"></p>
</div>
```


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        websiteTag: '<a href= "http://www.google.com">GOOGLEWEBSITE</a>'
    }
});
```

印出結果就會讓a tag 出現在 p tag內部

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


# Events

## v-on:click

使用v-on可以綁定事件，範例處我們使用click當範例:
* 當點擊add按鈕，年齡會加一
* 當點擊substract按鈕，年齡會減一

```htmlembedded=
<div id="vue-app">
        <h1>Events</h1>
        <button v-on:click="add">Add a Year</button>
        <button v-on:click="substract">Subtract a Year</button>
        <p>My age is {{age}}</p>
</div>
```


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        age: 25,
    },
    methods: {
        add: function () {
            this.age++;
        },
        substract: function () {
            this.age--;
        }
    }
});
```

![](https://i.imgur.com/ypn2jza.gif)


### 作者提醒

* 要特別注意寫在當v-on在呼叫函式的時候，add()，不需要加上括號!!(但要使用參數時，一樣可以使用括號)
* 但是使用在tempalte內部的{{test()}}則要使用括號


## v-on:dblclick

* 雙擊按鈕會年齡加10/減10

這邊不需要再加入新的方法，因此我們修改方法內容加入以參數的方式讓年齡依我們想要的年份更動

```javascript=
<div id="vue-app">
        <h1>Events</h1>
        <button v-on:click="add(1)">Add a Year</button>
        <button v-on:click="substract(1)">Subtract a Year</button>
        <button v-on:dblclick="add(10)">Add a Year</button>
        <button v-on:dblclick="substract(10)">Subtract a Year</button>
        <p>My age is {{age}}</p>
</div>
```

```java=
new Vue({
    el: '#vue-app',
    data: {
        age: 25,
    },
    methods: {
        add: function (inc) {
            this.age += inc;
        },
        substract: function (dec) {
            this.age -= dec;
        }
    }
});
```

## v-on:mousemove

* 可以使用mouse相關的event屬性
* 這邊的範例使用offsetX,Y用來取的框內的座標

```htmlembedded=
<div id="vue-app" v-on:mousemove="updateXY">{{x}},{{y}}
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        x: 0,
        y: 0
    },
    methods: {
        updateXY: function (event) {
            this.x = event.offsetX;
            this.y = event.offsetY;
        }
    }
});
```

當`console.log(event)`可以看到所以mouse相關的屬性可以使用
![](https://i.imgur.com/3lB9wVQ.png)

輸出滑鼠所在位置座標
![](https://i.imgur.com/pSFM4R2.png)


# Event Modifiers

[官方文件參考](https://vuejs.org/v2/guide/events.html#Event-Modifiers)

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


## once

* 讓這邊的點擊事件只能觸發一次

```javascript=
<div id="vue-app">
        <h1>Events</h1>
        <button v-on:click.once="add(1)">Add a Year</button>
        <p>My age is:{{age}}</p>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        age: 25
    },
    methods: {
        add: function (inc) {
            this.age += inc;
        }
    }
});
```

點擊按鈕上升到26後就不會再觸發事件
![](https://i.imgur.com/V7lvcr6.png)

## prevent

* 避免預設行為發動

```htmlembedded=
<div id="vue-app">
        <h1>Events</h1>
        <button v-on:click.once="add(1)">Add a Year</button>
        <p>My age is:{{age}}</p>
        <a v-on:click="click" href="https://google.com">google</a>
</div>
```


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        age: 25
    },
    methods: {
        add: function (inc) {
            this.age += inc;
        },
        click: function () {
            alert("It's been clicked!");
        }
    }
});
```

* 當使用click點擊事件在a tag內部觸發順序如下:

1. 觸發click事件，警告跳出It's been clicked!
2. a tag的預設行為，事件網頁跳轉會發生

* 所以想要避免預設行為的發生可以使用prevent，頁面就不會跳轉到外部頁面搂!

```htmlembedded=
<a v-on:click.prevent="click" href="https://google.com">google</a>
```


# Keyboard Events

[官方文件參考](https://vuejs.org/v2/guide/events.html#Key-Codes)

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

## keyup

* 當input被輸入鍵盤值時觸發事件內部的函式

```htmlembedded=
<div id="vue-app">
        <h1>Keyboard Events</h1>
        <label>Name:</label>
        <input type="text" v-on:keyup="logName">
        <label>Age:</label>
        <input type="text" v-on:keyup="logAge">
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {},
    methods: {
        logName: function () {
            console.log("you entered your name");
        },
        logAge: function () {
            console.log("you entered your age");
        }
    }
});
```

印出結果
![](https://i.imgur.com/ZCV1Jou.png)


## enter

當不需要每次輸入鍵盤值都觸發函式，可以使用enter，只有輸入鍵盤值enter時才會觸發函式

```htmlembedded=
<div id="vue-app">
        <h1>Keyboard Events</h1>
        <label>Name:</label>
        <input type="text" v-on:keyup.enter="logName">
        <label>Age:</label>
        <input type="text" v-on:keyup.enter="logAge">
</div>
```

必須輸入鍵盤值enter才會有觸發函式，甚至當input為空只輸入鍵盤值enter也會觸發函式
![](https://i.imgur.com/vfPwOpa.png)


## alt

使用方法跟enter一樣，但是需要搭配enter使用，必須按住alt + enter才會觸發函式

```htmlembedded=
<input type="text" v-on:keyup.alt.enter="logName">
```


# Two-Way Data Binding

## v-model

使用此directive可以把input的內容輸入到:
1. data內部對應的name,age
2. 呈現到DOM上

```htmlembedded=
<div id="vue-app">
        <h1>Keyboard Events</h1>
        <label>Name:</label>
        <input type="text" v-model="name">
        <span>{{name}}</span>
        <label>Age:</label>
        <input type="text" v-model="age">
        <span>{{age}}</span>
</div>
```


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        name: '',
        age: ''
    },
    methods: {
        logName: function () {
            console.log("you entered your name");
        },
        logAge: function () {
            console.log("you entered your age");
        }
    }
});
```

輸出結果
![](https://i.imgur.com/u2zjwvm.gif)


# Computed Properties

* 可以辨識正在使用的函式(methods無法斷判)
* 只會跑當下需要跑的資料
* 大多數時候比使用methods更有效率

## 範例

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

想要連動，當按下按鈕Add a A時，數字會連動變化
A - 1
Age + A = 21

```htmlembedded=
<div id="vue-app">
        <h1>Computed Properties</h1>
        <button v-on:click="a++">Add a A</button>
        <button v-on:click="b++">Add a B</button>
        <p>A - {{a}}</p>
        <p>B - {{b}}</p>
        <p>Age + A = {{addToA()}}</p>
        <p>Age + B = {{addToB()}}</p>
</div>
```
這邊使用methods呈現

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        age: 20,
        a: 0,
        b: 0
    },
    methods: {
        addToA: function () {
            console.log("addToA");
            return this.a + this.age;
        },
        addToB: function () {
            console.log("addToB");
            return this.b + this.age;
        },
    }
});
```

但這時候會發現，雖然我只按了按鈕A卻兩個函式都觸發了

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



因此我們可以使用computed這個property，把函式包起來，這樣一來Vue.js就會辨識正在使用的函式是哪一個瞜!


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        age: 20,
        a: 0,
        b: 0
    },
    computed: {
        addToA: function () {
            console.log("addToA");
            return this.a + this.age;
        },
        addToB: function () {
            console.log("addToB");
            return this.b + this.age;
        }
    },
});
```


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



# Dynamic CSS Classes


## v-bind:class(簡易介紹版)

為了動態的處理CSS class

`v-bind:class="{class名稱 : data內部資料也就是ture/false}"`

這邊範例使用點擊事件:

1. 當點擊div時會加上class avaliable
1. 再次點擊div時會移除class avaliable
 
```htmlembedded=
<div id="vue-app">
        <h1>Dynamic CSS</h1>
        <h2>Example 1</h2>
        <div v-on:click="avaliable = !avaliable" v-bind:class="{avaliable:avaliable}">
            <span>Ryu</span>
        </div>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        avaliable: true,
    }
});
```

簡單的CSS

```css=
span {
    background: red;
    display: inline-block;
    padding: 10px;
    color: #fff;
    margin: 10px 0;
}

.avaliable span {
    background: green;
}

.nearby span:after {
    content: "nearby";
    margin-left: 10px;
}
```

這樣使用就可以開關class搂!

![](https://i.imgur.com/bFbGv6H.gif)


## v-bind:class(真實使用版)

為了避免寫死在html內的template，真實專案中使用的方式會是能夠在JS檔案中做靈活修改的:

* 使用呼叫函式的方式`<div v-bind:class="compClasses">`
* 並在JS程式碼中輸入在computed內部
* compClasses 會返回class所需要的內容，需要修改的話也在這邊執行
* 不需要寫死在html內的templat搂!

```htmlembedded=
<div id="vue-app">
        <h1>Dynamic CSS</h1>
        <h2>Example 2</h2>
        <button v-on:click="nearby = !nearby">Toggle nearby</button>
        <button v-on:click="avaliable = !avaliable">Toggle avaliable</button>
        <div v-bind:class="compClasses">
            <span>Ryu</span>
        </div>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        avaliable: false,
        nearby: false,
    },
    computed: {
        compClasses: function () {
            return {
                avaliable: this.avaliable,
                nearby: this.nearby
            }
        }
    }
});
```

簡易CSS

```css=
span {
    background: red;
    display: inline-block;
    padding: 10px;
    color: #fff;
    margin: 10px 0;
}

.avaliable span {
    background: green;
}

.nearby span:after {
    content: "nearby";
    margin-left: 10px;
}
```

印出結果
![](https://i.imgur.com/YACJVvA.gif)


# Conditionals

## v-if

當`v-if="內容"`，內容處布林值為true時會顯示內容，false則否

使用`v-on:click="error = !error"`達到開關的效果

```htmlembedded=
<div id="vue-app">
        <h1>Conditionals</h1>
        <button v-on:click="error = !error">Toggle Error</button>
        <button v-on:click="sucess = !sucess">Toggle Sucess</button>
        <p v-if="error">There has been an error</p>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        error: false,
        sucess: false
    }
});
```

印出結果，當點擊按鈕時下方p tag內文字會出現
![](https://i.imgur.com/1L73zlW.png)

## v-else-if

```htmlembedded=
<p v-if="error">There has been an error</p>
<p v-else-if="sucess">There has been an sucess</p>
```

當出現v-if以及v-else-if時，只要v-if的狀態是true，那麼就不會顯示else-if的部分跟JS的判斷式一樣

## v-show 

做的事情跟v-if幾乎一樣但是差別在於:

當內容布林值顯示為false時

* v-if
會把元素完全移除掉

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


* v-show
只會呈現display:none

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

# Looping with v-for

## 陣列

逐一印出data內容，範例以ul表單為例:

`v-for="chracter in characters"`

* 這個部分的chracter可以名稱自訂
* characters這個部分就需要對照data內部


```htmlembedded=
<div id="vue-app">
        <h1>Looping through lists</h1>
        <ul>
            <li v-for="chracter in characters">{{chracter}}</li>
        </ul>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        characters: ['Mario', 'Luigi', 'Yoshi', 'Bowser']
```
印出結果
![](https://i.imgur.com/NmkvMCC.png)

## 物件

可以使用 (.)的方式去取得物件的屬性

```htmlembedded=
<ul>
    <li v-for="ninja in ninjas">
                {{ninja.name}} - {{ninja.age}}
    </li>
</ul>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        ninjas: [{
                name: 'Ryu',
                age: 25
            },
            {
                name: 'Yoshi',
                age: 35
            },
            {
                name: 'Ken',
                age: 55
            }
        ]
    }
});
```

印出結果
![](https://i.imgur.com/y6FfHFH.png)


## 輸出index

把index嵌入template中即可

使用在陣列或是物件的`v-for`都是可行的

```
(chracter, index) in characters
(ninja, index) in ninjas
```


```htmlembedded=
<ul>
    <li v-for="(chracter, index) in characters">{{index}} . {{chracter}}</li>
</ul>
<ul>
    <li v-for="(ninja, index) in ninjas">
                {{index}} . {{ninja.name}} - {{ninja.age}}
    </li>
</ul>
```

印出結果
![](https://i.imgur.com/4g2N7Zv.png)


## 使用li以外的容器包裹住v-for的內容

### 用div包裹住h3,p

使用div一樣可以做出li一樣的效果

```htmlembedded=
<div v-for="(ninja, index) in ninjas">
            <h3>{{index}}. {{ninja.name}}</h3>
            <p>{{ninja.age}}</p>
</div>
```

印出結果
![](https://i.imgur.com/IGhcAv5.png)


### 如果只想要內容物的h3,p tag

可以改用template tag就不會輸出到DOM上面，而只有包在裡面的內容會被輸出

```htmlembedded=
<template v-for="(ninja, index) in ninjas">
            <h3>{{index}}. {{ninja.name}}</h3>
            <p>{{ninja.age}}</p>
</template>
```

印出結果
![](https://i.imgur.com/RMsiKQL.png)


## 直接印出key,value而不用透過(.)

1. 第一次的v-for就正常發揮
1. 第二次的v-for則是印出每一個ninja的key,value
1. 把第二次的結果呈現在DOM上

```htmlembedded=
<template v-for="ninja in ninjas">
            <div v-for="(val,key) in ninja">
                <p>{{key}} - {{val}}</p>
            </div>
</template>
```
印出結果所有的 key-value pair
![](https://i.imgur.com/Mzus47P.png)


# Simple Punchbag Game

## 成品:

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

[成品網址](https://chiehliu.github.io/git-projects/Vue.js-Ninja/index.html)

## 成品功能:

1. 點擊Punch會讓沙包的血條扣寫扣到底時沙包會破掉
1. 點擊Restart會隨時把沙包的狀態更新回100%血量



## HTML

* bag image
使用v-bind綁定class當ended為true時，會給div加class=burst，就會更換成破掉的沙袋

* bag health
使用v-bind綁定`style"{ width: health + '%'}"`讓血量可以隨health的數量移動

* game controls
1. 使用v-on:click綁定兩個按並分別觸發punch, restart
1. Punch的部分特別使用v-show當內容為true時會秀出(沙袋還沒破)，破的時候按鈕消失(內容變成false)


### html程式碼:

```htmlembedded=
<div id="vue-app">
        
        <!-- bag image -->
        <div id="bag" v-bind:class="{burst: ended}"></div>

        <!-- bag health  -->
        <div id="bag-health">
            <div v-bind:style="{ width: health + '%'}"></div>
        </div>
        <!-- game controls -->

        <div id="controls">
            <button v-on:click="punch" v-show="!ended">Punch</button>
            <button v-on:click="restart">Restart</button>
        </div>

    </div>
```


## CSS:

### CSS完整程式碼

```css=
#bag {
    width: 200px;
    height: 500px;
    margin: 0 auto;
    background: url(/bag.png) center no-repeat;
    background-size: 80%;
}

#bag.burst {
    background: url(/bag-burst.png) center no-repeat;
    background-size: 80%;
}

#bag-health {
    width: 200px;
    border: 2px solid #000;
    margin: 0 auto 20px auto;
}

#bag-health div {
    height: 20px;
    background: crimson;
}

#controls {
    width: 120px;
    margin: 0 auto;
}
```

## JS:


### vue-app

* el: 抓取整個外框

* data: 
設置
1. health: 100
1. ended: false 預設式false，因為要血條歸零才會顯示true

* methods:

punch: 
1. 使用this抓取#vue-app實體後讓其health -= 10也就是每執行一次扣10點
1. 設置if判斷如果health等於或小於零則讓ended為true

restart:
1. 使用this抓取#vue-app實體後讓其health重新賦值100
1. 並且把ended回復成false

### JS完整程式碼:
```javascript=
new Vue({
    el: '#vue-app',
    data: {
        health: 100,
        ended: false,
    },
    methods: {
        punch: function () {
            this.health -= 10;
            if (this.health <= 0) {
                this.ended = true;
            }
        },
        restart: function () {
            this.health = 100;
            this.ended = false;
        }
    }
});
```

# Multiple Vue Instances

## 範例 創造多個Vue實體

* 創造兩個vue實體 app-one, app-two
* 並在兩個實體中
* 都使用`<h2>{{ title }}</h2>` `<p>{{ greet }}</p>`
* 印出結果沒有重複，分別印出各自的 title以及 greet


```htmlembedded=
<h1>Mutiple Vue Instances</h1>
<div id="vue-app-one">
    <h2>{{ title }}</h2>
</div>

<div id="vue-app-two">
    <h2>{{ title }}</h2>
</div>
```

```javascript=
var one = new Vue({
    el: '#vue-app-one',
    data: {
        title: 'Vue App One'
    ,
    computed: {
        greet: function () {
            return 'Hello from app one'
        }
    }
})

var two = new Vue({
    el: '#vue-app-two',
    data: {
        title: 'Vue App Two'
    },
    computed: {
        greet: function () {
            return 'Hello yo all from app two'
        }
    }
})
```

印出結果
![](https://i.imgur.com/lcl8NIs.png)

## 範例二 - 多個Vue實體交互作用

1. 創建一個按鈕在APP TWO，讓點擊時卻可以修改到APP ONE的title
1. 綁定v-on:click在按鈕上並觸函式changeTitle
1. 函式內容使用 APP ONE的變數名稱one並且使用其屬性title做修改內容然後返回其值


```htmlembedded=
<h1>Mutiple Vue Instances</h1>
<div id="vue-app-one">
    <h2>{{ title }}</h2>
    <p>{{ greet }}</p>
</div>

<div id="vue-app-two">
    <h2>{{ title }}</h2>
    <p>{{ greet }}</p>
    <button v-on:click="changeTitle">Change App One title</button>
</div>
```

```javascript=
var one = new Vue({
    el: '#vue-app-one',
    data: {
        title: 'Vue App One'
    },
    computed: {
        greet: function () {
            return 'Hello from app one'
        }
    }
})

var two = new Vue({
    el: '#vue-app-two',
    data: {
        title: 'Vue App Two'
    },
    methods: {
        changeTitle: function () {
            one.title = 'Title changed'
        }
    },
    computed: {
        greet: function () {
            return 'Hello yo all from app two'
        }
    }
})
```

印出結果

APP ONE的title順利被更改

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


### 範例三 - 使用變數修改Vue實體

因為Vue實體有綁定變數因此可以直接呼叫並使用其屬性做修改

```javascript=
two.title = 'change from outside';
```

印出結果

APP TWO的title也確實被修改

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


# Intro to Components

> Components是指一段程式碼或是template可以被重複使用在不同的Vue實體中


使用component的方式:

在component內部''輸入名稱，後方物件可以添加屬姓使用

```javascript=
Vue.component('輸入名稱',{
    template:'<p>Hey there, I am a re-usable component</p>'
})
```

## 範例 - 使用component在不同的Vue實體中

* 使用在html內部時要呼叫component名稱
* 內容被印出時則不會顯示componet名稱只顯示其內容

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


```htmlembedded=
<h1>Intro to Components</h1>
<div id="vue-app-one">
    <h2>Vue app one</h2>
    <greeting></greeting>
</div>

<div id="vue-app-two">
    <h2>Vue app two</h2>
    <greeting></greeting>
</div>
```

```javascript=
Vue.component('greeting', {
    template: '<p>Hey there, I am a re-usable component</p>'
})

new Vue({
    el: '#vue-app-one',

})

new Vue({
    el: '#vue-app-two',

})
```

印出結果

在兩個Vue實體中都印出component內容

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


## 範例 使用data以及methods在component內

* data 必須連接函式，當呼叫時才會修改內容，避免修改component內容時所有的Vue實體都同時更改了(因為每次使用data這邊會回傳一個新的物件 by reference的內容就會不同就不會同步修改彼此內容)

(Vue實體因為只有自己使用所以不需要這樣操作)

* methods 的用法跟一般的Vue實體一樣用物件的方式撰寫


```htmlembedded=
<h1>Intro to Components</h1>
<div id="vue-app-one">
    <h2>Vue app one</h2>
    <greeting></greeting>
</div>

<div id="vue-app-two">
    <h2>Vue app two</h2>
    <greeting></greeting>
</div>

```



```javascript=
Vue.component('greeting', {
    template: `<p>Hey there, I am {{name}} <button v-on:click="changeName">Change name</button></p>`,
    data: function () {
        return {
            name: 'Yoshi'
        }
    },
    methods: {
        changeName: function () {
            this.name = 'Mario';
        }
    }
})

new Vue({
    el: '#vue-app-one',

})

new Vue({
    el: '#vue-app-two',

})
```

印出結果:

當點擊按鈕Yoshi就變成了Mario並且只影響呼叫的Vue實體不會影響其他實體

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

## 特殊範例(示範使用) 使用data進行全部修改

這邊作者為了解釋component的data沒有使用物件，使用function的原因:

出在物件是傳址，所以這個範例讓物件導出去，地址就會是固定的，也因此兩個實體的內容會一起更改

1. 外部設置好 `data ={name:'Yoshi'}`(就不回傳新物件都回傳同一個變數)
1. 並在data的部分直接return data(用這樣的方式取代原本的function)
1. 印出結果會同步兩個實體

```htmlembedded=
<h1>Intro to Components</h1>
<div id="vue-app-one">
    <h2>Vue app one</h2>
    <greeting></greeting>
</div>

<div id="vue-app-two">
    <h2>Vue app two</h2>
    <greeting></greeting>
</div>

```

```javascript=
var data = {
    name: 'Yoshi',
};

Vue.component('greeting', {
    template: `<p>Hey there, I am {{name}} <button v-on:click="changeName">Change name</button></p>`,
    data: function () {
        return data
    },
    methods: {
        changeName: function () {
            this.name = 'Mario';
        }
    }
})

new Vue({
    el: '#vue-app-one',

})

new Vue({
    el: '#vue-app-two',

})
```

印出結果

雖然是在Vue app one呼叫卻會直接修改兩個實體的內容

![](https://i.imgur.com/EBC95C5.gif)

# Referencing with $refs

## $refs

* 可以取得其屬性並使用

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



```htmlembedded=
<div id="vue-app">
    <h2>Refs</h2>
    <input type="text" ref="input">
    <button v-on:click="readRefs">Submit</button>
    <p>Your favorite food: {{ output }}</p>
</div>
```


```javascript=
new Vue({
    el: '#vue-app',
    data: {
        output: 'empty now'
    },
    methods: {
        readRefs: function () {
            console.log(this.$refs);
            this.output = this.$refs.input.value
        }
    }
})
```

印出結果:
取的input裡面的value屬性並且指派給output

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



## 當Vue實體中有兩個以上的$refs處理方式

* 兩個以上屬性出現時必須先加上名字

當我們印出this.$refs會得到實體內部的$refs並且兩個的屬性都可以使用
![](https://i.imgur.com/5rm7tSg.png)



```htmlembedded=
<div id="vue-app">
    <h2>Refs</h2>
    <input type="text" ref="input">
    <button v-on:click="readRefs">Submit</button>
    <p>Your favorite food: {{ output }}</p>
    <div ref="test">hello</div>
</div>
```

```javascript=
new Vue({
    el: '#vue-app',
    data: {
        output: 'empty now'
    },
    methods: {
        readRefs: function () {
            console.log(this.$refs.test.innerText);
            this.output = this.$refs.input.value
        }
    }
})
```

但是使用方式必須先把名稱加在前面，才會指定要印出哪一個

`console.log(this.$refs.test.innerText);`


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




