Create by jsliang on 2018-11-8 13:34:30
Recently revised in 2019-1-12 19:23:17javascript
Hello 小夥伴們,若是以爲本文還不錯,記得給個 star , 大家的 star 是我學習的動力!GitHub 地址css
【2019-08-16】Hello 小夥伴們,因爲 jsliang 對文檔庫進行了重構,這篇文章的一些連接可能失效,而 jsliang 沒有精力維護掘金這邊的舊文章,對此深感抱歉。請須要獲取最新文章的小夥伴,點擊上面的 GitHub 地址,去文檔庫查看調整後的文章。html
推薦經過 目錄
以及使用 返回目錄
按鈕,得到更好的閱讀體驗。前端
不折騰的前端,和鹹魚有什麼區別~vue
返回目錄java
飲水思源:Vue 官方文檔ios
Vue (讀音 /vjuː/,相似於 view) 是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫或既有項目整合。另外一方面,當與現代化的工具鏈以及各類支持類庫結合使用時,Vue 也徹底可以爲複雜的單頁應用提供驅動。git
學習版本:v2.5.21
編寫時間:2019-1-10
github
如版本更迭太大或者時間小夥伴們看到這篇文章過久沒更新,小夥伴們請查看 Vue 官方文檔學習最新的 Vue。ajax
那麼,Vue 是怎麼折騰的呢?
話很少說,咱們直接來看代碼實現:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: '#app',
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<p>Hello World</p>
</div>
`
})
</script>
</body>
</html>
複製代碼
如今,咱們解析下代碼運行:
Vue 通常分兩個版本:
開發版本:開發中有友好的錯誤提示。
生產版本:上線部署使用的版本,代碼包比較小
index.html 代碼片斷
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
複製代碼
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
複製代碼
app
的 DOM 節點進行操做:new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容。
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<p>Hello World</p>
</div>
`
})
複製代碼
這樣,咱們最終就顯示了 Vue 的簡單引用,是否是以爲很是簡單:
若是 Vue 僅僅是隻有 template
這個模板裝載,那麼它跟 jQuery 就顯得沒多大差異了,下面咱們使用下 Vue 的 data
進行數據渲染:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: '#app',
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<p>{{ text }}</p>
</div>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
text: 'Hello World!'
}
}
})
</script>
</body>
</html>
複製代碼
在這裏,咱們能夠看到,咱們在 template
中加了一個 <p>
標籤,經過 {{ text }}
形式,引入了一個叫 text
的 data
數據:
<p>{{ text }}</p>
複製代碼
接着咱們在 <scirpt>
中定義了 text
的內容,從而實現數據渲染:
data() {
return {
// template 中要使用的數據
text: 'Hello World!'
}
}
複製代碼
這樣,咱們就知道了,咱們不只能夠經過模板 template
來渲染 <div>
標籤,咱們也能夠將 js 中定義的數據或者變量,經過操做 data
從而改變 html 裏面的內容。
在 2.1
章節 及 2.2
章節中,咱們使用 el
的方式是:
el: '#app',
複製代碼
該 el
掛載形式,在 Vue 內部運行機制中,它會根據你傳入的值,進行查找:
#app
,那它就判斷查找 id
爲 app
的節點;.app
,那它就查找 class
爲 app
的節點;div
,那它就查找節點名……你們應該清楚,這樣判斷查找是須要時間的,多執行一個判斷都是罪惡。
因此咱們能夠:
el: document.getElementById('app'),
複製代碼
這般操做,使得 Vue 直接將掛載點掛載到 id
上去,從而得到更好的加載速度。這算是對 el
的一個小優化。
若是小夥伴有點印象,應該還記得,咱們在章節 2.2
中經過 {{}}
這個插值表達式的使用,在 data
中對其裏面的數據進行操做。
下面,咱們進一步講解這個插值表達式 {{}}
還能夠進行哪一種騷操做:
光字面理解是不夠的,咱們經過代碼進行操做演示:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<p>{{ text }}</p>
<p>{{ {name: 'jack'} }}</p>
<p>{{ 'Hello World!' }}</p>
<p>{{ isTrue == -1 }}</p>
<p>{{ isTrue ? '真' : '假' }}</p>
</div>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
text: 'Hello World!',
isTrue: true
}
}
})
</script>
</body>
</html>
複製代碼
它在瀏覽器的展現爲:
關鍵代碼講解:
<div>
<!-- 賦值 text 到 <p> 標籤中 -->
<p>{{ text }}</p>
<!-- 賦值對象到標籤中 -->
<p>{{ {name: 'jack'} }}</p>
<!-- 直接賦值字符串到標籤中 -->
<p>{{ 'Hello World!' }}</p>
<!--
直接進行布爾判斷,isTrue 在 data 中設置爲 true,
而 -1 轉爲 布爾值 是 false,因此二者不相等
輸出值爲 false
-->
<p>{{ isTrue == -1 }}</p>
<!-- 運行三元表達式,isTrue 爲 true,輸出 真 -->
<p>{{ isTrue ? '真' : '假' }}</p>
</div>
複製代碼
經過三元表達式的運用,咱們能夠作到一些判斷:數組最後一個元素、是否動態顯示隱藏等。
在 Vue 中,若是單單使用 {{}}
這種插值表達式,是知足不了咱們對數據的操做慾望的。因此,Vue 以 v-if
、v-bind
等形式,提供了一些對於頁面 + 數據的更爲方便的操做:指令
v-text
v-html
v-if
v-else-if
v-else
v-show
v-bind
v-on
v-model
v-for
這裏採用一個頁面展現全部指令,若是小夥伴想逐個詳細瞭解指令,推薦去官網查看學習:Vue 指令
那麼,上面的指令都是怎麼使用的呢?這裏經過一個 index.html
及一張圖向你們演示其基本用法:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
<style>
/* 顏色樣式:紅、綠、藍 */
.color-red {
color: red;
}
.color-blue {
color: blue;
}
.color-green {
color: green;
}
</style>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<p>v-text 演示</p>
<p v-text='vTextOrHtml'></p>
<br/>
<p>v-html 演示</p>
<p v-html='vTextOrHtml'></p>
<br/>
<p>v-if -> v-else-if -> v-else 演示</p>
<p v-if='vIf == 1'>Hello v-If</p>
<p v-else-if='vIf == 2'>Hello v-else-if</p>
<p v-else>Hello v-else</p>
<br/>
<p>v-show 演示</p>
<p v-show='isTrue'></p>
<br/>
<p>v-bind:××× -> :××× 演示</p>
<input v-bind:value="vBind" v-bind:class="colorRed" type="text"/>
<input v-bind:other1="other1" :other2="other2" :other3=" 'other3' " value="Hello :屬性值" type="text"/><br/>
<br/>
<p>v-on:click -> @click 演示</p>
<button v-on:click=" vBind= 'Hello v-on:click' ">v-on:click - 點擊直接改變 vBind 的值</button><br>
<button @click="changevBindValue">v-on:click - 點擊經過事件改變 vBind 的值</button><br>
<br/>
<p>v-model 演示</p>
<input v-model="vModel" type="text" />
<p>{{ vModel }}</p>
<br/>
<p>v-for 演示</p>
<ul v-for="(item, index) in vFor" :class="item.classStyle">
<li>{{index+1}}. {{item.name}} - {{item.age}}</li>
</ul>
</div>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
// v-text 及 v-html 使用數據
vTextOrHtml: '<span style="color: red">我是紅的</p>',
// v-if 使用數據
vIf: 2,
// v-show 使用數據
isTrue: false,
// v-bind 使用數據
vBind: "Hello v-bind",
// v-bind 經過動態綁定 class 修改樣式
colorRed: 'color-red',
// v-bind 的 :屬性 的使用形式
other1: 'other1',
// 同上
other2: 'other2',
// v-model 使用數據
vModel: 'Hello v-model',
// v-for 使用數據
vFor: [{
name: '張三', // 姓名
age: 22, // 年齡
classStyle: "color-red" // 樣式
},
{
name: '李四',
age: 23,
classStyle: "color-blue"
},
{
name: '王五',
age: 24,
classStyle: "color-green"
}
]
}
}
})
</script>
</body>
</html>
複製代碼
咱們看下頁面:
在這裏,咱們對代碼進行下講解:
<div>
<!--
1. v-html
這裏直接將 vTextOrHtml 中的文本
當成 string 渲染到頁面中去
-->
<p v-text='vTextOrHtml'></p>
<br/>
<!--
2. v-html
這裏在渲染 vTextOrHtml 的過程當中,
若是遇到標籤,則對標籤頁進行渲染
-->
<p v-html='vTextOrHtml'></p>
<br/>
<!--
3. v-if/v-else-if/v-if
判斷 data 中 vIf 的值是多少,
這裏有三種狀況:v-if、v-else-if、v-else。
若是項目中有更多狀況,則再添加 v-else-if 便可
-->
<p v-if='vIf == 1'>Hello v-If</p>
<p v-else-if='vIf == 2'>Hello v-else-if</p>
<p v-else>Hello v-else</p>
<br/>
<!--
4. v-show
判斷 isTrue 是真仍是假,
它不一樣於 v-if 的方面是:
v-if 若是是假,則在 Element 中沒有渲染
v-show 若是是假,則該標籤爲 display: none
-->
<p v-show='isTrue'></p>
<br/>
<!--
5. v-bind
v-bind 有兩種格式:
1. v-bind:value - 全寫
2. :value - 簡寫
咱們還能夠經過 v-bind:class 來動態賦值
v-bind:other1="other1" 在頁面中顯示就是:
<input other1="other1" />>
-->
<input v-bind:value="vBind" v-bind:class="colorRed" type="text"/>
<input v-bind:other1="other1" :other2="other2" :other3=" 'other3' " value="Hello :屬性值" type="text"/><br/>
<br/>
<!--
6. v-on
v-on:click 有兩種格式:
1. v-on:click - 全寫
2. @click - 簡寫
v-on:click 除了能夠直接在裏面寫表達式,還能夠填寫方法
-->
<button v-on:click=" vBind= 'Hello v-on:click' ">v-on:click - 點擊直接改變 vBind 的值</button><br>
<button @click="changevBindValue">v-on:click - 點擊經過事件改變 vBind 的值</button><br>
<br/>
<!--
7. v-model
v-model 是雙向數據綁定,
在這裏,上面 input 的修改
會影響到下面 p 顯示的內容
-->
<input v-model="vModel" type="text" />
<p>{{ vModel }}</p>
<br/>
<!--
8. v-for
v-for 循環體遍歷輸出
-->
<ul v-for="(item, index) in vFor" :class="item.classStyle">
<li>{{index+1}}. {{item.name}} - {{item.age}}</li>
</ul>
</div>
複製代碼
v-bind 和 v-model 的區別:
關於 Vue 的指令,這裏咱先對它進行了個全面的簡單瞭解,知道它是如何使用的。
想詳細學習的小夥伴,記得前往官方文檔:Vue 文檔
在上一章 2.5
中,咱們經過在 button
中使用 v-on:click
時,給它綁定了事件方法。
可是,在 2.5
中,咱們大致講述了事件方法的使用,可是咱們只是只知其一;不知其二。
在這裏,咱們抽取出來作下講解:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<button @click="addStyle">添加行內樣式</button>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
addStyle(e) {
e.toElement.style.background = "red"
}
}
})
</script>
</body>
</html>
複製代碼
此時頁面的點擊效果以下所示:
此刻咱們分析下頁面:
<button>
中,咱們經過 @click
綁定了事件 addStyle
:<button @click="addStyle">添加行內樣式</button>
複製代碼
data
同級的 methods
中:methods: { // 方法
addStyle: function(e) {
e.toElement.style.background = "red"
}
}
複製代碼
e
,能夠獲取到點擊的時候的元素,經過查找,咱們發現它的樣式所在的目錄結構以下:- button
- toElement
- style
- background
複製代碼
敲黑板!敲黑板!敲黑板!
組件是 Vue 學習的重點,組件化的 SPA 或者 SSR 頁面的製做,使得咱們開發起來更加隨心應手。
在上面的章節中,咱們一直使用 template: ``
的形式,編寫 html
標籤。可是,隨着項目的不斷擴大,若是所有代碼都寫在一個 template
中,那麼咱們修改起來就複雜了。因此,咱們應該想辦法對它進行劃分,例如將一個頁面劃分爲 header
、content
、footer
三部分。這樣,咱們須要修改 nav
的時候,只須要在 header
中修改就能夠了。
頁面結構
- app
- header
- content
- footer
複製代碼
這樣的思想,在 Vue
中體現爲組件(組合起來的部件)。那麼,在 Vue
中,須要如何作,才能比較好的作到組件的劃分呢?
首先,咱們捋捋邏輯:
在前面的章節中,在 Vue 的定義上,咱們將首個 template
掛載到了 id 爲 app
的節點上。而後將 template
劃分爲三個塊:header
、content
、footer
。
在這裏,咱們將
#app
的template
叫作父組件,header
等叫子組件,就比如父親下面有三個兒子同樣。
而後,咱們嘗試從 new Vue
中抽離單個組件出來:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
// 聲明入口組件
var App = {
template: `<h1>我是入口組件</h1>`
}
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: '<app/>',
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
app: App
}
})
</script>
</body>
</html>
複製代碼
這時候頁面以下所示:
接着,咱們分析下進行的三部曲:
component
中定義並抽離 App
new Vue
外定義 App
template
中使用 App
這樣,咱們就作到了單個組件的抽離,及 new Vue
是 App
的父組件,App
是 new Vue
的子組件。
最後,既然上面作到了單個組件的抽離,如今咱們實現多個組件的抽離:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue學習</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 聲明頭部組件
var MyHeader = {
template: `<div>我是頭部</div>`
};
// 聲明內容組件
var MyContent = {
template: `<div>我是軀體</div>`
};
// 聲明底部組件
var myFooter = {
template: `<div>我是底部</div>`
}
new Vue({
el: document.getElementById('app'),
components: { // 聲明要用的組件們
// key 是組件名,value 是組件對象
'my-header': MyHeader,
'my-content': MyContent,
'my-footer': myFooter
},
template: `
<div>
<my-header/>
<my-content/>
<my-footer/>
</div>
`
})
</script>
</body>
</html>
複製代碼
這樣,咱們就作到了組件的抽離。
注意:template
有且只有一個根節點,若是沒有根節點,Vue 會給你報錯。
template: `
<my-header/>
<my-content/>
<my-footer/>
`
複製代碼
上面那種寫法是錯誤的,謹記。
作到這裏,咱們又能夠愉快玩耍了,並且 myHeader
、myContent
、myFooter
中是能夠跟 new Vue
同樣寫 data
、methods
的哦~
例如:
var MyHeader = {
data() {
return {
// ... 定義數據
}
},
template: `<h1>我是頭部</h1>`,
methods: {
// 定義方法
}
};
複製代碼
既然前面章節已經劃分了父子組件,那麼在這裏,咱們講件更有趣的事:父子組件通信。
在組件間,咱們 new Vue
至關於父親(父組件),他有本身的 data
。而後,子組件也會有本身的 data
。
「其實你不是我親生的,你的姓名是***」
。那麼,在 Vue
中,咱們要怎麼作,才能讓它的兒子(子組件),知道它的姓到底是什麼呢?咱們來看代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
// 子組件
var Son = {
template: `
<div>個人名字:{{name}}</div>
`,
props: ['name']
}
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<son :name="name"></son>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
name: '皮皮蝦'
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
son: Son
}
})
</script>
</body>
</html>
複製代碼
編寫完代碼後,咱們能夠在瀏覽器看到,瀏覽器顯示出了:個人名字:皮皮蝦
,這幾個大字。
哦了,原來父親的兒子姓 皮
。同時,咱們也就知道了,在父組件中的數據,經過 v-bind:***
的形式,將父組件中的 data
,發送給子組件。而子組件呢,經過 props
的定義,獲取到了父親的數據。
這樣咱們就作到了父組件傳遞數據給子組件。
在上面中,咱們提到:
- App
- my-header
- my-content
- my-footer
複製代碼
在 App
這個組件上,咱們掛載了三個子組件:myHeader
、myContent
、myFooter
。
beautifulGirl
。而後不只三個兒子(子組件)想追求她,就連父親(父組件)也想追求她(夠瘋狂)。那麼,在 Vue
中,是經過什麼方式,使父親和兒子都有機會接觸到這個女孩呢?(父子組件如何可以均可以使用共用組件)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
// 聲明頭部組件
var MyHeader = {
template: `
<div>我是頭部,我想了解<beautiful-girl></beautiful-girl></div>
`
};
// 聲明內容組件
var MyContent = {
template: `
<div>我是內容區,我想了解<beautiful-girl></beautiful-girl></div>
`
};
// 聲明底部組件
var myFooter = {
template: `
<div>我是底部,我想了解<beautiful-girl></beautiful-girl></div>
`
}
// 聲明共用組件
Vue.component('beautiful-girl', {
template: `<span>—— 美麗女孩 ——</span>`
})
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<my-header/>
<my-content/>
<my-footer/>
</div>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
'my-header': MyHeader,
'my-content': MyContent,
'my-footer': myFooter,
}
})
</script>
</body>
</html>
複製代碼
在這裏,咱們經過 Vue.component('組件名',{ })
的形式,註冊了個全局組件 beautiful-girl
,這樣,父子組件均可以直接調用該組件,從而在瀏覽器顯示爲:
如今,父親和兒子均可以和漂亮女孩溝通了。到底是父親給他們的兒子找了個後媽,仍是他們兒子找到本身所愛呢?敬請期待……
在工做中,咱們常常須要對一些後端傳回來的數據進行過濾。例如:我司 Java 小哥傳回來的金錢,就是分進制的,即:1元 = 100分。因此傳回個 2000,實際上是 20 元。那麼,在 Vue 中,咱們該如何對數據進行過濾呢?
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
// 聲明頭部組件
var MyHeader = {
template: `
<div>我是頭部,我想了解<beautiful-girl></beautiful-girl></div>
`
};
// 聲明內容組件
var MyContent = {
template: `
<div>我是內容區,我想了解<beautiful-girl></beautiful-girl></div>
`
};
// 聲明底部組件
var myFooter = {
template: `
<div>我是底部,我想了解<beautiful-girl></beautiful-girl></div>
`
}
// 聲明共用組件
Vue.component('beautiful-girl', {
template: `<span>—— 美麗女孩 ——</span>`
})
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<p>我是錢多多,我有 {{money}} 多一點: ¥{{money | addDot}},跟我混有出息~</p>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
money: 1000000
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
},
// 8. filters - 組件內的過濾器
filters: {
addDot(money) {
return (money / 1000000 + ".000000");
}
}
})
</script>
</body>
</html>
複製代碼
在上面,咱們經過 filters
中的 addDot
方法,對數據進行了過濾,將 money
的數據,從 10000000
變成了 1.000000
。
而後,在嘗試了局部 filters
的好處以後,咱們還能夠試試它的全局過濾器寫法:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
// 全局過濾器
Vue.filter('addDot', function(money) {
return (money / 1000000 + ".000000");
})
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<p>我是錢多多,我有 {{money}} 多一點: ¥{{money | addDot}},跟我混有出息~</p>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
money: 1000000
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
},
// 8. filters - 組件內的過濾器
filters: {
}
})
</script>
</body>
</html>
複製代碼
最後在頁面中顯示爲:
在 Vue
中,咱們經過 v-model
作了雙向數據綁定,即在頁面的 <input>
中輸入的值,在咱們的 Vue
中能夠得到數據;在 Vue
中定義的數據,也會即時渲染到頁面中。
可是,在代碼中,咱們怎樣才能獲取到它即時輸入的數據呢?
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<div>
<input type="text" v-model="money" />
<span>{{money}}</span>
</div>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
money: ''
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
},
// 8. filters - 組件內的過濾器
filters: {
},
// 9. watch - 偵聽屬性
watch: {
// key: data 屬性的屬性名
money(newVal, oldVal) {
console.log(newVal, oldVal);
}
}
})
</script>
</body>
</html>
複製代碼
這樣,當咱們輸入 11 個 1 的過程當中,瀏覽器的 Console
對應輸出爲:
在上面,咱們講了經過 watch
來監聽 data
中 number
、string
等字段的改變。可是,在 Vue 中,爲了方便咱們的監聽操做,Vue 還定義了個方法:computed
,咱們能夠經過 computed
,監控咱們在 data
中定義的所有數據。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue學習</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: document.getElementById('app'),
template: `
<div>
<input type="text" v-model="number1" />
+
<input type="text" v-model="number2" />
*
<input type="text" v-model="number3" />
=
{{result}}
</div>
`,
data: {
number1: 0,
number2: 0,
number3: 0,
result: '',
},
computed: {
// 若是原值不變,緩存不調函數的優化機制
result: function() {
// 監視對象,寫在了函數內部,
// 凡是函數內部有 this. 相關屬性,改變都會觸發當前函數
let addSum = parseInt(this.number1) + parseInt(this.number2);
let allSum = addSum * this.number3;
return allSum;
}
}
})
</script>
</body>
</html>
複製代碼
其結果以下面 GIF 圖所示:
在上面,咱們涉及了兩個知識點:watch
與 computed
。
那麼,又到 「玄學」 的時刻了,都是跟監聽數據打交道,咱們平時使用 Vue 的時候,何時使用 watch
,何時使用 computed
?而後,若是咱們在加上 methods,那麼何時咱們又用 methods 呢?
首先,咱們對比下 computed
與 methods
:
computed
是根據 data
中的數據變化,而進行的操做。即 this.任意數據
改變了,那麼,computed
就會進行改變;而若是 this.任務數據
不變,那麼 computed
就會執行它的緩存策略,不會更新methods
通常是根據點擊之類的事件來觸發的,例如用戶經過 @click="方法"
來進行數據的改變。而後,咱們對比下 computed
與 watch
:
若是上面章節的 computed
方法換成 watch
:
index.html 代碼片斷
// 9. watch - 偵聽屬性
watch: {
// key: data 屬性的屬性名
result(newVal, oldVal) {
console.log(newVal, oldVal);
this.result = this.number1 + this.number2 * this.number3;
}
},
複製代碼
你會發現,result
數據不變化了,由於這是 computed
才特有的玩意,若是你須要將上面章節的 computed
方法換成 watch
,那麼你須要:
index.html 代碼片斷
// 9. watch - 偵聽屬性
watch: {
// key: data 屬性的屬性名
number1(val) {
this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
},
number2(val) {
this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
},
number3(val) {
this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
}
},
複製代碼
如此,小夥伴應該瞭解到,watch
若是須要完成 computed
的功能,那麼,它須要監聽每個須要改變的屬性。
最後,在這裏,咱們大體描述下 watch
與 computed
的區分:
computed
強調計算,例如 c = a + b
,b
是外界傳來不斷變化的,由於你只要顯示 c
,因此使用 computed
。而 watch
屬性強調自身值的變化先後的動做,若是須要完成 c = a + b
,那麼你須要 watch
數據 a
與 b
的變化,在這二者變化的時候,在方法中執行 c = a + b
。watch
在處理異步操做或者開銷較大的操做上有優點。
watch
;watch
;computed
。computed
對綁定的值有依賴,若是每次操做的值不變化,則不進行計算,具備緩存特性。watch 會偵聽先後變化的狀態,不管操做的值是否變化,都會執行定義的函數體,因此會有 data(newVal, oldVal)。若是小夥伴們較真上了,那麼請查看官方文檔:計算屬性和偵聽器
在平常工做中,咱們對一些經常使用的功能,例如:側邊欄、頂部導航欄等,會進行經常使用的封裝,等咱們想用的時候,就能夠直接引用。那麼,在 Vue 中,想實現這類功能,咱們還須要瞭解什麼?
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var myLi = {
template: `
<li><slot></slot></li>
`
};
Vue.component('my-li', myLi);
var App = {
template: `
<div>
<ul>
<my-li><button>我是第一行 button 按鈕</button></my-li>
<my-li><h3>我是第二行 h3 標籤</h3></my-li>
<my-li><a href="javascript:void(0)">我是第三行 a 導航</a></my-li>
<my-li><span>我是第四行 span 標籤</span></my-li>
</ul>
</div>
`
};
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<app/>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
app: App
},
// 8. filters - 組件內的過濾器
filters: {
},
// 9. watch - 偵聽屬性
watch: {
// key: data 屬性的屬性名
},
// 10. computed - 計算屬性
computed: {
// 若是原值不變,computed 會執行緩存,即不調用方法
}
})
</script>
</body>
</html>
複製代碼
其結果以下圖所示:
那麼,上面代碼中,咱們幹了什麼?
首先,如上代碼及其結果圖,咱們的 new Vue
中掛載了一個組件 App
。
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
複製代碼
而後,該 App
的目的,是想動態引用一個 li
組件
var App = {
template: `
<div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
`
};
複製代碼
接着,咱們在全局定義 myLi
組件的同時,經過 <slot></slot>
插槽,使它可以動態地加載 dom
節點。
var myLi = {
template: `
<li><slot></slot></li>
`
};
Vue.component('my-li', myLi);
複製代碼
最後,咱們在 App
中,傳遞給它不一樣的 dom
節點,從而動態生成 App
。
var App = {
template: `
<div>
<ul>
<my-li><button>我是第一行 button 按鈕</button></my-li>
<my-li><h3>我是第二行 h3 標籤</h3></my-li>
<my-li><a href="javascript:void(0)">我是第三行 a 導航</a></my-li>
<my-li><span>我是第四行 span 標籤</span></my-li>
</ul>
</div>
`
};
複製代碼
這樣,咱們就思路清晰地知道,如何經過 <slot></slot>
來動態地加載 dom
節點,對咱們 Vue 開發又有了更好的幫助。
在上面中,咱們談論到了單個插槽 slot
的用法。可是,若是組件想根據父組件是否傳遞某個變量來存放插槽的數量,要怎麼作呢?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var mySlot = {
template: `
<ul>
<li>
<slot></slot>
</li>
<li>
<slot name="one"></slot>
</li>
<li>
<slot name="two"></slot>
</li>
<li>
<slot name="three"></slot>
</li>
</ul>
`
};
Vue.component('my-slot', mySlot);
var App = {
template: `
<div>
<my-slot>
<p>Helo World!</p>
<button slot="one">按鈕</button>
<a href="javascript:void(0)" slot="two">連接</a>
</my-slot>
</div>
`
};
new Vue({
// 3. el - 掛載目標,即渲染在哪一個掛載點
el: document.getElementById('app'),
// 4. template - 模板,即渲染到掛載點的內容
// 最外層必須有一層包裹,例如 <div>
template: `
<app/>
`,
// 5. data - 數據,即在操做中須要用到的數據
// 能夠理解爲在 jQuery 中 var text = "Hello World!"
// {{ text }} 爲數據渲染到 DOM 的方式之一
data() {
return {
// template 中要使用的數據
}
},
// 6. methods - 方法,即咱們的頁面事件
// 能夠理解爲在 jQuery 中定義 Function
methods: {
},
// 7. components - 組件名稱
components: {
// key 是組件名,value 是組件對象
app: App
},
// 8. filters - 組件內的過濾器
filters: {
},
// 9. watch - 偵聽屬性
watch: {
// key: data 屬性的屬性名
},
// 10. computed - 計算屬性
computed: {
// 若是原值不變,computed 會執行緩存,即不調用方法
}
})
</script>
</body>
</html>
複製代碼
效果圖以下:
下面咱們分析下,咱們在代碼中作了啥:
首先,咱們經過下面代碼能夠知道,第一個 li
的 slot
是未命名的默認 slot
,因此它在頁面中展現爲 p
的數據。
var mySlot = {
template: `
<ul>
<li>
<slot></slot>
</li>
</ul>
`
};
var App = {
template: `
<div>
<my-slot>
<p>Helo World!</p>
<button slot="one">按鈕</button>
<a href="javascript:void(0)" slot="two">連接</a>
</my-slot>
</div>
`
};
複製代碼
而後,再觀察下 App
中的代碼 <button slot="one">按鈕</button>
和 <a href="javascript:void(0)" slot="two">連接</a>
,發現它們使用了 slot="***"
,這說明了它指定了要求組件中 <slot name="***"></slot>
的代碼接收。因此第二行第三行顯示爲按鈕和連接。
最後,因爲最後一個 li
中 <slot name="three"></slot>
,這個 name="three"
在 App
組件中沒有用到,因此它表現爲空。
在 Vue 中,何時進行虛擬 dom
渲染成 dom
,或者何時銷燬代碼,都是有對應的鉤子的:
關於生命週期,Vue 官方文檔是有相關圖示及文檔的:官方文檔 - Vue 生命週期
下面咱們經過代碼演示,講解這 5 組生命週期的用法。
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var lifeCycle = {
template: `
<div>
我是生命週期組件
</div>
`,
data: function() {
return {
text: 'Hello World!'
}
},
beforeCreate: function() {
// 組件建立以前
console.log(this.text); // [Console] undefined
},
created: function() {
// 組件建立以後
console.log(this.text); // [Console] Hello World!
}
/*
* 使用 lifeCycle 組件,就會觸發以上的事件函數(鉤子函數)
* created 中能夠操做數據,而且能夠實現 Vue -> 頁面 的影響
* 應用:發起 ajax 請求
*/
}
var App = {
components: {
'life-cycle': lifeCycle
},
template: `
<div>
<life-cycle></life-cycle>
</div>
`
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
</script>
</body>
</html>
複製代碼
在代碼中能夠看到,咱們在 App
中引用了 lifeCycle
這個組件。
咱們經過鉤子函數 beforeCreate
(組件建立以前) 與 created
(組件建立以後),結合 console
發現,這兩個鉤子函數對於 data
來講,一個在 data
掛載前(beforeCreate),因此打印出來的是:undefined
,而另一個發生在 data
掛載後,因此打印出來的是:Hello World!
。
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var lifeCycle = {
template: `
<div>
我是生命週期組件
</div>
`,
data: function() {
return {
text: 'Hello World!'
}
},
beforeMount: function() {
// Vue 起做用以前
console.log(document.body.innerHTML);
},
mounted: function() {
// Vue 起做用,裝載數據到 DOM 以後
console.log(document.body.innerHTML);
}
}
var App = {
components: {
'life-cycle': lifeCycle
},
template: `
<div>
<life-cycle></life-cycle>
</div>
`
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
</script>
</body>
</html>
複製代碼
那麼,雖然說它們的做用,一個是 Vue 起做用以前,一個是 Vue 起做用,裝載數據到 DOM 以後。
咱們應該怎樣才能觀察到它的做用?
看到上圖的紅框,也許你會恍然大悟:「喔,beforeMount
就是我裝載以前的鉤子函數,而 mounted
是我裝載以後的鉤子函數,它是 Vue 做用之後的 DOM」
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var lifeCycle = {
template: `
<div id="update">
<p>我是生命週期組件</p>
<p>{{text}}</p>
<button @click="text = '!dlroW olleH'">點擊改變 text</button>
</div>
`,
data: function() {
return {
text: 'Hello World!'
}
},
// 基於數據改變,影響頁面
beforeUpdate: function() {
// 改變前
console.log(document.getElementById('update').innerHTML);
},
updated: function() {
// 改變後
console.log(document.getElementById('update').innerHTML);
}
/*
* 在平常工做中,咱們能夠在事件先後拿到它的 DOM,從而作一些咱們想要的操做
*/
}
var App = {
components: {
'life-cycle': lifeCycle
},
template: `
<div>
<life-cycle></life-cycle>
</div>
`
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
</script>
</body>
</html>
複製代碼
在解析代碼前,咱們先查看它的輸出:
能夠看出,beforeUpdate
能夠獲取原 DOM,而 updated
能夠獲取新 DOM。
它們在上面代碼中變現爲:獲取 <button>
按鈕觸發的事件先後 DOM 的變化,經過這個變化,咱們能夠在當中作一些操做,從而更好的知足咱們的業務需求。
beforeMount
& mounted
) VS ( beforeUpdate
& updated
)那麼問題來了,beforeMount
這組和 beforeUpdate
都能監控到 DOM 的變化,它們有什麼區別呢?
答案是,通常咱們若是須要在頁面加載的時候,監控 DOM 的變化,那就使用 beforeMount
和 mounted
;可是,若是咱們想監控用戶的操做(點擊事件等),那麼,咱們就須要使用 beforeUpdate
和 updated
,由於它們不像 beforeMount
和 mounted
只會在頁面掛載初期執行一次,它們能夠根據用戶的操做被執行屢次。
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var lifeCycle = {
template: `
<div id="update">
<p>我是生命週期組件</p>
</div>
`,
// 對應父組件 v-if == false 的時候,就產生下面鉤子函數,銷燬當前組件
beforeDestroy: function() {
// 銷燬以前
console.log('實例銷燬以前調用。在這一步,實例仍然徹底可用。');
},
destroyed: function() {
// 銷燬以後
console.log('Vue 實例銷燬後調用。調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。');
}
}
var App = {
components: {
'life-cycle': lifeCycle
},
data: function() {
return {
isExist: true
}
},
template: `
<div>
<life-cycle v-if="isExist"></life-cycle>
<button @click="isExist = !isExist">點擊改變 子組件 狀態</button>
</div>
`
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
</script>
</body>
</html>
複製代碼
在這裏,咱們在點擊 <button>
的時候,控制檯顯示爲:
能夠看出,當咱們點擊 <button>
的時候,咱們的 isExist
狀態(第一次時)被改變爲 false
,從而觸發了 lifeCycle
的銷燬鉤子函數,在控制檯打印了上面兩行話。
相應的,若是是當 isExist
狀態變爲 true
的時候,會觸發咱們的 beforeCreate
和 created
這兩個鉤子函數,有興趣的小夥伴能夠嘗試一下,這裏不作過多演示。
通過長期的工做,咱們知道,若是頻繁的操做 DOM,進行影響到鉤子函數 beforeCreate
和 created
及 beforeDestory
和 destory
的操做,是對咱們的性能會產生影響的。咱們要如何防止某部分代碼的頻繁操做 DOM,而且監聽到它的操做呢?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var lifeCycle = {
template: `
<div id="update">
<p>我是生命週期組件</p>
</div>
`,
activated: function() {
console.log("組件被激活了");
},
deactivated: function() {
console.log("組件被停用了");
}
}
var App = {
components: {
'life-cycle': lifeCycle
},
data: function() {
return {
isExist: true
}
},
template: `
<div>
<keep-alive>
<life-cycle v-if="isExist"></life-cycle>
</keep-alive>
<button @click="isExist = !isExist">點擊改變 子組件 狀態</button>
</div>
`
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `
<app/>
`
})
</script>
</body>
</html>
複製代碼
在代碼中,咱們經過 <keep-alive></keep-alive>
這個 Vue 的內置組件,對咱們子組件進行了包裹。
而後,當咱們進入頁面和點擊按鈕時,作到了 activated
和 deactivated
這兩個鉤子函數的觸發:
能夠看出,當咱們進來頁面的時候,它就告訴咱們,該組件被激活了。當咱們第一次點擊 <button>
按鈕的時候,isExist
的狀態變成了 false
,即該組件被停用了。最後,咱們再次點擊了 <button>
,這時候控制檯再次打印 組件被激活了
。
在平常開發中,可能有小夥伴會想到操做 DOM 元素。若是用原生的 document.getElementById
吧,可能太 low
了,因此,有沒有相似於 jQuery 的 $("#id")
之類的呢?
話很少說,先上代碼:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var App = {
template: `
<div>
<button ref="btn">按鈕</button>
</div>
`,
beforeCreate: function() {
// 這裏不能操做數據,只是初始化了事件等……
console.log(this.$refs.btn); // [Console] undefined
},
created: function() {
// 能夠操做數據了
console.log(this.$refs.btn); // [Console] undefined
},
beforeMount: function() {
// new Vue 發生裝載,替換 <div id="app"></div> 以前
console.log(this.$refs.btn); // [Console] undefined
},
mounted: function() {
// 裝載數據以後
console.log(this.$refs.btn.innerHTML); // [Console] 按鈕
}
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `<app/>`
})
</script>
</body>
</html>
複製代碼
咱們先查看下頁面:
首先,咱們在組件的 DOM 部分(<button>
),寫上 ref = "btn"。
而後,咱們發現只有在 mounted
數據裝載以後這個鉤子函數中,經過組件對象 this.$refs.btn
能夠獲取到元素
這樣,咱們就知道在一些場景,如何能夠方便地經過 Vue 獲取到 DOM 元素了。
在上面,咱們獲取到了單個 DOM 節點的部分,假如咱們須要獲取到整個子組件,那麼要怎麼作呢?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var tempComponent = {
template: `
<div>我是臨時組件</div>
`
}
Vue.component('temp', tempComponent);
var App = {
template: `
<div>
<temp ref="temp" />
</div>
`,
mounted: function() {
// 裝載數據以後
console.log(this.$refs.temp.$el);
}
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `<app/>`
})
</script>
</body>
</html>
複製代碼
咱們先不急着分析,先看控制檯打印出了什麼;
在這裏能夠看到它打印出了一堆關於該組件的東西,其中
$children
- 當前組件的子組件$el
- 當前組件的元素節點$parent
- 當前組件的父組件$root
- 獲取 new Vue
實例而後發現元素 $el
是 DOM 節點的內容,咱們嘗試打印出來看一下:
console.log(this.$refs.temp.$el);
複製代碼
Console
<div>我是臨時組件</div>
複製代碼
經過 Console 能夠看出,$el
就能夠打印出其中的 <button>
元素了。
固然,咱們有時候操做 DOM,是想在 data
數據變動的時候進行操做,若是是使用上面方法,有些時候是搞不定的。
那麼,咱們應該怎麼作呢?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue 學習</title>
</head>
<body>
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裏操做到實際渲染 -->
<!-- 簡單理解爲 jQuery 的拼接字符串(並不全是) -->
<div id="app"></div>
<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
<!-- Vue Router CDN - 管理路由 -->
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
<!-- Axios CDN - 調用接口 -->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
<script>
var App = {
template: `
<div>
<input v-if="isShow" ref="input" />
</div>
`,
data: function() {
return {
isShow: true
}
},
mounted: function() {
// 但願在 Vue 真正渲染 DOM 到頁面以後進行下面操做
this.$nextTick(function() {
this.$refs.input.focus();
})
}
}
new Vue({
el: document.getElementById('app'),
components: {
app: App
},
template: `<app/>`
})
</script>
</body>
</html>
複製代碼
如上,經過 Vue 的全局 API Vue.nextTick()
,咱們在下次 DOM 更新循環結束以後執行延遲迴調。在修改數據以後當即使用這個方法,獲取更新後的 DOM。
這個操做咱們可想象下 Promise
的執行流程,會得到更好的體驗。
那麼,學到這裏,咱們應該進行一個簡單的操練,來回顧咱們所學知識了:
如上,咱們入門了基礎的 Vue,可能小夥伴們會以爲仍是很暈。
可是,不要緊,咱們接下來在講解 VueRouter、VueCli 的時候仍是會使用 Vue 基礎語法的,正如那句話:萬丈高樓平地起,地基還得本身起。
多實操,多作筆記,總能熟練上去的,加油~
後記
若是小夥伴須要存放 jsliang.top 這樣的純靜態頁面或者 company.jsliang.top 這樣的具備 Node 後端支持的頁面,推薦購買雲服務器來存放。
若是小夥伴們不知道該怎麼選擇雲服務器,能夠查看 詳細介紹 或者加 jsliang QQ:1741020489
諮詢。
jsliang 的文檔庫 由 梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議 進行許可。
基於 github.om/LiangJunron… 上的做品創做。
本許可協議受權以外的使用權限能夠從 creativecommons.org/licenses/by… 處得到。