[TOC]
## 1. 模板
頁面元素的構成部分
### 1.1 插值
> 在靜態文本之間插入動態數據值
~~~
<span>msg: {{ msg }}</span>
~~~
> 上面的demo中雙大括號會將數據解析為普通文本,若想真正的輸出HTML代碼,需要使用 `v-html` (實際使用很少,更多時候會在插值外面添加元素標簽包裹插值)
~~~
<p>Using normal: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
~~~
上面demo的result:
~~~
Using normal: <span>this is a test</span>
Using v-html directive: this is a test
~~~
#### 1.1.1 JavaScript表達式
> 若處理太過復雜的內容時,推薦使用 `computed` 計算屬性
~~~
<div>
?<p>{{ num + 1 }}</p>
?<p>{{ ok ? 'yes' : 'no' }}</p>
</div>
?
data() {
return {
num: 1,
ok: true
}
}
~~~
### 1.2 指令
事件監聽、屬性綁定等數據相關更改與呈現,都與它相關
#### 1.2.1 v-bind
> 常見屬性綁定,可縮寫為 `:`
#### 1.2.2 v-on
> 常見事件處理綁定,可縮寫為 `@`
#### 1.2.3 v-model
> 用于雙向數據綁定
應用場景: 例如表單輸入,輸入框等
~~~
<div>
? ?<input type="text" v-model="txtVal">
</div>
?
data() {
return {
txtVal: ''
}
}
~~~
#### 1.2.4 v-once
> 用于只需渲染一次值的元素;性能優化
應用場景: 例如標題的渲染
~~~
<div>
? ?<span v-once>{{ title }}</span>
</div>
~~~
### 1.3 修飾符
修飾符與指令搭配使用,在某些情況下會取得很棒的響應。
#### 1.3.1 v-mode修飾符(常用)
~~~
<!-- 在輸入框輸入值更改時才會觸發 -->
<input v-model.lazy="txtVal" type="text">
~~~
~~~
<!-- 未使用.number修飾符的txtVal為string類型 -->
<!-- 而添加.number修飾符的txtVal將得到number類型 -->
<input v-model.number="txtVal" type="number">
~~~
~~~
<!-- 去除輸入字符的首尾空格 -->
<input v-model.trim="txtVal" type="text">
~~~
#### 1.3.2 事件修飾符
~~~
<!-- .stop阻止事件冒泡(由內而外) -->
<div @click="handleClickDiv" class="event">
? ?<li @click.stop="handleClickLi"></li>
</div>
~~~
~~~
<!-- .prevent阻止默認事件,等同于JavaScript的`event.preventDefault()` -->
~~~
~~~
<!-- 有事件冒泡時會更改事件的執行順序: .capture的事件優先觸發且會(由外至內)先執行 -->
~~~
~~~
<!-- .self會觸發除子元素范圍之外的事件,可以理解外由外至內阻止事件冒泡 -->
~~~
#### 1.3.3 按鍵修飾符
~~~
按鍵按下到彈起:@keydown - @keypress - @keyup
~~~
相對常用的有: @keyup.enter/@keyup.esc
## 2\. Script腳本
頁面的靈魂,所有數據相關的操作都在這里完成。推薦在熟悉 `vue` 基本用法之后,前去閱讀 `vue進階篇-api`
## 3\. 樣式
頁面的外表,可對頁面進行修飾
> 不建議書寫內聯樣式
`v-bind:class` 可以動態切換class,亦能與普通的class屬性共存
~~~
<div
?class="static"
?v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
~~~
綁定的數據對象不必內聯定義在模板內
~~~
<div v-bind:class="classObject"></div>
~~~
~~~
data() {
return {
? classObject: {
? ? active: true,
? ? 'text-danger': false
? }
}
}
~~~
還可以綁定一個返回對象的計算屬性
~~~
<div v-bind:class="classObject"></div>
~~~
~~~
data() {
return {
? isActive: true,
? error: false
}
},
computed: {
classObject: function () {
? return {
? ? active: this.isActive && !this.error,
? ? 'text-danger': this.error
? }
}
}
~~~
## 4\. 渲染
### 4.1 條件渲染
#### 4.1.1 v-if v-else-if v-else
> 切換過程中會銷毀和重建元素
~~~
<div>
?<span v-if="isIf === 1">if</span>
?<li v-else-if="isIf === 2">else if</li>
?<p v-else>else</p>
</div>
~~~
#### 4.1.2 v-show
> 基于 `css` 的切換,沒有顯示元素的 `display` 屬性為 `none` ;初始條件為假也會被編譯
應用場景: 需要頻繁切換視圖顯示
~~~
<span v-show="isShow">show</span>
<li v-show="!isShow">not show</li>
~~~
#### 4.1.3 兩者的區別
v-if有更高的切換消耗,v-show有更高的初始渲染消耗
### 4.2 列表渲染
#### 4.2.1 v-for
渲染數組: `v-for="item in arr"`, 渲染對象: `v-for="(value, key) of obj"`
> 需要指定 `key` 屬性
### 4.3 特殊特性key
`key` 的特殊性主要用在vue的虛擬dom算法,在新舊nodes對比辨識VNodes。
> 有相同父元素的子元素的 `key` 必須不一樣,重復的 `key` 會造成渲染錯誤
## 5\. 組件
每個 `vue` 組件都擁有 `template` , `script` 以及 `style` , 且組件是可復用的,也就是說,你可以在父組件中多次使用子組件,這些被使用的子組件都單獨存在,不為同一個
### 5.1 基礎組件
組件通信
> 下面的demo包含了父子通信與子父通信兩種,日常工作也經常用到
~~~
<!-- ... -->
<div>
? ?<p>這里是父組件</p>
? ?<Child :music="music" :handleName="handleNe" @sendMsg="handleListenChild" />
?</div>
?
<script>
import Child from '@/components/Child'
?
export default {
// ...
?components: {
? ?Child
},
?data() {
? ?return {
? ? ?music: {
? ? ? ?name: '告白氣球',
? ? ? ?author: '周杰倫'
? ? }
? }
},
?methods: {
? ?handleNe(name) {
? ? ?console.log('name', name)
? },
? ?handleListenChild(msg) {
? ? ?console.log('child said: ', msg)
? }
}
}
}
</script>
~~~
~~~
<!-- ... -->
<div>
? ?<p>這里是子組件Child</p>
? ?<p>父組件傳遞的值:{{ JSON.stringify(music) }}</p>
? ?<button @click="handleSendName">發送名字給父組件</button>
? ?<button @click="handleSendMsg">發消息給父組件</button>
?</div>
?
<script>
export default {
?// ...
?props: {
? ?music: {
? ? ?type: Object,
? ? ?default: null
? },
? ?handleName: Function
},
?data() {
? ?return {
? ? ?newName: 'xiaopi',
? ? ?msg: '嗯哼?'
? }
},
?methods: {
? ?handleSendName() {
? ? ?const { newName } = this
? ? ?this.handleName(newName)
? },
? ?handleSendMsg() {
? ? ?const { msg } = this
? ? ?this.$emit('sendMsg', msg)
? }
}
}
</script>
~~~
### 5.2 動態組件
> 將多個子組件掛載在同一位置,通過變量來切換這些子組件,實現 `tab切換` 的效果,這樣的功能也可以通過vue-router實現,但路由更適合較大的組件,且url會有相應更改
具體實現: 通過Vue的 `<component>` 元素加一個特殊的 `is` 實現效果
~~~
<div>
?<p>這是一個動態組件</p>
?<button @click="handleTabToHome">home</button>
?<button @click="handleTabToPosts">posts</button>
?<button @click="handleTabToActive">active</button>
?<!-- 組件會在 currentTabComponent 更改時改變 -->
?<component :is="currentTabComponent"></component>
</div>
~~~
> `currentTabComponent` 可以包含一個已注冊組件的組件名(推薦使用)或一個組件的選項對象
### 5.3 插槽slot
> 插槽可以理解為是一個占位符 || 一個替換標簽
應用場景: 通用訂制式組件
#### 5.3.1 匿名插槽
~~~
<div>
<p>這里是父組件</p>
<Slot-Child>
? ?<template><p>我是匿名插槽</p></template>
? ?<template><p>我來寫兩次</p></template>
?</Slot-Child>
</div>
~~~
~~~
<div>
<p>我是子組件Slot-Child</p>
<slot></slot>
<!-- <slot name="default"></slot> -->
</div>
~~~
#### 5.3.2 具名插槽
~~~
<Slot-Child>
<template v-slot:content>
? ?<ul>
? ? ?<li>我</li>
? ? ?<li>是</li>
? ? ?<li>誰</li>
? ?</ul>
?</template>
?<!-- 未提供插槽內容將會渲染后備數據 -->
?<template v-slot:unUsed></template>
?<!-- 提供的插槽內容將會替換后備數據 -->
?<!-- <template v-slot:unUsed>新能源</template> -->
</Slot-Child>
~~~
~~~
<div>
?<p>我是子組件Slot-Child</p>
?<slot name="content"></slot>
?<slot name="unUsed">這是后備能源</slot>
</div>
~~~
#### 5.3.3 作用域插槽
* 能夠綁定數據
* 樣式父組件定,內容可以自己定
~~~
<Slot-Child>
?<template v-slot:Scope="data">
? ?<ul>
? ? ?<li v-for="item in data.music" :key="item.id">{{item.type}}</li>
? ?</ul>
?</template>
</Slot-Child>
~~~
~~~
<!-- ... -->
<div>
? ?<p>我是子組件Slot-Child</p>
? ?<slot name="Scope" :music="music"></slot>
?</div>
?
<script>
// ...
?data() {
? ?return {
? ? ?music: [
? ? ? { 'type': 'rap', id: 0 },
? ? ? { 'type': '嘻哈', id: 1 },
? ? ? { 'type': '古典', id: 2 },
? ? ? { 'type': '爵士', id: 3 },
? ? ]
? }
}
</script>
~~~
## 6\. 路由
~~~
import vue from 'vue'
import Router from 'vue-router'
import Layout from '@/views/layout'
import Book from '@/views/book'
?
vue.use(Router)
?
const router = newRouter({
?routes: [
? {
? ? ?path: '/',
? ? ?name: 'layout',
? ? ?component: Layout
? }, {
? ? ?path: '/book',
? ? ?name: 'book',
? ? ?component: Book
? }
]
})
?
export default router
~~~
一個簡單的路由就注冊成功了,更多路由相關的知識點請閱讀 `vue番外篇-vue-router`