> 如果有記憶吐司就好了...
# Vue 學習筆記
使用Vue可以讓我們用更簡易的方式,將程式渲染到畫面上。
```htmlembedded=
<div id="counter">
<!--使用兩個大括號包住要顯示的屬性名稱-->
Counter: {{ counter }}
</div>
```
```js=
const Counter = {
data() {
return {
counter: 0 // ←屬性名稱
}
}
}
// 綁定Vue.createApp(變數名稱).mount('DOM')
Vue.createApp(Counter).mount('#counter')
```
畫面如下:

---
## Vue起手式
兩種方法: CDN(整包加入) / import esm (需要的加入)
### CDN
```htmlembedded=
<script src="https://unpkg.com/vue@next"></script>
```
基本寫法
```js=
Vue.createApp({
data() {
return{ ... }
},
methods:{ ... },
mounted: function(){ ... },
}).mount('DOM元素')
```
or
```js=
const 變數 = {
data() {
return{
...
}
}
}
Vue.createApp(變數).mount('DOM元素')
```
### ESM
```JS=
import { createApp } from 'https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.26/vue.esm-browser.min.js'
```
基本寫法
```htmlembedded=
<!-- 載入js時需加 type="module" -->
<script type="module" src="index.js"></script>
```
```js=
// {要載入的模組}
import { createApp } from 'https://cdnjs.cloudflare.com/ajax/libs/vue/3.1.4/dist/vue.esm-browser.min.js';
createApp({
data() {
return{ ... }
},
methods: {
clickAlert() {
alert('我被觸發了');
},
mounted: function(){ ... },
}).mount('DOM元素')
```
---
## v-html / v-text / {{ }}
JS(共用)
```js=
var app = new Vue({
el: '#app',
data: {
name:`<a herf="#">Jasper</a>`
}
})
```
### 1. `{{ }}`
僅顯示字串
```htmlembedded=
<div id="app">
<p>1.祝{{ name }}早日成為工程師</p>
</div>
</div>
```
如下:

### 2. `v-html`
會帶上標籤的效果一同渲染到畫面上。
官網上有特別聲明,簡單來說就是使用v-html有安全性的問題,只建議在安全領域下使用,不建議用於客戶端或任何不安全的環境下。
> WARNING
>
> Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS attacks (opens new window). Only use v-html on trusted content and never on user-provided content.
```htmlembedded=
<div id="app">
<p>2.祝<span v-html="name"></span>早日成為工程師</p>
</div>
```
如下:

### 3. `v-text`
僅顯示字串
```htmlembedded=
<div id="app">
<p>3.祝<span v-text="name"></span>早日成為工程師</p>
</div>
```
如下:

**所以...**
* `v-text` 與 `{{ }}`一樣都僅顯示字串,不會將標籤效果渲染出來。
* `v-html` 會將整個結構一同渲染至畫面上
---
## v-cloak
我們使用vue.js的時候,若遇到網速比較慢,在畫面還沒渲染出來之前通常會顯示`{{ message }}`之類的資料裸露在畫面上,此時就可以使用`v-cloak`的方式將它隱藏,讓使用者體驗更好。
```htmlembedded=
<!--html帶上屬性即可-->
<div id="app" v-cloak>
{{ message }}
</div>
```
```js=
var app = new Vue({
el:'#app',
data:{
message: 'HelloWorld'
}
})
```
v-clock的關鍵語法是加在css內,如下:
```css=
[v-colak] {
display: none;
}
```
## v-bind 屬性綁定
使用`v-bind`可以綁定屬性,ex:title、src、class...等
```htmlembedded=
<div id="bind-attribute">
<span v-bind:title="message">
將指標停留在我身上
</span>
</div>
```
```js=
const AttributeBinding = {
data() {
return {
message: '我指到你了 ' + new Date().toLocaleString()
}
}
}
Vue.createApp(AttributeBinding).mount('#bind-attribute')
```
效果如下:

---
## v-on 綁定事件監聽
使用`v-on`與使用者互動,透過click、change、submit...等
```htmlembedded=
<div id="event-handling">
<p>{{ message }}</p>
<!-- 綁定點擊事件(click)-->
<button v-on:click="reverseMessage">Reverse Message</button>
</div>
```
```js=
const EventHandling = {
data() {
return {
message: '123456'
}
},
methods: {
reverseMessage() {
this.message = this.message
.split('') //["1","2","3","4","5","6"]
.reverse() //["6","5","4","3","2","1"]
.join('') //'654321'
}
}
}
Vue.createApp(EventHandling).mount('#event-handling')
```
效果如下:

---
## v-model 雙向綁定
使用`v-model`讓DOM與畫面可以同步進行
```htmlembedded=
<div id="two-way-binding">
<p>{{ message }}</p>
<input v-model="message" />
</div>
```
```js=
const TwoWayBinding = {
data() {
return {
message: 'Hello Vue!'
}
}
}
Vue.createApp(TwoWayBinding).mount('#two-way-binding')
```
效果如下:

---
## v-if / v-else / v-else-if 條件式綁定
### v-if
```htmlembedded=
<div id="conditional-rendering">
<span v-if="seen">Now you see me</span>
</div>
```
```js=
const ConditionalRendering = {
data() {
return {
seen: true //判斷為true才顯示
}
}
}
Vue.createApp(ConditionalRendering).mount('#conditional-rendering')
```
效果如下:

### v-else
同層必須要有`v-if`才能使用
```htmlembedded=
<div id="app">
<!--若 num>0 成立顯示Now you see me-->
<div v-if="num > 0">
Now you see me
</div>
<!-- 若不成立顯示Now you don't-->
<div v-else>
Now you don't
</div>
</div>
```
```js=
var app = new Vue({
el:'#app',
data:{
num: 9 // 因為9>0所以畫面顯示Now you see me
}
})
```
### v-else-if
同層必須要有`v-if` 或` v-else if`才能使用
```htmlembedded=
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
以上皆非
</div>
</div>
```
```js=
var app = new Vue({
el:'#app',
data:{
type: "C" //顯示C
}
})
```
---
## v-for 迴圈綁定
### 陣列
使用`v-for`可以將陣列的資料,一筆一筆渲染在畫面上,若參數兩個或以上必須加()。
陣列中的參數(item,index,array)
第一個位置:通常為item,可自定義名稱,代表的是陣列中每一筆物件
第二個位置:通常為index,可自定義名稱,為索引值,從0開始
第三個位置:很少用到,通常為array,指的是陣列本身
```htmlembedded=
<div id="app">
<ol>
<!-- v-for="參數 in 陣列名稱" -->
<li v-for="item in todos">
{{ item.text }}
</li>
</ol>
</div>
```
```js=
const app = {
data() {
return {
todos: [ // ←陣列
{ text: 'Learn JavaScript' },
{ text: 'Learn Vue' },
{ text: 'Build something awesome' }
]
}
}
}
Vue.createApp(app).mount('#app')
```
畫面如下:

### 物件
v-for也可以使用在物件上,所帶的參數與陣列略有不同。
物件中的參數(item, key)
第一個位置:通常為item,可自定義名稱,指的是物件family內的每一整筆物件如jasper:{...}、nini:{...}、max:{...}。
第二個位置:通常為key,可自定義名稱,指的是物件內的屬性,如下方程式碼中的jasper、nini、max。
```htmlembedded=
<div id="app">
<ol>
<!-- v-for="參數 in 物件名稱" -->
<li v-for="(item,key) in family">
{{ key }} 是 {{ item.title }},
今年{{ item.age }}歲,
身高{{ height }},
體重{{ weight }}
</li>
</ol>
</div>
```
```js=
const app = {
data() {
return {
family: {
jasper: {
title: '爸爸',
age: 32,
height: 168,
weight: 60
},
nini: {
title: '媽媽',
age: 29,
height: 158,
weight: 50
},
max: {
title: '兒子',
age: 0,
height: '未知',
weight: '未知'
}
}
}
}
}
Vue.createApp(app).mount('#app')
```
呈現如下:

---
## v-show
方法跟`v-if`類似,差別於判斷後`v-show`牽動的是css的元素`display`,意思是若值為`false`,則`display:none`將`v-show`綁定的dom隱藏起來,就不會顯示在畫面上。
```htmlembedded=
<div id="app">
<!--當status為1時顯示123 -->
<p v-show="status === 1">123</p>
</div>
```
```js=
<script>
var app = new Vue({
el:'#app',
data:{
status: 2
}
</script>
// 因為status是2,所以畫面不會顯示
// 查看開發者工具內的element
// <p style="display: none;">123</p>
```
效果如下:

---
其他還有很多指令,之後再來補充
v-once
v-memo
v-pre
v-is
v-slot
---
## 事件修飾符
Vue.js 藉由事件修飾符 (Event Modifiers) 處理了許多 DOM 事件的細節,讓我們能專注於程式邏輯的撰寫。
* .stop:等同於event.stopPropagation(),防止事件冒泡。
* .capture:與事件冒泡的方向相反,事件捕獲 (event capturing) 是由外而內的。
* .prevent:等同於event.preventDefault(),防止執行預設的行為。
* .self:只會觸發自己範圍內的事件,不包含子元素。
* .once:只會觸發一次
### .stop
在預設的情況下,當我按下按鈕之後,會由內而外的執行函式中的alert,此現象稱為冒泡現象,stop就可以來阻止冒泡現象發生。
冒泡線上的執行順序: inner → middle → outer
以下範例為預設的冒泡現象:
```htmlembedded=
<div id="app">
<div @click="outer">
<div @click="middle">
<button @click="inner">按我!</button>
</div>
</div>
</div>
```
```js=
// 使用CDN的方式
const app = ({
methods: {
inner() {
alert('這是裡面的 button');
},
middle() {
alert('這是中間的 div');
},
outer() {
alert('這是外面的 div');
}
}
});
Vue.createApp(app).mount('#app')
```
呈現如下:

加上.stop後:
```htmlembedded=
<div id="app">
<div @click="outer">
<div @click="middle">
<button @click.stop="inner">按我!</button>
</div>
</div>
</div>
```
呈現如下:

可以看到加上.stop後的click事件,執行後就會停止不會向外執行,我知道有人應該會好奇,那如果加在中間層的click事件呢?
```htmlembedded=
<div id="app">
<div @click="outer">
<div @click.stop="middle">
<button @click="inner">按我!</button>
</div>
</div>
</div>
```
呈現如下:

沒錯!!當你加在中間層,他依然是依照預設的冒泡現象執行,但是執行到你有加stop的click事件後就會停止了。
### .capture
與冒泡現象相反
```htmlembedded=
<div id="app">
<div @click.capture="outer">
<div @click.capture="middle">
<button @click.capture="inner">按我!</button>
</div>
</div>
</div>
```
```js=
// 使用CDN的方式
const app = ({
methods: {
inner() {
alert('這是裡面的 button');
},
middle() {
alert('這是中間的 div');
},
outer() {
alert('這是外面的 div');
}
}
});
Vue.createApp(app).mount('#app')
```
呈現如下:

---
## 關於生命週期
我們都知道`v-if`與`v-show`差異在於,使用`v-if`時,當你隱藏又重啟時`v-if`會重新跑一次完整的生命週期,`v-show`則是當他跑過一次生命週期之後就會生成,即使你隱藏他,他只是`display:none`,當你重起他就會直接顯示不會重新跑生命週期。
常用的情境:
1. 若你希望每次戳api不要讓他重新跑一次生命週期,因為跑一次就算一次,此時可以使用標籤`<keep-alive>`去包覆v-if,這樣重啟始只會跑activated與deactivated。
2. 當切換元件時,上一個元件沒有正確卸載時會導致切換過去的元件出錯,此時可以在生命週期unmounted做卸載,ex:Event Bus。
---
## Props
將外層的資料透過html(前內後外)為平台,拿來內層使用。
```htmlembedded=
<div id="app" class="p-3">
<!-- 直接帶入文字 -->
<line-msg msg="Hello World"></line-msg>
<!-- 引用外層的message -->
<line-msg :msg="message"></line-msg>
<!-- 若遇到小駝峰,則改為小寫中間加符號- -->
<line-msg2 :next-msg="message"></line-msg2>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
message: 'Hello World'
}
}
})
app.component('line-msg', {
template: `<div>請正確呈現訊息:{{ msg }}</div>`,
props: ['msg']
})
app.component('line-msg2', {
template: `<div>請正確呈現訊息:{{ nextMsg }}</div>`,
props: ['nextMsg']
})
app.mount('#app')
```
畫面如下:

### 也可以一次傳遞多筆資料
```htmlembedded=
<div id="app" class="p-3">
<line-msg :msg1="message1" :msg2="message2" :arraymsg="msgObj"></line-msg>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
message1: '有看到我的訊息嗎?',
message2: '這個工具可以傳遞 2 句話以上',
msgObj: ['也是', '可以', '傳遞陣列資料']
}
}
})
app.component('line-msg', {
template: `<div>
<span>請正確呈現訊息:{{ msg1 }}</span> <br>
<span>請正確呈現訊息:{{ msg2 }}</span> <br>
<p>請正確呈現訊息:<span v-for="item in arraymsg">{{ item }}</span></p>
</div>`,
props: ['msg1','msg2','arraymsg']
})
app.mount('#app')
```
畫面如下:

### 如何使用props進行簡單驗證
若是 props 傳入值的型別,與設定不同,雖然仍可使用,但會跳出警告,以方便開發時 debug。
```htmlembedded=
<div id="app">
<props-com
:child-string="string"
:child-object="object"
>
</props-com>
</div>
```
```js=
// 根元件
const app = Vue.createApp({
data() {
return {
string: 'test',
object:{ name:'Ryder', gender:'man'},
}
},
})
// 內層元件
app.component('props-com', {
props:{
childString:{
type: String, // 型別須為字串
},
childNum:{
type: Number, // 型別須為數字
default: 100 // 預設值100
},
childObject:{
type: Object // 型別須為物件
}
},
template:
`<div>{{ childString }}</div>
<div>{{ childNum }}</div>
<div>{{ childObject }}</div>
`,
});
app.mount('#app');
```
---
## Emit
```htmlembedded=
<div id="app" class="p-3">
{{ message }}
<mobile-phone @push-data="getMessage"></mobile-phone>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
message: ''
}
},
methods: {
getMessage(msg) {
this.message = msg;
}
}
})
app.component('mobile-phone', {
template: `<div>
<input class="me-3" v-model="innerText">
<button @click="push">傳送訊息</button>
</div>`,
data: function() {
return {
innerText: '需要向外傳的訊息'
}
},
methods: {
push() {
this.$emit('pushData', this.innerText);
}
}
})
app.mount('#app')
```
畫面如下:

---
## Props + Emit
```htmlembedded=
<div id="app" class="p-3">
{{ newMessage }}
<mobile-phone :msg="message" @push-data="getMessage"></mobile-phone>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
message: '晚餐吃什麼~,請回覆:「」',
newMessage: '', // 5
}
},
methods: {
getMessage(msg) { // 4
this.newMessage = msg;
}
}
})
app.component('mobile-phone', {
template: `<div>
<input class="me-3" v-model="message">
<button @click="push">傳送訊息</button>
</div>`,
props: ['msg'], // 1
data() {
return {
message: this.msg // 2
}
},
methods: {
push() { // 3
this.$emit('push-data', this.message);
}
}
})
app.mount('#app')
```
畫面如下:

---
## 同層元件之間的傳遞可使用mitt套件
CDN
```htmlembedded=
<script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>
```
```htmlembedded=
<div id="app" class="p-3">
<h3>小明的手機</h3>
<ming-phone class="mb-3"></ming-phone>
<h3>老媽的手機</h3>
<mom-phone></mom-phone>
</div>
```
```js=
const emitter = mitt() // 將套件載入
const app = Vue.createApp({})
app.component('ming-phone', {
template: `<div><strong>老媽傳來的訊息:</strong> {{ momMsg }}</div>`,
data() {
return {
momMsg: ''
}
},
created() {
emitter.on('passMsg', res => {
this.momMsg = res;
}); // 接收
}
})
app.component('mom-phone', {
template: `<div>
<input class="me-3" v-model="msg">
<button @click="pushData">傳送訊息</button>
</div>`,
data() {
return {
msg: '快回家,晚上煮好料 der'
}
},
methods: {
pushData() {
emitter.emit('passMsg', this.msg); // 傳送
}
}
})
app.mount('#app')
```
畫面如下:

---
## 跨層級資料傳遞provide
一般兩層的元件,我們會使用emit、props來引用或取得內外層的資料與方法,而provide則是可以運用在三層以上的元件來做資料的傳遞。
```htmlembedded=
<div id="app">
<ming-mom></ming-mom>
</div>
```
```js=
// 最三層
const ming = {
template: `<div>
小明拿到了 {{ this.cash }} 為零用錢
</div>`,
}
// 第一層
const app = Vue.createApp({
data() {
return {
cash:1000,
}
},
})
// 第二層
app.component('ming-mom', {
template:
`<ming></ming>`,
components: {
ming
},
});
app.mount('#app');
```
我們預期希望從第一層傳遞資料跨過第二層到傳遞到第三層來使用。
第一層新增一個privide的屬性(物件or函式),放入要傳遞的資料或方法
第三層新增一個inject的屬性載入資料或方法
```js=
// 第三層
const ming = {
template: `<div>
小明拿到了 {{ this.cash }} 元零用錢
</div>`,
inject:['cash'] //對應provide內的屬性名稱
}
// 第一層
const app = Vue.createApp({
data() {
return {
cash:1000,
}
},
provide:{
cash:1000,
}
})
// 第二層
app.component('ming-mom', {
template:
`<ming></ming>`,
components: {
ming
},
});
app.mount('#app');
```
畫面呈現:
小明拿到了 1000 元零用錢
---
## 混和元件方法mixins
使用屬性mixins將元件混入另一個元件內
```htmlembedded=
<div id="app">
<nike></nike>
<adidas></adidas>
<reebok></reebok>
</div>
```
```js=
const filterMix = {
created(){
this.cash = this.dollarSign(this.cash)
},
methods:{
dollarSign(dollar) {
return `$${dollar}`;
}
},
};
const app = Vue.createApp({
data() {
return {
}
},
})
app.component('nike', {
data() {
return {
cash:3000,
title:'nike 球鞋',
img:'https://i.imgur.com/fiUT2Sx.jpg'
}
},
template:
`<div class="card" style="width: 18rem;">
<img :src="img" class="card-img-top">
<div class="card-body">
<h5 class="card-title">{{title}}</h5>
<div>售價: <span>{{cash}}</span></div>
</div>
</div>`,
mixins:[filterMix] //混入元件
});
app.component('adidas', {
data() {
return {
cash:2500,
title:'adidas 球鞋',
img:'https://i.imgur.com/6A15UOE.jpg'
}
},
template:
`<div class="card" style="width: 18rem;">
<img :src="img" class="card-img-top">
<div class="card-body">
<h5 class="card-title">{{title}}</h5>
<div>售價: <span>{{cash}}</span></div>
</div>
</div>`,
mixins:[filterMix] // 混入元件
});
app.component('reebok', {
data() {
return {
cash:2299,
title:'reebok 球鞋',
img:'https://i.imgur.com/2GkIleC.jpg'
}
},
template:
`<div class="card" style="width: 18rem;">
<img :src="img" class="card-img-top">
<div class="card-body">
<h5 class="card-title">{{title}}</h5>
<div>售價: <span>{{cash}}</span></div>
</div>
</div>`,
mixins:[filterMix] //混入元件
});
app.mount('#app');
```
預期將filterMix元件混入nike、addidas、reebok三個元件內,將cash內的金額補上$。
畫面如下:

---
## teleport傳送
使用標籤teleport+屬性to來指定要傳送的地方。
```htmlembedded=
<div id="app">
<div class="minHome">小明家:</div>
<div id="huaHome">小華家:</div>
<span>小王家:</span>
<home></home>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
}
},
})
app.component('home', {
template:
`<teleport to=".minHome">小明</teleport>
<teleport to="#huaHome">小華</teleport>
<teleport to="span">小王</teleport>
`,
});
app.mount('#app');
```
畫面如下:
小明家:小明
小華家:小華
小王家:小王
---
## 使用 pathMatch 進行換頁404頁面設定
```htmlembedded=
<div id="app">
<router-link to="/pageOne">1</router-link>
<router-link to="/pageTwo">2</router-link>
<router-view></router-view>
</div>
```
```js=
const app = Vue.createApp({});
const pageOne = {
template: `<div>第一頁</div>`
};
const pageTwo = {
template: `<div>404</div>`,
};
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes:[
{
path: '/pageOne',
component: pageOne
},
{
// 若要指向404不存在
// router 需設定 path: '/:pathMatch(.*)*',
path: '/:pathMatch(.*)*',
component: pageTwo
}
]
})
app.use(router);
app.mount('#app');
```
畫面如下:

---
## 使用 methods 切換路由頁面
運用this.$router.push()的方法指向指定的路徑
```htmlembedded=
<div id="app">
<router-link class="p-3" to="/pageOne">1</router-link>|
<router-link class="p-3" to="/pageTwo">2</router-link>
<router-view></router-view>
</div>
```
```js=
const app = Vue.createApp({});
const pageOne = {
template: `<div>第一頁</div>`
};
const pageTwo = {
template: `<div>第二頁 <button type="button" @click="changePage">換頁</button></div>`,
methods: {
changePage() {
this.$router.push('/pageOne') //指定的路徑
}
}
};
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes: [
{
path: '/pageOne',
component: pageOne
},
{
path: '/pageTwo',
component: pageTwo
}
]
})
app.use(router);
app.mount('#app');
```
---
## refs 呼叫元件方法
使用$refs找到指定的元件,並運用該元件的方法。
```htmlembedded=
<div id="app">
<button type="button" @click="callComponent">按我</button>
<br>
<alert-com ref="alert"></alert-com>
</div>
```
```js=
const app = Vue.createApp({
methods: {
callComponent() {
// 調用該元件的方法
this.$refs.alert.callAlert();
},
}
})
app.component('alert-com', {
template: `<div>我裡面藏了 Alert</div>`,
methods: {
callAlert() {
alert('跳出警告了')
}
}
});
app.mount('#app');
```
---
## 建置computed運算後回傳該值
```htmlembedded=
<div id="app">
收入:
<input type="number" v-model="cash">
<br>
今年要繳的稅金為 {{ taxes }} 元
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
cash: 0,
}
},
computed: {
taxes(){
return Number.parseInt(this.cash*0.2)
}
}
}).mount('#app');
```
畫面如下:

---
## 使用 watch 監控
```htmlembedded=
<div id="app">
收入:
<input type="number" v-model="cash">
<br>
今年要繳的稅金為 {{ Taxes }} 元
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
cash: 0,
Taxes: 0,
}
},
watch: {
cash() {
this.Taxes = Number.parseInt(this.cash*0.2)
}
}
}).mount('#app');
```
畫面如下:

### 監控 props
```htmlembedded=
<div id="app">
收入:
<input type="number" v-model="cash">
<br>
<new-input :prop-Dash="cash"></new-input>
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
cash: 0,
}
},
})
app.component('new-input', {
props: ['propCash'], // 對應的是根元件的cash
data() {
return {
newcash: 0,
}
},
template: `<input type="number" v-model="newcash"/>`,
watch: {
propCash() { // 監聽對象propCash
this.newcash = this.propCash;
}
},
});
app.mount('#app');
```
畫面如下:

---
## 運用 methods 作為 filter
使用return將結果傳回函式本身。
```htmlembedded=
<div id="app">
{{ reverseText(text) }}
<br>
{{ dollarSign(cash) }}
</div>
```
```js=
const app = Vue.createApp({
data() {
return {
text: '棒棒伯斯卡',
cash: 1000
}
},
methods: {
reverseText(someText) {
console.log(someText);
return someText.split('').reverse().join('');
},
dollarSign(dollar) {
return `$${dollar}`;
}
}
}).mount('#app')
```
畫面如下:
卡斯伯棒棒
$1000
---
參考文獻:
[Vue.js](https://v3.cn.vuejs.org/)
[[Vue.js] 使用 v-cloak 解決 Vue Instance 顯示變數的問題](https://tools.wingzero.tw/article/sn/131)
[[Vue學習筆記](三)Vue指令(上) — v-text, v-html, v-if, v-show, v-for](https://medium.com/andy%E7%9A%84%E8%B6%A3%E5%91%B3%E7%A8%8B%E5%BC%8F%E7%B7%B4%E5%8A%9F%E5%9D%8A/vue%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-%E4%B8%89-vue%E6%8C%87%E4%BB%A4-%E4%B8%8A-v-text-v-html-v-if-v-show-v-for-4eb6cd994359)
[Vue.js: Methods 與事件處理 (Event Handling)](https://cythilya.github.io/2017/04/17/vue-methods-and-event-handling/)