起因
一直想着要寫一定深度的文章,然後覺得學習Vue是一個好的過程,本文將帶你走進Vue的世界,支持國內框架! 如果看完本文還不懂Vue是什麼的小夥伴,可以隨便打博主!(斜眼笑),前方高能,本文可能篇幅比較長,建議收藏在閒暇時間學習,也歡迎夥伴們討論留言學習!
Vue -漸進式JavaScript框架
介紹
- vue 中文網
- vue github
- Vue.js 是一套構建用戶界面(UI)的漸進式JavaScript框架
庫和框架的區別
Library
庫,本質上是一些函數的集合。每次調用函數,實現一個特定的功能,接着把控制權交給使用者
- 代表:jQuery
- jQuery這個庫的核心:DOM操作,即:封裝DOM操作,簡化DOM操作
Framework
框架,是一套完整的解決方案,使用框架的時候,需要把你的代碼放到框架合適的地方,框架會在合適的時機調用你的代碼
- 框架規定了自己的編程方式,是一套完整的解決方案
- 使用框架的時候,由框架控制一切,我們只需要按照規則寫代碼
主要區別
-
You call Library, Framework calls you
-
核心點:誰起到主導作用(控制反轉)
框架中控制整個流程的是框架
使用庫,由開發人員決定如何調用庫中提供的方法(輔助) -
好萊塢原則:Don’t call us, we’ll call you.
-
框架的侵入性很高(從頭到尾)
MVVM的介紹
- MVVM,一種更好的UI模式解決方案
- 從Script到Code Blocks、Code Behind到MVC、MVP、MVVM - 科普
MVC
- M: Model 數據模型(專門用來操作數據,數據的CRUD)
- V:View 視圖(對於前端來說,就是頁面)
- C:Controller 控制器(是視圖和數據模型溝通的橋樑,用於處理業務邏輯)
MVVM組成
- MVVM ===> M / V / VM
- M:model數據模型
- V:view視圖
- VM:ViewModel 視圖模型
優勢對比
-
MVC模式,將應用程序劃分爲三大部分,實現了職責分離
-
在前端中經常要通過 JS代碼 來進行一些邏輯操作,最終還要把這些邏輯操作的結果現在頁面中。也就是需要頻繁的操作DOM
-
MVVM通過
數據雙向綁定
讓數據自動地雙向同步V(修改數據) -> M
M(修改數據) -> V
數據是核心 -
Vue這種MVVM模式的框架,不推薦開發人員手動操作DOM
Vue中的MVVM
雖然沒有完全遵循 MVVM 模型,Vue 的設計無疑受到了它的啓發。因此在文檔中經常會使用 vm (ViewModel 的簡稱) 這個變量名錶示 Vue 實例
學習Vue要轉化思想
- 不要在想着怎麼操作DOM,而是想着如何操作數據!!!
起步 - Hello Vue
- 安裝:
npm i -S vue
<!-- 指定vue管理內容區域,需要通過vue展示的內容都要放到找個元素中 通常我們也把它叫做邊界 數據只在邊界內部解析-->
<div id="app">{{ msg }}</div>
<!-- 引入 vue.js -->
<script src="vue.js"></script>
<!-- 使用 vue -->
<script>
var vm = new Vue({
// el:提供一個在頁面上已存在的 DOM 元素作爲 Vue 實例的掛載目標
el: '#app',
// Vue 實例的數據對象,用於給 View 提供數據
data: {
msg: 'Hello Vue'
}
})
</script>
Vue實例
- 注意 1:先在data中聲明數據,再使用數據
- 注意 2:可以通過 vm.$data 訪問到data中的所有屬性,或者 vm.msg
var vm = new Vue({
data: {
msg: '大家好,...'
}
})
vm.$data.msg === vm.msg // true
數據綁定
- 最常用的方式:Mustache(插值語法),也就是 {{}} 語法
- 解釋:{{}}從數據對象data中獲取數據
- 說明:數據對象的屬性值發生了改變,插值處的內容都會更新
- 說明:{{}}中只能出現JavaScript表達式 而不能解析js語句
- 注意:Mustache 語法不能作用在 HTML 元素的屬性上
<h1>Hello, {{ msg }}.</h1>
<p>{{ 1 + 2 }}</p>
<p>{{ isOk ? 'yes': 'no' }}</p>
<!-- !!!錯誤示範!!! -->
<h1 title="{{ err }}"></h1>
雙向數據綁定 Vue two way data binding
-
雙向數據綁定:將DOM與Vue實例的data數據綁定到一起,彼此之間相互影響
數據的改變會引起DOM的改變
DOM的改變也會引起數據的變化 -
原理:
Object.defineProperty
中的get
和set
方法getter
和setter
:訪問器
作用:指定讀取或設置
對象屬性值的時候,執行的操作
/* defineProperty語法 介紹 */
var obj = {}
Object.defineProperty(obj, 'msg', {
// 設置 obj.msg = "1" 時set方法會被系統調用 參數分別是設置後和設置前的值
set: function (newVal, oldVal) { },
// 讀取 obj.msg 時get方法會被系統調用
get: function ( newVal, oldVal ) {}
})
Vue雙向綁定的極簡實現
<!-- 示例 -->
<input type="text" id="txt" />
<span id="sp"></span>
<script>
var txt = document.getElementById('txt'),
sp = document.getElementById('sp'),
obj = {}
// 給對象obj添加msg屬性,並設置setter訪問器
Object.defineProperty(obj, 'msg', {
// 設置 obj.msg 當obj.msg反生改變時set方法將會被調用
set: function (newVal) {
// 當obj.msg被賦值時 同時設置給 input/span
txt.value = newVal
sp.innerText = newVal
}
})
// 監聽文本框的改變 當文本框輸入內容時 改變obj.msg
txt.addEventListener('keyup', function (event) {
obj.msg = event.target.value
})
</script>
動態添加數據的注意點
-
注意:只有
data
中的數據纔是響應式的,動態添加進來的數據默認爲非響應式 -
可以通過以下方式實現動態添加數據的響應式
Vue.set(object, key, value)
- 適用於添加單個屬性Object.assign()
- 適用於添加多個屬性
var vm = new Vue({
data: {
stu: {
name: 'jack',
age: 19
}
}
})
/* Vue.set */
Vue.set(vm.stu, 'gender', 'male')
/* Object.assign 將參數中的所有對象屬性和值 合併到第一個參數 並返回合併後的對象*/
vm.stu = Object.assign({}, vm.stu, { gender: 'female', height: 180 })
異步DOM更新
-
說明:Vue 異步執行 DOM 更新,監視所有數據改變,一次性更新DOM
-
優勢:可以去除重複數據,對於避免不必要的計算和 避免重複 DOM 操作上,非常重要
-
如果需要拿到更新後dom中的數據 則需要通過 Vue.nextTick(callback):在DOM更新後,執行某個操作(屬於DOM操作)
實例調用vm.$nextTick(function () {})
methods: {
fn() {
this.msg = 'change'
this.$nextTick(function () {
console.log('$nextTick中打印:', this.$el.children[0].innerText);
})
console.log('直接打印:', this.$el.children[0].innerText);
}
}
指令
- 解釋:指令 (Directives) 是帶有 v- 前綴的特殊屬性
- 作用:當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM
v-text
- 解釋:更新DOM對象的 textContent
<h1 v-text="msg"></h1>
v-html
- 解釋:更新DOM對象的 innerHTML
<h1 v-html="msg"></h1>
v-bind
- 作用:當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM
- 語法:
v-bind:title="msg"
- 簡寫:
:title="msg"
<!-- 完整語法 -->
<a v-bind:href="url"></a>
<!-- 縮寫 -->
<a :href="url"></a>
v-on
- 作用:綁定事件
- 語法:
v-on:click="say"
orv-on:click="say('參數', $event)"
- 簡寫:@click=“say”
- 說明:綁定的事件定義在
methods
<!-- 完整語法 -->
<a v-on:click="doSomething"></a>
<!-- 縮寫 -->
<a @click="doSomething"></a>
事件修飾符
.stop
阻止冒泡,調用 event.stopPropagation().prevent
阻止默認行爲,調用 event.preventDefault().capture
添加事件偵聽器時使用事件捕獲
模式.self
只當事件在該元素本身(比如不是子元素)觸發時,纔會觸發事件.once
事件只觸發一次
v-model
- 作用:在表單元素上創建雙向數據綁定
- 說明:監聽用戶的輸入事件以更新數據
- 案例:計算器
<input type="text" v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
v-for
- 作用:基於源數據多次渲染元素或模板塊
<!-- 1 基礎用法 -->
<div v-for="item in items">
{{ item.text }}
</div>
<!-- item 爲當前項,index 爲索引 -->
<p v-for="(item, index) in list">{{item}} -- {{index}}</p>
<!-- item 爲值,key 爲鍵,index 爲索引 -->
<p v-for="(item, key, index) in obj">{{item}} -- {{key}}</p>
<p v-for="item in 10">{{item}}</p>
key屬性
- 推薦:使用 v-for 的時候提供 key 屬性,以獲得性能提升。
- 說明:使用 key,VUE會基於 key 的變化重新排列元素順序,並且會移除 key 不存在的元
素。 - vue key
- vue key屬性的說明
<div v-for="item in items" :key="item.id">
<!-- 內容 -->
</div>
樣式處理 -class和style
- 使用方式:
v-bind:class="expression"
or:class="expression"
- 表達式的類型:字符串、數組、對象(重點)
- 語法:
<!-- 1 -->
<div v-bind:class="{ active: true }"></div> ===> 解析後
<div class="active"></div>
<!-- 2 -->
<div :class="['active', 'text-danger']"></div> ===>解析後
<div class="active text-danger"></div>
<!-- 3 -->
<div v-bind:class="[{ active: true }, errorClass]"></div> ===>解析後
<div class="active text-danger"></div>
--- style ---
<!-- 1 -->
<div v-bind:style="{ color: activeColor, 'font-size': fontSize + 'px' }"></div>
<!-- 2 將多個 樣式對象 應用到一個元素上-->
<!-- baseStyles 和 overridingStyles 都是data中定義的對象 -->
<div v-bind:style="[baseStyles, overridingStyles]"></div>
v-if 和 v-show
- 條件渲染
v-if
:根據表達式的值的真假條件,銷燬或重建元素v-show
:根據表達式之真假值,切換元素的 display CSS 屬性
<p v-show="isShow">這個元素展示出來了嗎???</p>
<p v-if="isShow">這個元素,在HTML結構中嗎???</p>
提升性能:v-pre
- 說明:vue會跳過這個元素和它的子元素的編譯過程。可以用來顯示原始 Mustache 標籤。跳過大量沒有指令的節點會加快編譯。
<span v-pre>{{ this will not be compiled }}</span>
提升性能:v-once
- 說明:vue只渲染元素和組件一次。隨後的重新渲染,元素/組件及其所有的子節點將被視爲靜態內容並跳過。這可以用於優化更新性能。
<span v-once>This will never change: {{msg}}</span>
過濾器 filter
- 作用:文本數據格式化
- 過濾器可以用在兩個地方:{{}}和 v-bind 表達式
- 兩種過濾器:1 全局過濾器 2 局部過濾器
全局過濾器
- 說明:通過全局方式創建的過濾器,在任何一個vue實例中都可以使用
- 注意:使用全局過濾器的時候,需要先創建全局過濾器,再創建Vue實例
- 顯示的內容由過濾器的返回值決定
Vue.filter('filterName', function (value) {
// value 表示要過濾的內容
})
- 示例:
<div>{{ dateStr | date }}</div>
<div>{{ dateStr | date('YYYY-MM-DD hh:mm:ss') }}</div>
<script>
Vue.filter('date', function(value, format) {
// value 要過濾的字符串內容,比如:dateStr
// format 過濾器的參數,比如:'YYYY-MM-DD hh:mm:ss'
})
</script>
局部過濾器
- 說明:局部過濾器是在某一個vue實例的內容創建的,只在當前實例中起作用
{
data: {},
// 通過 filters 屬性創建局部過濾器
// 注意:此處爲 filters
filters: {
filterName: function(value, format) {}
}
}
按鍵值修飾符
- 說明:在監聽鍵盤事件時,Vue 允許爲 v-on 在監聽鍵盤事件時添加關鍵修飾符
- 鍵盤事件 - 鍵值修飾符
- 其他:修飾鍵(.ctrl等)、鼠標按鍵修飾符(.left等)
// 只有在 keyCode 是 13 時調用 vm.submit()
@keyup.13="submit"
// 使用全局按鍵別名
@keyup.enter="add"
---
// 通過全局 config.keyCodes 對象自定義鍵值修飾符別名
Vue.config.keyCodes.f2 = 113
// 使用自定義鍵值修飾符
@keyup.enter.f2="add"
監視數據變化 - watch
- 概述:
watch
是一個對象,鍵是需要觀察的表達式,值是對應回調函數 - 作用:當表達式的值發生變化後,會調用對應的回調函數完成響應的監視操作
- VUE $watch
new Vue({
data: { a: 1, b: { age: 10 } },
watch: {
a: function(val, oldVal) {
// val 表示當前值
// oldVal 表示舊值
console.log('當前值爲:' + val, '舊值爲:' + oldVal)
},
// 監聽對象屬性的變化
b: {
handler: function (val, oldVal) { /* ... */ },
// deep : true表示是否監聽對象內部屬性值的變化
deep: true
},
// 只監視user對象中age屬性的變化
'user.age': function (val, oldVal) {
},
}
})
計算屬性
- 說明:計算屬性是基於它們的依賴進行緩存的,只有在它的依賴發生改變時纔會重新求值
- 注意:Mustache語法({{}})中不要放入太多的邏輯,否則會讓模板過重、難以理解和維護
- 注意:computed中的屬性不能與data中的屬性同名,否則會報錯
- Vue computed屬性原理
var vm = new Vue({
el: '#app',
data: {
firstname: 'jack',
lastname: 'rose'
},
computed: {
fullname() {
return this.firstname + '.' + this.lastname
}
}
})
實例生命週期
- 所有的 Vue 組件都是 Vue 實例,並且接受相同的選項對象即可 (一些根實例特有的選項除外)。
- 實例生命週期也叫做:組件生命週期
生命週期介紹
- vue生命週期鉤子函數
- 簡單說:一個組件從開始到最後消亡所經歷的各種狀態,就是一個組件的生命週期
生命週期鉤子函數的定義:從組件被創建,到組件掛載到頁面上運行,再到頁面關閉組件被卸載,這三個階段總是伴隨着組件各種各樣的事件,這些事件,統稱爲組件的生命週期函數!
- 注意:Vue在執行過程中會自動調用
生命週期鉤子函數
,我們只需要提供這些鉤子函數即可 - 注意:鉤子函數的名稱都是Vue中規定好的!
鉤子函數 - beforeCreate()
- 說明:在實例初始化之後,數據觀測 (data observer) 和 event/watcher 事件配置之前被調用
- 注意:此時,無法獲取 data中的數據、methods中的方法
鉤子函數 - created()
- 注意:這是一個常用的生命週期,可以調用methods中的方法、改變data中的數據
- vue實例生命週期 參考1
- vue實例生命週期 參考2
- 使用場景:發送請求獲取數據
鉤子函數 - beforeMounted()
說明:在掛載開始之前被調用
鉤子函數 - mounted()
說明:此時,vue實例已經掛載到頁面中,可以獲取到el中的DOM元素,進行DOM操作
鉤子函數 - beforeUpdated()
- 說明:數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。你可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
- 注意:此處獲取的數據是更新後的數據,但是獲取頁面中的DOM元素是更新之前的
鉤子函數 - updated()
- 說明:組件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。
鉤子函數 - beforeDestroy()
- 說明:實例銷燬之前調用。在這一步,實例仍然完全可用。
- 使用場景:實例銷燬之前,執行清理任務,比如:清除定時器等
鉤子函數 - destroyed()
- 說明:Vue 實例銷燬後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬。
axios
-
Promise based HTTP client for the browser and node.js
以Promise爲基礎的HTTP客戶端,適用於:瀏覽器和node.js
封裝ajax,用來發送請求,異步獲取數據 -
安裝:
npm i -S axios
// 在瀏覽器中使用,直接引入js文件使用下面的GET/POST請求方式即可
// 1 引入 axios.js
// 2 直接調用axios提供的API發送請求
created: function () {
axios.get(url)
.then(function(resp) {})
}
---
// 配合 webpack 使用方式如下:
import Vue from 'vue'
import axios from 'axios'
// 將 axios 添加到 Vue.prototype 中
Vue.prototype.$axios = axios
---
// 在組件中使用:
methods: {
getData() {
this.$axios.get('url')
.then(res => {})
.catch(err => {})
}
}
---
// API使用方式:
axios.get(url[, config])
axios.post(url[, data[, config]])
axios(url[, config])
axios(config)
Get 請求
const url = 'http://vue.studyit.io/api/getnewslist'
// url中帶有query參數
axios.get('/user?id=89')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// url和參數分離,使用對象
axios.get('/user', {
params: {
id: 12345
}
})
Post 請求
- 不同環境中處理 POST請求
- 默認情況下,axios 會將JS對象序列化爲JSON對象。爲了使用
application/x-www-form-urlencoded
格式發送請求,我們可以這樣:
// 使用 qs 包,處理將對象序列化爲字符串
// npm i -S qs
// var qs = require('qs')
import qs from 'qs'
qs.stringify({ 'bar': 123 }) ===> "bar=123"
axios.post('/foo', qs.stringify({ 'bar': 123 }))
// 或者:
axios.post('/foo', 'bar=123&age=19')
const url = 'http://vue.studyit.io/api/postcomment/17'
axios.post(url, 'content=點個贊不過份')
axios.post('/user', qs.stringify({
firstName: 'Fred',
lastName: 'Flintstone'
}))
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
全局配置
// 設置請求公共路徑:
axios.defaults.baseURL = 'http://vue.studyit.io'
攔截器
- 攔截器會攔截髮送的每一個請求,請求發送之前執行
request
中的函數,請求發送完成之後執行response
中的函數