Vue
1. Vue 定義
官網(wǎng):https://cn.vuejs.org/
Vue (類似于 view) 是一套用于構(gòu)建用戶界面的漸進(jìn)式框架,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用,Vue是mvvm模式的。
2. Vue API
2.1 全局配置
2.2 全局API
2.2.1 filter 過濾器
? Vue.js 允許你自定義過濾器挠日,可被用于一些常見的文本格式化。過濾器可以用在兩個(gè)地方:雙花括號(hào)插值和 v-bind 表達(dá)式 (后者從 2.1.0+ 開始支持)。過濾器應(yīng)該被添加在 JavaScript 表達(dá)式的尾部两蟀,由“管道”符號(hào)指示。
<div id="app">
<ul>
<li
v-for="goods in goodsList"
:key="goods.id"
>
<!-- 在雙花括號(hào)中 -->
<h5>{{goods.title | toUpper}}</h5>
<!-- 豎線之后寫過濾器的名字震缭,就會(huì)把前面值傳遞給過濾器赂毯,
過濾器處理之后再作為插值表達(dá)式來顯示 -->
<p>{{goods.price | toFix}}</p>
</li>
</ul>
</div>
補(bǔ)充:
<!-- 在 `v-bind` 中 待理解-->
<li v-bind:id="rawId | formatId"></li>
const app = new Vue({
el: '#app',
data: {
goodsList: [
{
id: 1,
title: '羅技鼠標(biāo)',
price: 9.9999999999
}
]
},
filters: {
// 定義一個(gè)過濾器,接收要過濾的值拣宰,返回過濾的結(jié)果
toFix (val) {
return val.toFixed(2)
},
toUpper (val) {
return val.toUpperCase()
}
}
})
過濾器是 JavaScript 函數(shù)党涕,因此可以接收參數(shù)。如:
{{ message | filterA('arg1', arg2) }}
filterA 被定義為接收三個(gè)參數(shù)的過濾器函數(shù)巡社。其中 message 的值作為第一個(gè)參數(shù)膛堤,
普通字符串 'arg1' 作為第二個(gè)參數(shù),表達(dá)式 arg2 的值作為第三個(gè)參數(shù)晌该。
2.3 選項(xiàng) / 數(shù)據(jù)
2.3.1 data
? 類型:Object | Function
data => Vue實(shí)例中的數(shù)據(jù)對象肥荔,對象必須是純粹的對象 (含有零個(gè)或多個(gè)的 key/value 對)。
? 注意:data
屬性使用了箭頭函數(shù)气笙,則 this
不會(huì)指向這個(gè)組件的實(shí)例次企,不過你仍然可以將其實(shí)例作為函數(shù)的第一個(gè)參數(shù)來訪問。
? 組件的data必須是一個(gè)方法潜圃。因?yàn)槊總€(gè)組件的數(shù)據(jù)是獨(dú)立的缸棵,使用方法可以保證不共享,在data里return一個(gè)對象谭期。復(fù)用組件時(shí)堵第,data必須是個(gè)函數(shù)(function)
var data = { a: 1 }
// 直接創(chuàng)建一個(gè)實(shí)例
var vm = new Vue({
data: data
})
vm.a // => 1
vm.$data === data
2.3.2 methods 事件處理器
? 類型:{ [key: string]: Function }
? methods是用來寫方法的地方,可以在其他地方調(diào)用這里的方法隧出。methods 將被寫到 Vue 實(shí)例中踏志。可以直接通過 VM 實(shí)例訪問這些方法胀瞪,或者在指令表達(dá)式中使用针余。方法中的 this
自動(dòng)綁定為 Vue 實(shí)例饲鄙。
? 注意:不應(yīng)該使用箭頭函數(shù)來定義 method 函數(shù) (例如 plus: () => this.a++
)。理由是箭頭函數(shù)綁定了父級(jí)作用域的上下文圆雁,所以 this
將不會(huì)按照期望指向 Vue 實(shí)例忍级,this.a
將是 undefined。
var vm = new Vue({
data: { a: 1 },
methods: {
plus: function () {
this.a++
}
}
})
vm.plus() // 調(diào)用方法
vm.a // 輸出 2
2.3.3 computed 計(jì)算屬性
? 類型:{ [key: string]: Function | { get: Function, set: Function } }
? 計(jì)算屬性將被寫到 Vue 實(shí)例中伪朽。所有 get 和 set 的 this 上下文自動(dòng)地綁定為 Vue 實(shí)例轴咱。計(jì)算屬性每次的計(jì)算結(jié)果都會(huì)被緩存,除非依賴的響應(yīng)式屬性變化才會(huì)重新計(jì)算烈涮。注意朴肺,如果某個(gè)依賴 (比如非響應(yīng)式屬性) 在該實(shí)例范疇之外,則計(jì)算屬性是不會(huì)被更新的坚洽。
? 注意:一個(gè)計(jì)算屬性如果使用了箭頭函數(shù)戈稿,則 this
不會(huì)指向這個(gè)組件的實(shí)例,不過你仍然可以將其實(shí)例作為函數(shù)的第一個(gè)參數(shù)來訪問酪术。
var vm = new Vue({
data: { a: 1 },
computed: {
// 僅讀取
aDouble: function () {
return this.a * 2
},
// 讀取和設(shè)置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3 // 設(shè)置計(jì)算結(jié)果為 3
vm.a // 所以輸出a => 2
vm.aDouble // => 4
2.3.4 watch 偵聽屬性
? 類型:{ [key: string]: string | Function | Object | Array }
? watch 用于監(jiān)聽(觀察)某個(gè)屬性是否發(fā)生改變器瘪,發(fā)生改變就做出相應(yīng)的操作來響應(yīng)這個(gè)數(shù)據(jù)變化。一個(gè)對象绘雁,鍵是需要觀察的表達(dá)式橡疼,值是對應(yīng)回調(diào)函數(shù)、方法名或者包含選項(xiàng)的對象庐舟。Vue 實(shí)例將會(huì)在實(shí)例化時(shí)調(diào)用 $watch()
欣除,遍歷 watch 對象的每一個(gè)屬性是否發(fā)生數(shù)據(jù)變化,并做出響應(yīng)挪略。
? 注意:不應(yīng)該使用箭頭函數(shù)來定義 watcher 函數(shù) (例如 searchQuery: newValue => this.updateAutocomplete(newValue)
)历帚。理由是箭頭函數(shù)綁定了父級(jí)作用域的上下文,所以 this
將不會(huì)按照期望指向 Vue 實(shí)例杠娱,this.updateAutocomplete
將是 undefined挽牢。
<div id="app">
<label>姓:<input type="text" v-model="xing"></label><br>
<label>名:<input type="text" v-model="ming"></label><br>
<label>姓名:<input type="text" v-model="name"></label><br>
</div>
const app = new Vue({
el: '#app',
data: {
xing: '',
ming: '',
name:''
},
watch: {
// 監(jiān)聽值的修改
// 只要值發(fā)生了改變,都會(huì)執(zhí)行這個(gè)方法
xing (nVal, oVal) {
console.log(nVal, oVal)
// 姓發(fā)生了改變
this.name = nVal + this.ming
},
ming (nVal) {
this.name = this.xing + nVal
},
name (nVal) {
this.xing = nVal.slice(0, 1)
this.ming = nVal.slice(1)
}
}
})
2.3.5 props
類型:Array<string> | Object
? props 可以是數(shù)組或?qū)ο筇螅糜诮邮諄碜愿附M件的數(shù)據(jù)禽拔。props 可以是簡單的數(shù)組,或者使用對象作為替代室叉,對象允許配置高級(jí)選項(xiàng)睹栖,如類型檢測、自定義驗(yàn)證和設(shè)置默認(rèn)值茧痕。
基于對象的語法使用以下選項(xiàng):
-
type
: 校驗(yàn)數(shù)據(jù)類型野来。可以是下列原生構(gòu)造函數(shù)中的一種:String
踪旷、Number
曼氛、Boolean
豁辉、Array
、Object
搪锣、Date
秋忙、Function
彩掐、Symbol
构舟、任何自定義構(gòu)造函數(shù)、或上述內(nèi)容組成的數(shù)組堵幽。 -
default
:any
prop 指定一個(gè)默認(rèn)值狗超。 -
required
:Boolean
定義該 prop 是否是必填項(xiàng)。 -
validator
:Function
自定義驗(yàn)證函數(shù)會(huì)將該 prop 的值作為唯一的參數(shù)代入朴下。
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
? props 使用 DOM 中的模板時(shí)努咐,camelCase (駝峰命名法) 的 prop 名需要使用其等價(jià)的 kebab-case (短橫線分隔命名) 命名:
<!-- 在 html 中是 post-title 的 -->
<blog-post post-title="hello!"></blog-post>
Vue.component('blog-post', {
// 在 JavaScript 中是 postTitle 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
? props 是單向數(shù)據(jù)流, 所有的prop都使得其父子 prop 之間形成了一個(gè)單向下行綁定:父級(jí) prop 的更新會(huì)向下流動(dòng)到子組件中殴胧,但是反過來則不行渗稍。所以props可用于組件傳參(父 => 子)。
2.4 特殊特性
2.4.1 ref
ref
被用來給元素或子組件注冊引用信息团滥。引用信息將會(huì)注冊在父組件的 $refs
對象上竿屹。如果用在子組件上,引用就指向組件實(shí)例灸姊。
在普通的 DOM 元素上使用拱燃,引用指向的就是 DOM 元素。
<div id="app">
<input type="text" ref="add" value="hello">
</div>
new Vue ({
el: '#app',
data: {
},
methods: {
// 取到input這個(gè)DOM元素
this.$refs.add.focus()
}
})
3. Vue的基礎(chǔ)使用
3.1 引入Vue
<!-- 開發(fā)環(huán)境版本力惯,包含了有幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或者保存 Vue.js 到本地碗誉,本地調(diào)用也可
3.2 聲明式渲染
? 聲明式渲染 就是利用插值表達(dá)式進(jìn)行數(shù)據(jù)渲染
Vue.js 的核心是一個(gè)允許采用簡潔的模板語法來聲明式地將數(shù)據(jù)渲染進(jìn) DOM 的系統(tǒng):
<div id="app">
{{ message }} <!-- 插值表達(dá)式 -->
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
輸出:Hello Vue!
注意:此時(shí)數(shù)據(jù)和 DOM 已經(jīng)被建立了關(guān)聯(lián),所有東西都是響應(yīng)式的父晶。如:修改 app.message 的值哮缺,輸出信息也會(huì)更改。
3.3 Vue 實(shí)現(xiàn)雙向綁定的原理(插值表達(dá)式的原理):
? Vue的雙向綁定是基于defineProperty實(shí)現(xiàn)的甲喝。流程如下:
注意:defineProperty是用來給一個(gè)對象定義屬性的尝苇。基于defineProperty的get/set實(shí)現(xiàn)
3.4 模板語法
? Vue.js 使用了基于 HTML 的模板語法俺猿,允許開發(fā)者聲明式地將 DOM 綁定至底層 Vue 實(shí)例的數(shù)據(jù)茎匠。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循規(guī)范的瀏覽器和 HTML 解析器解析押袍。
? 在底層的實(shí)現(xiàn)上诵冒,Vue 將模板編譯成虛擬 DOM 渲染函數(shù)。結(jié)合響應(yīng)系統(tǒng)谊惭,Vue 能夠智能地計(jì)算出最少需要重新渲染多少組件汽馋,并把 DOM 操作次數(shù)減到最少侮东。
3.4.1 插值表達(dá)式
數(shù)據(jù)綁定最常見的形式就是使用“Mustache”語法 (雙大括號(hào)) 的文本插值:
<div id="app">
{{ message }} ——插值表達(dá)式
</div>
注:插值表達(dá)式里面代表是javascript表達(dá)式。所以字符要加引號(hào)
<div id="app">
{{isHandsome}} <br>
{{1+1}} <br>
{{isHandsome && 'you are right'}} <br>
{{1 + 1 !== 2 ? '你算對了' : '回去讀小班'}} <br>
</div>
3.4.2 template標(biāo)簽
template標(biāo)簽豹芯,HTML5提供的新標(biāo)簽悄雅,更加規(guī)范和語義化 ;可以把列表項(xiàng)放入template標(biāo)簽中铁蹈,然后進(jìn)行批量渲染宽闲。
<template id="tem">
<div id="app">
<h1 id="title">hello world!</h1>
</div>
</template>
打開網(wǎng)頁,會(huì)發(fā)現(xiàn)在瀏覽器并沒有渲染出任何信息握牧,這是因?yàn)閠emplate標(biāo)簽內(nèi)容天生不可見容诬,設(shè)置了display:none;屬性沿腰。
var tem =document.getElementById("tem");//獲取template標(biāo)簽
var title = tem.content.getElementById("title"); //在template標(biāo)簽內(nèi)部內(nèi)容览徒,必須要用.content屬性才可以訪問到
console.log(title); //找到h1
template標(biāo)簽中的 元素是被當(dāng)做一個(gè)不可見的包裹元素,主要用于分組的條件判斷和列表渲染颂龙。
3.5 Vue 指令
? Vue.js的指令 (Directives) 是帶有 v-
前綴的特殊特性习蓬。指令特性的值預(yù)期是單個(gè) JavaScript 表達(dá)式 (v-for
是例外情況)。指令的職責(zé)是措嵌,當(dāng)表達(dá)式的值改變時(shí)躲叼,將其產(chǎn)生的連帶影響,響應(yīng)式地作用于 DOM铅匹。
3.5.1 v-text
? v-text 更新元素文本內(nèi)容, 讓元素的文本內(nèi)容顯示屬性的內(nèi)容押赊。
<div id="app">
<!-- 插值表達(dá)式不會(huì)解析html字符串,當(dāng)作普通文本在渲染 -->
{{str}} 輸出結(jié)果:<b>hello</b>
<!-- 指令包斑,指令里面是javascript 所以str要加引號(hào)-->
<p v-text="str"></p> 輸出結(jié)果:<b>hello</b>
<!-- 由于v-text里面必須放javascript流礁,所以會(huì)把內(nèi)容當(dāng)然屬性或者方法去讀取,因此下面這行代碼會(huì)報(bào)錯(cuò) -->
<p v-text="你真帥"></p> 輸出結(jié)果:報(bào)錯(cuò)
<!-- 當(dāng)指令和插值表達(dá)式同時(shí)存在的時(shí)候指令生效 -->
<p v-text="'你真帥'">{{str}}</p> 輸出結(jié)果:你真帥
</div>
const app = new Vue({
el: '#app',
data: {
str: '<b>hello</b>'
}
})
3.5.2 v-html
? 雙大括號(hào)會(huì)將數(shù)據(jù)解釋為普通文本罗丰,而非 HTML 代碼神帅。為了輸出真正的 HTML,你需要使用 v-html
指令:
<div id="app">
<!-- v-html能解析html字符串 -->
<p v-html="str"></p> 輸出結(jié)果:加粗的 hello
</div>
3.5.3 條件渲染 v-if(else) / v-show
v-if(else)
? v-if
指令用于條件性地渲染一塊內(nèi)容萌抵。這塊內(nèi)容只會(huì)在指令的表達(dá)式返回 true 值的時(shí)候被渲染找御。
? v-if
是通過是否渲染來決定顯示隱藏。v-show
是一定會(huì)渲染绍填,通過display樣式來決定是否顯示隱藏霎桅。
<div id="app">
<div v-if="false">這是一個(gè)彈框1</div> false 不渲染顯示
<div v-if="1 + 1 === 2">這是一個(gè)彈框2</div> true 渲染顯示
</div>
? 也可以用 v-else
添加一個(gè)“else 塊”,v-else
元素必須緊跟在帶 v-if
或者 v-else-if
的元素的后面讨永,否則它將不會(huì)被識(shí)別滔驶。v-else指令與v-if或者v-show同時(shí)使用,v-if條件不成立則會(huì)顯示v-else內(nèi)容卿闹。
<div id="app">
<!-- false, 渲染else揭糕;true徘钥,渲染if -->
<div v-if="isModelShow">這是一個(gè)彈框4</div>
<!-- v-else只作用與上一個(gè)兄弟元素的v-if -->
<div v-else>這事跟彈框4相反的一個(gè)顯示</div>
</div>
const app = new Vue({
el: '#app',
data: {
isModelShow: false
}
})
v-show
? 用于根據(jù)條件展示元素的選項(xiàng)是 v-show
指令蝗蛙。用法跟v-if
大致一樣:
<div id="app">
<div v-show="true">這是一個(gè)彈框5</div> 顯示
<div v-show="1 + 1 === 3">這是一個(gè)彈框6</div> 隱藏
</div>
注意:v-show
不支持 <template>
元素蹈矮,也不支持 v-else
技俐。
v-if
與v-show
的區(qū)別:
? v-show
不管條件是否成立,都會(huì)渲染html吏口,而v-if
只有條件成立才會(huì)渲染奄容。
? v-show
的元素始終會(huì)被渲染并保留在 DOM 中。v-show
只是簡單地切換元素的 CSS 屬性 display
锨侯。
? 非常頻繁地切換顯示隱藏嫩海,則使用 v-show
較好;反之囚痴,則使用 v-if
較好。
3.5.4 v-for 列表渲染 (循環(huán))
v-for
指令根據(jù)一組數(shù)組的選項(xiàng)列表進(jìn)行渲染审葬。v-for
指令需要使用 item in items
形式的特殊語法深滚,items
是源數(shù)據(jù)數(shù)組并且 item
是數(shù)組元素迭代的別名。
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
輸出結(jié)果: ·Foo
·Bar
v-for
可以循環(huán)字符串 涣觉、數(shù)字痴荐、對象、數(shù)組等官册。
v-for
也可以循環(huán)數(shù)字生兆。在這種情況下,它將重復(fù)多次模板膝宁。
<div id="app">
<span v-for="n in 10">{{ n }} </span>
</div>
例:v-for
循環(huán)對象鸦难,可以遍歷 索引、鍵名员淫、屬性合蔽。
<div id="app">
<!-- 給每一個(gè)循環(huán)動(dòng)態(tài)綁定一個(gè)唯一的key,這個(gè)key一般是一條數(shù)據(jù)的id,或者name,title之類的唯一標(biāo)識(shí) -->
<div v-for="(value, key, index) in person" v-bind:key="obj.id">
{{ index }}.{{ key }}: {{ value }}
</div>
<!-- 循環(huán)data數(shù)據(jù),得到索引和元素值介返,循環(huán)渲染當(dāng)前標(biāo)簽 -->
<div v-for="(value, key) in person" :key="like.id">
{{ key }}: {{ value }}
</div>
</div>
new Vue({
el: '#app',
data: {
person: {
name: '小明',
age: 20,
gender: '男'
}
}
})
3.5.5 v-model 表單輸入綁定
v-model
指令用于表單 <input>
拴事、<textarea>
及 <select>
元素上創(chuàng)建雙向數(shù)據(jù)綁定。它會(huì)根據(jù)控件類型自動(dòng)選取正確的方法來更新元素圣蝎。它負(fù)責(zé)監(jiān)聽用戶的輸入事件以更新數(shù)據(jù)刃宵,并對一些極端場景進(jìn)行一些特殊處理。
v-model
在內(nèi)部為不同的輸入元素使用不同的屬性并拋出不同的事件:
text 和 textarea 元素使用
value
屬性和input
事件徘公;checkbox 和 radio 使用
checked
屬性和change
事件牲证;-
select 字段將
value
作為 prop 并將change
作為事件。1. input文本應(yīng)用
<!-- 輸入框的v-model指令負(fù)責(zé)綁定value --> <!-- 雙向綁定步淹,用戶在input里輸入值會(huì)自動(dòng)綁定到data上 --> <div id="app"> <input type="text" v-model="username"> {{username}} </div>
const app = new Vue({ el: '#app', data: { username: 'zhangsan' } })
2.多行文本 textarea
<span>Multiline message is:</span> <p style="white-space: pre-line;">{{ message }}</p> <br> <textarea v-model="message" placeholder="add multiple lines"></textarea>
3.復(fù)選框 checkbox
單個(gè)復(fù)選框从隆,綁定到布爾值 true 選中诚撵,false 未選中 <!-- v-model使用在checkbox上的時(shí)候代表多選框的選中狀態(tài),綁定的是checked屬性 --> <input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}</label>
多個(gè)復(fù)選框键闺,綁定到同一個(gè)數(shù)組: <!-- v-model可以使用一個(gè)數(shù)組來綁定多選按鈕寿烟,選中的value值就會(huì)存在這個(gè)數(shù)組里 --> <div id='example-3'> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div>
new Vue({ el: '#example-3', data: { checkedNames: [] } })
4.單選按鈕 radio
<div id="example-4"> <input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> <br> <span>Picked: {{ picked }}</span> </div>
new Vue({ el: '#example-4', data: { picked: '' } })
5.下拉菜單 select
<!-- v-model用在select上,綁定的就是選中的那個(gè)option的value --> <div id="example-5"> <select v-model="selected"> <option disabled value="">請選擇</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> </div>
new Vue({ el: '...', data: { selected: '' } })
3.5.6 v-clock
v-clock
指令可以解決使用插值表達(dá)式頁面閃爍問題(解決頁面卡頓給用戶帶來不好體驗(yàn))辛燥。
方法:將該指令加在html標(biāo)簽中時(shí)筛武,可以在該文件中加style屬性為display:none。
[v-cloak] {
display: none;
}
<!-- 加上v-cloak這個(gè)指令以后挎塌,在vue實(shí)例化之前div身上就會(huì)有v-cloak這個(gè)屬性徘六,實(shí)例化之后這個(gè)屬性就會(huì)被移除
-->
<div id="app" v-cloak>
{{msg}}
</div>
const app = new Vue({
el: '#app',
data: {
msg: 'hello world'
}
})
3.5.7 v-bind 屬性綁定
v-bind
用于動(dòng)態(tài)地綁定一個(gè)或多個(gè)特性,v-bind用來綁定一個(gè)屬性榴都,屬性值作為JavaScript去執(zhí)行待锈。
可以在其名稱后面帶一個(gè)參數(shù),中間放一個(gè)冒號(hào)隔開嘴高,這個(gè)參數(shù)通常是HTML元素的特性(attribute)竿音,如v-bind: class 、v-bind: src 等拴驮。 注意:class可以和v-bind:class同時(shí)存在春瞬,疊加渲染。
1. 綁定屬性 (如:href套啤、src)
<div id="app">
<a v-bind:href = "baiduLink">百度一下</a>
<!-- v-bind 簡寫為 : -->
<a :href = "baiduLink">百度一下</a>
<img :src="imgUrl" alt="">
</div>
const app = new Vue({
el: '#app',
data: {
baiduLink:'https://www.baidu.com/',
imgUrl:'https://ss3.baidu.com/-rVXeDTa2gU2pMbgoY3K/it/u=1488861817,1113726833&fm=202'
}
})
2. 綁定 style - Class
.box {
width: 200px;
height: 200px;
background: red;
margin-bottom: 10px;
}
.ac {
background: green;
}
<div id="app">
<!-- 綁定class名稱 -->
<div :class="'box'"></div>
<div :class="className"></div>
<!-- 可以綁定一個(gè)對象,通過isAc的boolean來決定ac是否存在 -->
<div :class="{ac: isAc}"></div>
<!-- 普通class和綁定class可以共存,最后把兩部分疊加渲染 -->
<div class="box" :class="{ac: isAc}"></div>
<!-- 這個(gè)是最復(fù)雜的用法,綁定一個(gè)數(shù)組,數(shù)組元素可以直接是class名稱就能直接綁定,如果另外一個(gè)class根 據(jù)數(shù)據(jù)決定,那就再寫一個(gè)對象 -->
<div :class="[className, {ac: isAc}]"></div>
<p :style="style">Lorem ipsum dolor</p>
</div>
const app = new Vue({
el: '#app',
data: {
className: 'box',
isAc: false,
style: {
width: '100px',
height: '100px',
color: 'red'
}
}
})
3.5.8 v-on 事件監(jiān)聽
v-on
指令用于監(jiān)聽 DOM 事件宽气,并在觸發(fā)時(shí)運(yùn)行一些 JavaScript 代碼。例如給button添加點(diǎn)擊事件
<button v-on:click="show">
<!-- v-on:click指令可以簡寫為@click潜沦,修改代碼:-->
<button @click="show">
? 許多事件處理邏輯會(huì)更為復(fù)雜萄涯,所以直接把 JavaScript 代碼寫在 v-on
指令中是不可行的。因此 v-on
還可以接收一個(gè)需要調(diào)用的方法名稱止潮。
<div id="app">
<button v-on:click="onNumDecrease">decrease</button>
{{num}}
<button @click="onNumAdd(12, $event)">Add</button>
</div>
const app = new Vue({
el: '#app',
data: {
num: 1
},
methods: {
// 定義當(dāng)前vue實(shí)例的方法
onNumDecrease (e) {
// 事件處理函數(shù)在v-on監(jiān)聽的時(shí)候不寫括號(hào),函數(shù)的第一個(gè)參數(shù)就是事件對象
console.log(e)
// this.$data.num
this.num--
},
onNumAdd (n, e) {
// 事件處理函數(shù)在v-on監(jiān)聽的時(shí)候?qū)懥死ㄌ?hào),那就可以傳參,而且傳一個(gè)特殊變量$event就是事件對象
console.log(n)
console.log(e)
}
}
})
3.5.9 事件修飾符
? 事件處理程序中經(jīng)常需要處理默認(rèn)事件等窃判,為了解決這個(gè)問題,Vue.js 為 v-on
提供了事件修飾符喇闸。之前提過袄琳,修飾符是由點(diǎn)開頭的指令后綴來表示的。事件修飾符監(jiān)聽事件的同時(shí)就阻止默認(rèn)事件等燃乍。
? 常用事件修飾符有:.stop 唆樊、 .prevent 、 .capture 刻蟹、.self 逗旁、.once 、.passive 。
.stop 防止事件冒泡
? 冒泡事件:嵌套兩三層父子關(guān)系片效,然后所有都有點(diǎn)擊事件红伦,點(diǎn)擊子節(jié)點(diǎn),就會(huì)觸發(fā)從內(nèi)至外 子節(jié)點(diǎn) => 父節(jié)點(diǎn)的點(diǎn)擊事件淀衣。
<!-- 阻止單擊事件繼續(xù)傳播 阻止冒泡 -->
<a v-on:click.stop="doThis"></a>
.prevent 阻止默認(rèn)事件
.prevent
等同于JavaScript的event.preventDefault()
昙读,用于取消默認(rèn)事件。
<!-- 提交事件不再重載頁面 阻止默認(rèn)提交-->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 點(diǎn)擊右鍵不再出現(xiàn)菜單 阻止右鍵菜單-->
<p @contextmenu.prevent="onCM">Lorem ipsum dolor</p>
.capture 捕獲事件
捕獲事件:嵌套兩三層父子關(guān)系膨桥,然后所有都有點(diǎn)擊事件蛮浑,點(diǎn)擊子節(jié)點(diǎn),就會(huì)觸發(fā)從外至內(nèi) 父節(jié)點(diǎn) => 子節(jié)點(diǎn)的點(diǎn)擊事件
<!-- 添加事件監(jiān)聽器時(shí)使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處理只嚣,然后才交由內(nèi)部元素進(jìn)行處理 -->
<div v-on:click.capture="doThis">...</div>
.self 觸發(fā)事件
.self
只會(huì)觸發(fā)自己范圍內(nèi)的事件沮稚,不會(huì)包含子元素。
<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>
注意:
使用修飾符時(shí)册舞,順序很重要蕴掏;相應(yīng)的代碼會(huì)以同樣的順序產(chǎn)生。因此环础,
用 v-on:click.prevent.self 會(huì)阻止所有的點(diǎn)擊囚似,
而 v-on:click.self.prevent 只會(huì)阻止對元素自身的點(diǎn)擊。
.once 只執(zhí)行一次點(diǎn)擊
如果我們在@click
事件上添加.once
修飾符线得,只要點(diǎn)擊按鈕只會(huì)執(zhí)行一次。
<!-- 點(diǎn)擊事件將只會(huì)觸發(fā)一次 -->
<a v-on:click.once="doThis"></a>
.passive 新增
<!-- 滾動(dòng)事件的默認(rèn)行為 (即滾動(dòng)行為) 將會(huì)立即觸發(fā) -->
<!-- 而不會(huì)等待 `onScroll` 完成 -->
<!-- 這其中包含 `event.preventDefault()` 的情況 -->
<div v-on:scroll.passive="onScroll">...</div>
這個(gè) .passive
修飾符能夠提升移動(dòng)端的性能徐伐。
? 注意:不要把 .passive
和 .prevent
一起使用贯钩,因?yàn)?.prevent
將會(huì)被忽略,同時(shí)瀏覽器可能會(huì)向你展示一個(gè)警告办素。請記住角雷,.passive
會(huì)告訴瀏覽器你不想阻止事件的默認(rèn)行為。
3.5.10 v-on:keyup 按鍵修飾符
在監(jiān)聽鍵盤事件時(shí)性穿,我們經(jīng)常需要檢查詳細(xì)的按鍵勺三。Vue 允許為 v-on
在監(jiān)聽鍵盤事件時(shí)添加按鍵修飾符⌒柙可以使用按鍵名吗坚,也可使用按鍵碼。
常用按鍵名:enter 呆万、tab 商源、delete 、esc 谋减、space 牡彻、left 、up 出爹、right 庄吼、down
常用按鍵碼:13(enter ) 缎除、 37-40(左上右下)
<!-- 只有在 `key` 是 `Enter` 時(shí)調(diào)用 `vm.submit()` -->
<!-- 按下 enter,提交表單 -->
<input @keyup.enter="submit">
<!-- 按下 enter总寻,提交表單 -->
<input v-on:keyup.13="submit">
4. Vue 組件
4.1 組件概念
? 組件是可復(fù)用的 Vue 實(shí)例器罐,且?guī)в幸粋€(gè)名字。我們可以在一個(gè)通過 new Vue
創(chuàng)建的 Vue 根實(shí)例(父組件)中废菱,把這個(gè)組件作為自定義元素來使用技矮。
? data 方法
? 一個(gè)組件的 data 選項(xiàng)必須是一個(gè)函數(shù),函數(shù)體內(nèi) return一個(gè)對象殊轴。因?yàn)榻M件里的數(shù)據(jù)是獨(dú)立的衰倦,使用方法可以保證不共享,其他地方不能調(diào)用這個(gè)data的數(shù)據(jù)旁理。
data () {
return {
}
}
4.2 組件注冊
為了能在模板中使用樊零,這些組件必須先注冊以便 Vue 能夠識(shí)別。這里有兩種組件的注冊類型:全局注冊和局部注冊孽文。
4.2.1 全局注冊
? 用 Vue.component
來創(chuàng)建的組件驻襟,叫做全局組件,全局組件可以在全局內(nèi)使用芋哭。全局組件可以用在任何新創(chuàng)建的 Vue 根實(shí)例 (new Vue
) 的模板(包括組件樹中的所有子組件的模板)中沉衣。
創(chuàng)建方法:
// Vue.component 的第一個(gè)參數(shù)是組件名,第二個(gè)參數(shù)是一個(gè)對象
Vue.component('my-component-name', {
// ... 選項(xiàng) ...
})
// 組件名可以駝峰命名减牺,也可以中線連接(在HTML中使用組件時(shí)駝峰命名需變?yōu)?my-component-name)
Vue.component('MyComponentName', { /* ... */ })
范例:
<div id="app">
<hello-world></hello-world>
</div>
<script>
// 注冊全局組件
Vue.component('HelloWorld', {
template: '<div>{{msg}}</div>',
// 組件的data必須是一個(gè)方法豌习,因?yàn)槊總€(gè)組件的數(shù)據(jù)是獨(dú)立的,使用方法可以保證不共享拔疚,return一個(gè)對象
data () {
return {
msg: 'hello'
}
}
})
const app = new Vue({
el: '#app',
data: {
msg1: 'hello'
}
})
</script>
4.2.2 局部注冊
? 局部注冊組件就只能在當(dāng)前實(shí)例里面使用肥隆,局部注冊的組件在其他子組件中不可用。
創(chuàng)建方法:
// 局部注冊組件
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
// 局部注冊的組件在其他子組件中不可用
'component-a': ComponentA
},
// ...
}
// new 一個(gè)Vue實(shí)例
new Vue({
el: '#app',
components: {
// 在父組件中使用子組件 A B
'component-a': ComponentA,
'component-b': ComponentB
}
})
范例:
<div id="app">
<!-- 這里打印出 hello world -->
<hello-world></hello-world>
<!-- 下面這個(gè)地方不能解析稚失,因?yàn)檫@個(gè)組件是app1局部的 -->
<hello-vue></hello-vue>
</div>
<div id="app1">
<!-- 這里打印出 hello world -->
<hello-world></hello-world>
<!-- 這里打印出 hello vue -->
<hello-vue></hello-vue>
</div>
<script>
Vue.component('HelloWorld', {
template: '<div>hello world</div>'
})
// 定義一個(gè)組件
const HelloVue = {
template: '<h2>hello Vue</h2>'
}
const app = new Vue({
el: '#app',
data: {
}
})
const app1 = new Vue({
el: '#app1',
components: {
// 這里用到解構(gòu)賦值
HelloVue
}
})
</script>
注意:注冊的組件大駝峰命名栋艳,在html
里面使用這個(gè)組件的時(shí)候需要把大寫變?yōu)樾?/strong>,然后使用中線連接句各。
? 每個(gè)template
里面一般都有一個(gè)div進(jìn)行外層包裹吸占。
4.3 組件傳遞數(shù)據(jù)
4.3.1 通過 Prop 向子組件傳遞數(shù)據(jù)(父 => 子)
props:
? 處理數(shù)據(jù)傳輸,使用這個(gè)組件的時(shí)候把父組件定義的msg
傳遞給組件內(nèi)部诫钓,在組件內(nèi)部通過props來接收旬昭, 組件內(nèi)部的props可以直接作為data使用。
當(dāng)以綁定的方式傳遞菌湃,這個(gè)時(shí)候會(huì)把app
實(shí)例中的data的數(shù)據(jù)傳遞過去问拘。
注意:每個(gè)子組件都必須在父組件里進(jìn)行注冊。
示例:
<div id="app">
<!-- 打印出 hello component -->
<hello-world msg="hello component"></hello-world>
<!-- 打印出 hello -->
<hello-world :msg="msg1"></hello-world>
</div>
<script>
const HelloWorld = {
template: '<div>{{msg}}</div>',
props: ['msg']
}
const app = new Vue({
el: '#app',
data: {
msg1: 'hello'
},
components: {
HelloWorld
}
})
</script>
如果要傳遞數(shù)字或boolean需要綁定,否則傳遞過去后會(huì)解析成字符串骤坐。?
props配置屬性時(shí)绪杏,可以校驗(yàn)數(shù)據(jù)類型,是否必須傳 required: true纽绍;或者default:0 默認(rèn)值蕾久。
示例:
<!-- 傳遞數(shù)字或者boolean需要綁定,否則傳遞過去以后解析成字符串 -->
<hello-world msg="hello component" :num="3"></hello-world>
<!-- props中配置屬性 -->
props: {
msg: {
type: String,
required: true // 這里代表必傳
},
num: {
type: Number,
default: 0 // 這里代表不傳時(shí)拌夏,默認(rèn)為0
},
isCompleted: Boolean
}
}
props綁定駝峰方式要改寫成中線僧著;html
屬性名用中線連接,js
使用駝峰障簿。
示例:
<div id="app">
<!-- html屬性名用中線 -->
<hello-world :user-name="userName"></hello-world>
</div>
<script>
const HelloWorld = {
template: '<div>{{userName}}</div>',
// 這里的javascript使用駝峰
props: ['userName']
}
const app = new Vue({
el: '#app',
data: {
userName: 'xiaoming'
},
components: {
HelloWorld
}
})
</script>
4.3.2 通過$emit 向父組件傳遞數(shù)據(jù)(子 => 父)
$emit
emit 監(jiān)聽子組件事件
? 由于props
是單向的數(shù)據(jù)流盹愚,只能單向響應(yīng)父組件向子組件的數(shù)據(jù)傳遞。不能響應(yīng)子組件向父組件的數(shù)據(jù)傳遞站故。
? 所以如果需要子組件向父組件進(jìn)行數(shù)據(jù)響應(yīng)皆怕,就得使用$emit這個(gè)自定義屬性,利用這個(gè)自定義屬性發(fā)出一個(gè)emit事件西篓,事件命名要用中線連接而不用駝峰愈腾。
然后在父組件中監(jiān)聽子組件的自定義事件,當(dāng)子組件emit
這個(gè)事件的時(shí)候岂津,父組件的這個(gè)方法就會(huì)響應(yīng)執(zhí)行虱黄;
父組件中能響應(yīng)子組件對數(shù)據(jù)的修改,并且函數(shù)方法的第一個(gè)參數(shù)就是自定義事件傳遞過來的參數(shù)吮成。
注意:子組件的props
一般不允許修改礁鲁。
示例:
<div id="app">
<!-- 監(jiān)聽 num-add 這個(gè)事件 父組件響應(yīng)事件的方法onParentAddNum-->
<hello-world :num="num" @num-add="onParentAddNum"></hello-world>
{{num}}
</div>
<script>
const HelloWorld = {
template: '<div>{{num}}<button @click="onAddNum">Add</button></div>',
props: ['num'],
methods: {
onAddNum () {
// 自定義emit事件 事件名 num-add
this.$emit('num-add', {
num: this.num + 1
})
}
}
}
const app = new Vue({
el: '#app',
data: {
num: 1
},
methods: {
// 監(jiān)聽事件 響應(yīng)方法
onParentAddNum (data) {
this.num = data.num
}
},
components: {
HelloWorld
}
})
</script>
4.3.3 通過 bus 向兄弟組件傳遞數(shù)據(jù)(兄 => 弟)
event bus 事件總線
事件總線就是利用空的Vue實(shí)例來進(jìn)行兩個(gè)兄弟組件之間的數(shù)據(jù)傳輸 。
方法:
創(chuàng)建一個(gè)空的Vue實(shí)例 const bus = new Vue()赁豆;
在第一個(gè)兄弟組件中使用bus觸發(fā)一個(gè)emit自定義事件 bus.$emit;
-
在第二個(gè)兄弟組件中使用$bus.on進(jìn)行監(jiān)聽(這個(gè)方法寫在created(){}中)冗美;
解釋:created() 這里的代碼是Vue實(shí)例創(chuàng)建之后執(zhí)行的
在點(diǎn)擊的時(shí)候就會(huì)觸發(fā)這個(gè)事件魔种,第二個(gè)兄弟組件就能響應(yīng)這個(gè)事件;
第二個(gè)兄弟組件一上來就需要監(jiān)聽事件總線的事件粉洼,響應(yīng)第一個(gè)兄弟組件里通過bus給它的emit的這個(gè)事件节预,就可以接收到傳遞給它的參數(shù)
data
。
示例:
<div id="app">
<ge></ge>
<di></di>
</div>
<script>
const bus = new Vue()
const ge = {
template: '<div><span @click="onDawodi">打我弟</span></div>',
methods: {
onDawodi () {
//
bus.$emit('wuwuwu', {
kusheng: 'yinyinyin'
})
}
}
}
const di = {
template: '<div><span>{{ku}}</span></div>',
data () {
return {
ku: ''
}
},
created () {
// 初始化 就監(jiān)聽 bus 事件總線
// 觸發(fā) bus.$emit 的點(diǎn)擊事件 onDawodi属韧,馬上響應(yīng) wuwuwu 這個(gè)自定義事件
// 接收傳遞過來的data安拟,把data的數(shù)據(jù)賦給當(dāng)前data方法中的對象
// 數(shù)據(jù)傳輸成功
bus.$on('wuwuwu', (data) => {
this.ku = data.kusheng
})
}
}
const app = new Vue({
el: '#app',
components: {
ge,
di
}
})
</script>
4.4 template 標(biāo)簽
? 可以在html
中寫一個(gè)template
標(biāo)簽,并給這個(gè)標(biāo)簽起一個(gè)id宵喂,在創(chuàng)建組件的時(shí)候使用template關(guān)聯(lián)這個(gè)id糠赦;在這個(gè)標(biāo)簽里就放DOM元素。
在DOM元素div
(id = "app")標(biāo)簽中寫入組件標(biāo)簽,在組件的標(biāo)簽中對父組件的數(shù)據(jù)進(jìn)行綁定拙泽。
示例:
<!-- html 'app' 中使用組件 product -->
<div id="app">
<product
:price="price"
:title="title"
:src="src"
></product>
</div>
<!-- 創(chuàng)建組件 product 的template -->
<template id="product">
<div>
<div class="img">
<img :src="src" alt="">
</div>
<p>{{title}}</p>
<p>¥<span>{{price}}</span></p>
</div>
</template>
<script>
// 定義一個(gè)子組件Product
const Product = {
template: '#product',
props: {
src: String,
title: String,
price: Number
}
}
// Vue實(shí)例
const app = new Vue({
el: '#app',
data: {
title: '這是最貴的小姐姐',
price: 99,
src: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2151614847,425289411&fm=111&gp=0.jpg'
},
// 在實(shí)例中使用子組件 Product
components: {
Product
}
})
</script>
4.5 動(dòng)態(tài)組件
動(dòng)態(tài)組件就是在不同組件之間進(jìn)行動(dòng)態(tài)切換淌山,這在實(shí)際項(xiàng)目中是常見的。
實(shí)現(xiàn)方法:
可以通過 Vue 的 <component>
元素加一個(gè)特殊的 is
特性來實(shí)現(xiàn)顾瞻,這個(gè)is
特性可以綁定父組件中data數(shù)據(jù)泼疑,然后通過點(diǎn)擊時(shí)改變這個(gè)數(shù)據(jù)來達(dá)到動(dòng)態(tài)切換。
示例:
<template id="guonei">
<div>華為手機(jī)要升級(jí)了</div>
</template>
<template id="guoji">
<div>apple 倒閉了</div>
</template>
<div id="app">
<div>
<span @click="news = 'guonei'">國內(nèi)新聞</span>
<span @click="news = 'guoji'">國際新聞</span>
</div>
<!-- 這里直接使用component標(biāo)簽和它的is特性 -->
<component :is="news"></component>
</div>
<script>
const guonei= {
template: '#guonei'
}
const guoji= {
template: '#guoji'
}
const app = new Vue({
el: '#app',
data: {
news: 'guoji'
},
components: {
guonei,
guoji
}
})
</script>
4.6 slot 插槽
? slot
(插槽)放在template
標(biāo)簽中占位置荷荤,在使用組件的時(shí)候退渗,去決定是否需要某個(gè)DOM元素,需要的話就寫在組件內(nèi)部(如下圖<hello>標(biāo)簽)蕴纳,在template
標(biāo)簽里面的slot
標(biāo)簽就會(huì)被這個(gè)dom元素自動(dòng)替換会油。
當(dāng)寫多個(gè)slot
時(shí),需要寫上name
屬性袱蚓,使用時(shí)添加屬性 slot="slot標(biāo)簽的name值"就可以對應(yīng)起來了钞啸。
示例:
<template id="hello">
<div>
<slot name="a"></slot>
商品名稱
<slot name="b"></slot>
</div>
</template>
<div id="app">
<hello>
<!-- slot 的值一一對應(yīng) slot標(biāo)簽的name值 -->
<b slot="b">包郵</b>
<b slot="a">打九折</b>
</hello>
</div>
<script>
const Hello = {
template: '#hello'
}
const app = new Vue({
el: '#app',
components: {
Hello
}
})
</script>
4.7 過渡 & 動(dòng)畫
transtion
4.7.1 概述
Vue 在插入、更新或者移除 DOM 時(shí)喇潘,提供多種不同方式的應(yīng)用過渡效果体斩。
包括以下工具:
- 在 CSS 過渡和動(dòng)畫中自動(dòng)應(yīng)用 class
- 可以配合使用第三方 CSS 動(dòng)畫庫,如 Animate.css
- 在過渡鉤子函數(shù)中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 動(dòng)畫庫颖低,如 Velocity.js
4.7.2 方法
4.7.2.3 animate.css 動(dòng)畫庫
參考網(wǎng)站:https://daneden.github.io/animate.css/?
這個(gè)是常用的外部工具絮吵,里面有很多動(dòng)畫效果,簡單易用忱屑。使用時(shí)只需將文件引入蹬敲,然后結(jié)合自定義過渡類名將屬性名改為此工具中對應(yīng)的屬性名,就可以達(dá)到相應(yīng)的動(dòng)畫效果了莺戒。
4.7.2.4 過渡模式
當(dāng)同時(shí)生效的進(jìn)入和離開的過渡不能滿足所有要求伴嗡,這時(shí) Vue 提供了 過渡模式。
-
in-out
:新元素先進(jìn)行過渡从铲,完成之后當(dāng)前元素過渡離開瘪校。 -
out-in
:當(dāng)前元素先進(jìn)行過渡,完成之后新元素過渡進(jìn)入名段。
4.7.2.5 列表過渡
transition
過渡只能作用于一個(gè)元素阱扬;多個(gè)元素需要過渡時(shí)(列表過渡),需要使用 transition-group
組件伸辟,其他的和一般過渡一致麻惶。
4.8 Vue 生命周期(lifecycle )
? 所有的生命周期鉤子自動(dòng)綁定 this
上下文到實(shí)例中,因此可以直接訪問數(shù)據(jù)信夫,對屬性和方法進(jìn)行運(yùn)算窃蹋。
? 注意:不能使用箭頭函數(shù)來定義一個(gè)生命周期方法 (例如 created: () => this.fetchTodos()
)卡啰。
圖示:[圖片上傳失敗...(image-ebc822-1566829451674)]
生命周期總體來說有四段:
-
create創(chuàng)建vue實(shí)例
? beforecreate:創(chuàng)建之前
? created:創(chuàng)建之后
-
mount 將掛載
mount 解析實(shí)例中的數(shù)據(jù),通過插值表達(dá)式把數(shù)據(jù)渲染到DOM元素上(掛載到DOM元素上)脐彩。
? beforemount:掛載之前
? mounted:掛載之后
-
update更新
在updated處碎乃,根據(jù)虛擬DOM更新真實(shí)DOM(做數(shù)據(jù)更新)
? beforeupdate:創(chuàng)建之前
? updated:創(chuàng)建之后
-
destroy銷毀
? beforedestroy:創(chuàng)建之前
? destroyed:創(chuàng)建之后
注意:ajax
數(shù)據(jù)請求一般在 created
或者 beforemount
去發(fā)送。
4.9 虛擬DOM
? 基于真實(shí)dom
惠奸,構(gòu)建的一個(gè)虛擬的dom
梅誓,數(shù)據(jù)操作時(shí)是對虛擬dom
進(jìn)行操作。它有一個(gè)臟檢查佛南,用來檢查舊的數(shù)據(jù)和新的數(shù)據(jù)有什么區(qū)別梗掰,然后對舊的數(shù)據(jù)進(jìn)行更新。
原理:
根據(jù)真實(shí)DOM構(gòu)建一個(gè)虛擬DOM(js對象)嗅回。
當(dāng)真實(shí)DOM要修改的時(shí)候及穗;會(huì)先修改虛擬DOM;然后用修改之后的虛擬DOM跟真實(shí)的DOM進(jìn)行臟檢查(比對)绵载。
-
把修改過后的那一部分重新渲染到真實(shí)DOM上埂陆。
注意:臟檢查運(yùn)用的算法 — diff算法
好處:虛擬DOM可以避免多次的DOM操作,提高性能娃豹。(頻繁請求DOM影響性能)
查詢 super() 用法
5. router 路由
網(wǎng)址 :https://router.vuejs.org/zh/installation.html
5.1 使用router的步驟
? 1. 寫一個(gè) router.js 文件 引入需要配置的組件焚虱,再使用router ;
? 得到一個(gè)router的實(shí)例懂版,并導(dǎo)出 鹃栽;通過routers字段配置路由;
? 跳轉(zhuǎn)的路由路徑躯畴,給組件起個(gè)名字民鼓,對應(yīng)的組件
// 定義路由,導(dǎo)出路由
// 1. 引入核心模塊(包)
import Vue from 'vue'
import Router from 'vue-router'
// 2. 引入需要配置的組件
import Home from './views/Home.vue'
import About from './views/about.vue'
// 3. 使用 router (類似于中間件)
Vue.use(Router)
// 4. new 一個(gè)router實(shí)例蓬抄,并導(dǎo)出
export default new Router({
// 5. 通過routes字段配置路由
routes: [
{
path: '/', // 跳轉(zhuǎn)的路由路徑
name: 'home', // 給組件取個(gè)名字
component: Home // 這個(gè)路由對應(yīng)的組件
},
{
path: '/about',
name: 'about',
component: About
}
]
})
? 2. main.js 引入router.js
? 實(shí)例化vue的時(shí)候把router配置進(jìn)來丰嘉,我們#app這個(gè)實(shí)例中就可以使用配置好的router了。
import Vue from 'vue'
import App from './App.vue'
// 引入了 router.js
import router from './router'
Vue.config.productionTip = false
new Vue({
// 實(shí)例化Vue 的時(shí)候吧router配置進(jìn)來嚷缭,我們#app這個(gè)實(shí)例里就能使用配置好的 router了
router,
render: h => h(App)
}).$mount('#app')
? 3. App.vue
? <router-link to="組件名"/>會(huì)渲染成a標(biāo)簽供嚎,to就相當(dāng)于href,就是要跳轉(zhuǎn)的那個(gè)組件的path
? <router-view/>必須的峭状,組件跳轉(zhuǎn)的顯示位置,即點(diǎn)擊home這兒就顯示home組件
<template>
<div id="app">
<div id="nav">
<!-- router-link默認(rèn)會(huì)渲染成 a標(biāo)簽逼争,to 相當(dāng)于 href,就是要跳轉(zhuǎn)的那個(gè)組件的path -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<!-- router-view 必須寫的优床!組件跳轉(zhuǎn)的顯示位置 作用:顯示跳轉(zhuǎn)組件的位置-->
<!-- 點(diǎn)擊home這兒就顯示home組件。即點(diǎn)擊誰就顯示相對應(yīng)的組件 -->
<router-view/>
</div>
</template>
? 嵌套路由:
? 在router.vue文件中配置路由時(shí)誓焦,當(dāng)一個(gè)組件中還有其他組件視圖胆敞,就需要進(jìn)行路由嵌套着帽。在當(dāng)前配置路由的地方加上children屬性,在其中配置子路由移层。
5.2 router 組件跳轉(zhuǎn)
一級(jí)路由
組件之間需要跳轉(zhuǎn)時(shí)仍翰,就要用到路由來進(jìn)行解決(利用路由進(jìn)行跳轉(zhuǎn))。
二級(jí)路由
=> 動(dòng)態(tài)路由 + 傳參 观话,實(shí)現(xiàn)子組件跳轉(zhuǎn)
路由嵌套予借,
傳參方式: 傳參方式: 1. to="/list/man" 這是通過path進(jìn)行路由傳參。只能傳一個(gè)參數(shù)
? 傳參方式: 2. :to="{ name: 'category', params: {cateName: 'woman'}}" 這是通過綁定 to 后频蛔,給這個(gè)對象傳組件名稱灵迫,通過組件名來跳轉(zhuǎn),params 也是個(gè)對象晦溪,可以實(shí)現(xiàn)傳多個(gè)參數(shù)瀑粥。start這個(gè)參數(shù)未在路由內(nèi)配置,但是能夠被接收三圆,這個(gè)叫做隱式傳參狞换。
? 3. :to="{ name: 'Category', params: {cateName: 'kid', start: 0}, query: { end: 200 }} query傳參,通過 舟肉? 連接參數(shù)修噪,顯示在url上。
跳轉(zhuǎn)方式: router-link + to 度气,聲明式
? router.push({ path: '/' } }) 在js中編寫割按, 編程式 (如:返回首頁)
router-view 命名視圖
?
重定向
點(diǎn)擊該路由,跳轉(zhuǎn)到其他頁面(非該路由對應(yīng)頁)去磷籍。
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
重定向也可以是一個(gè)命名路由
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
也可以是一個(gè)方法适荣,動(dòng)態(tài)返回重定向目標(biāo)
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目標(biāo)路由 作為參數(shù)
// return 重定向的 字符串路徑/路徑對象
}}
]
})
5.3 導(dǎo)航守衛(wèi)
5.3.1 全局配置導(dǎo)航守衛(wèi)
? 在每一次導(dǎo)航發(fā)生改變(路由跳轉(zhuǎn))之前,都會(huì)進(jìn)入這個(gè)鉤子函數(shù)院领,在這個(gè)函數(shù)里只有調(diào)用了 next 才會(huì)跳轉(zhuǎn)弛矛。一般用于全局的權(quán)限驗(yàn)證。
// router.beforeEach
// 注冊一個(gè)全局導(dǎo)航守衛(wèi)
const router = new VueRouter({ ... })
router.beforeEach((to, from, next)=> {
在進(jìn)入 to 之前進(jìn)行登錄(權(quán)限)驗(yàn)證
if(to.){
} else {
}
})
// router.afterEach
// 注冊全局后置鉤子比然,然而和守衛(wèi)不同的是丈氓,這些鉤子不會(huì)接受 next 函數(shù)也不會(huì)改變導(dǎo)航本身
router.afterEach(()=> {
if(){
} else {
}
})
()中有三個(gè)參數(shù),分別是:to from next
解釋: from表示當(dāng)前路由路徑
? to表示即將跳轉(zhuǎn)至的路由路勁
? next()需要跳轉(zhuǎn)時(shí)强法,必須調(diào)用
注意:beforeEach
指路由跳轉(zhuǎn)之前万俗,這時(shí)this
指向undifend
? 在每一次導(dǎo)航發(fā)生之前都會(huì)進(jìn)入這個(gè)鉤子函數(shù),在這個(gè)函數(shù)里只有調(diào)用了next才會(huì)跳轉(zhuǎn)饮怯,一般用于全局 的權(quán)限驗(yàn)證(比如登錄)闰歪。判斷當(dāng)前要跳轉(zhuǎn)的那個(gè)組件是否需要權(quán)限;再驗(yàn)證是否已登錄蓖墅,沒有登錄就中斷當(dāng)前導(dǎo)航库倘,進(jìn)入新的導(dǎo)航临扮;不需要權(quán)限驗(yàn)證就直接進(jìn)入當(dāng)前導(dǎo)航。
補(bǔ)充:
to和from是將要進(jìn)入和將要離開的路由對象,路由對象指的是平時(shí)通過this.$route獲取到的路由對象教翩。
next:Function 這個(gè)參數(shù)是個(gè)函數(shù)杆勇,且必須調(diào)用,否則不能進(jìn)入路由(頁面空白)饱亿。
next() 進(jìn)入該路由蚜退。
next(false): 取消進(jìn)入路由,url地址重置為from路由地址(也就是將要離開的路由地址)路捧。
-
next 跳轉(zhuǎn)新路由关霸,當(dāng)前的導(dǎo)航被中斷,重新開始一個(gè)新的導(dǎo)航杰扫。
我們可以這樣跳轉(zhuǎn):next('path地址')或者next({path:''})或者next({name:''})
且允許設(shè)置諸如 replace: true队寇、name: 'home' 之類的選項(xiàng)
以及你用在router-link或router.push的對象選項(xiàng)。
5.3.2 路由獨(dú)享導(dǎo)航守衛(wèi)
beforeEnter()
參數(shù):to from next (同上)
// 路由配置上直接定義 beforeEnter 守衛(wèi)
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
5.3.3 組件內(nèi)的守衛(wèi)
? 路由組件內(nèi)直接定義以下路由導(dǎo)航守衛(wèi):
beforeRouteEnter
-
beforeRouteUpdate
(2.2 新增) beforeRouteLeave
beforeRouteEnter
守衛(wèi) 不能 訪問 this
章姓,因?yàn)槭匦l(wèi)在導(dǎo)航確認(rèn)前被調(diào)用,因此即將登場的新組件還沒被創(chuàng)建佳遣。
在下列組件外層套一個(gè)組件。因?yàn)檫@個(gè)是組件內(nèi)的守衛(wèi)凡伊。
<!-- 進(jìn)入之前 -->
<!-- 第一次進(jìn)入使用 beforeRouteEnter 只是在進(jìn)入時(shí)調(diào)用一次 -->
beforeRouteEnter (to, from, next){
// 在渲染該組件的對應(yīng)路由被 confirm 前調(diào)用
// 不能獲取組件實(shí)例 this
// 因?yàn)槭匦l(wèi)執(zhí)行前零渐,組件實(shí)例還沒有被創(chuàng)建
// 在next 里可以傳遞一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)的第一個(gè)形參就是this系忙,即VM = this
next(vm => {
})
}
<!-- 修改更新 之后每次修改更新都用 beforeRouteUpdate -->
beforeRouteUpdate (to, from, next){
// 在當(dāng)前路由改變诵盼,但是該組件被復(fù)用時(shí)調(diào)用
// 舉例來說,對于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id银还,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候风宁,
// 由于會(huì)渲染同樣的 Foo 組件,因此組件實(shí)例會(huì)被復(fù)用蛹疯。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用戒财。
// 可以訪問組件實(shí)例 `this`
}
beforeRouteLeave (to, from, next) {
// 導(dǎo)航離開該組件的對應(yīng)路由時(shí)調(diào)用
// 可以訪問組件實(shí)例 `this`
}
}
5.4 路由懶加載
? 路由懶加載 => 能把不同路由對應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問的時(shí)候才加載對應(yīng)組件捺弦,更加高效饮寞。
問題:當(dāng)打包構(gòu)建應(yīng)用時(shí),JavaScript 包會(huì)變得非常大列吼,影響頁面加載幽崩。
解決方法:
? 結(jié)合 Vue 的異步組件和 Webpack 的代碼分割功能,輕松實(shí)現(xiàn)路由組件的懶加載寞钥。
1.通過注釋語法歉铝,可以把添加相同注釋語法的組件打包到一個(gè)js 文件里。
7. Vuex
網(wǎng)址:https://vuex.vuejs.org/zh/
? Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的凑耻。Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式太示。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)。全局狀態(tài)管理Vuex.Store是一個(gè)單例
狀態(tài)自管理應(yīng)用包含以下幾個(gè)部分:
- state香浩,驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源类缤;
- view,以聲明方式將 state 映射到視圖邻吭;
- actions餐弱,響應(yīng)在 view 上的用戶輸入導(dǎo)致的狀態(tài)變化。
“單向數(shù)據(jù)流”理念的簡單示意:
多個(gè)組件共享狀態(tài)時(shí)囱晴,單向數(shù)據(jù)流的簡潔性很容易被破壞:
- 多個(gè)視圖依賴于同一狀態(tài)膏蚓。
- 來自不同視圖的行為需要變更同一狀態(tài)。
7.1 vuex使用
7.1.1 安裝
npm install vuex --save
// 引入
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
7.1.2 創(chuàng)建 store
安裝 Vuex 之后畸写,讓我們來創(chuàng)建一個(gè) store驮瞧。創(chuàng)建過程直截了當(dāng)——僅需要提供一個(gè)初始 state 對象和一些 mutation
// 模塊化環(huán)境中
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
新建一個(gè)store目錄---創(chuàng)建index.js---編寫內(nèi)容state、getters酣栈、actions蹲嚣、mutations汁雷、modules
提交一個(gè)mutation,這個(gè)mutation在store的實(shí)例中定義的 state只能在mutation中mutate
只能傳一個(gè)參數(shù)狂魔,可以傳對象或數(shù)組。
通過 store.state
來獲取狀態(tài)對象淫痰,以及通過 store.commit
方法觸發(fā)狀態(tài)變更:
store.commit('increment')
7.2 核心概念
state 數(shù)據(jù)源
mutation 修改數(shù)據(jù)最楷,提交mutation修改
getter state 中派生出一些狀態(tài),相當(dāng)于 store 的計(jì)算屬性,根據(jù)state計(jì)算
-
action 類似mutation待错,mutation中只能寫同步籽孙;action可以包含任意異步操作,action提交的是mutation朗鸠,而不是直接變更狀態(tài)
參數(shù):context蚯撩,可以理解為store,通過commit提交mutation context.commit('方法')
如果需要通過異步去修稿state烛占,那么就需要在action中寫異步代碼胎挎,異步返回的時(shí)候再提交mutation,進(jìn)行數(shù)據(jù)處理 忆家。
mapState 返回一個(gè)對象犹菇,可以將其映射到computed中
...mapState([‘count’])
...mapMutations(['count'])
7.3 規(guī)則
Vuex 并不限制你的代碼結(jié)構(gòu)。但是芽卿,它規(guī)定了一些需要遵守的規(guī)則:
- 應(yīng)用層級(jí)的狀態(tài)應(yīng)該集中到單個(gè) store 對象中揭芍。
- 提交 mutation 是更改狀態(tài)的唯一方法,并且這個(gè)過程是同步的卸例。
- 異步邏輯都應(yīng)該封裝到 action 里面称杨。
8. 生命周期 <∫恪!姑原!
8.1 Vue的生命周期
create 創(chuàng)建
mount 掛載
update 更新
-
destroy 銷毀
在前面加上 before 悬而,表示在 * *之前; 過去時(shí)態(tài)锭汛,表示在 * * 之后
8.2 導(dǎo)航守衛(wèi)的生命周期
全局守衛(wèi):
- router.beforeEach 全局前置守衛(wèi) 進(jìn)入路由之前
- router.beforeResolve 全局解析守衛(wèi)(2.5.0+) 在beforeRouteEnter調(diào)用之后調(diào)用
- router.afterEach 全局后置鉤子 進(jìn)入路由之后
路由組件內(nèi)的守衛(wèi):
- beforeRouteEnter 進(jìn)入路由前
- beforeRouteUpdate (2.2) 路由復(fù)用同一個(gè)組件時(shí)
- beforeRouteLeave 離開當(dāng)前路由時(shí)
8.3 keep-alive 生命周期
Vue提供了一個(gè)內(nèi)置組件keep-alive
來緩存組件內(nèi)部狀態(tài)笨奠,避免重新渲染,文檔網(wǎng)址
<keep-alive>
是一個(gè)抽象組件:它自身不會(huì)渲染一個(gè) DOM 元素唤殴,也不會(huì)出現(xiàn)在父組件鏈中般婆。
keep-alive
大多數(shù)使用場景就是這種。
<keep-alive>
<component :is="view"></component>
</keep-alive>
// 或者
<keep-alive>
<router-view></router-view>
</keeo-alive>
生命周期:
在被keep-alive
包含的組件/路由中朵逝,會(huì)在原有的Vue生命周期前提下蔚袍,多出兩個(gè)生命周期的鉤子:activated
與 deactivated
。
- activated在組件第一次渲染時(shí)會(huì)被調(diào)用廉侧,之后在每次緩存組件被激活時(shí)調(diào)用页响。
- deactivated:組件被停用(離開路由)時(shí)調(diào)用
使用了keep-alive就不會(huì)調(diào)用 beforeDestroy (組件銷毀前鉤子)和destroyed(組件銷毀),因?yàn)榻M件沒被銷毀段誊,被緩存起來了闰蚕。
這個(gè)鉤子可以看作
beforeDestroy
的替代。
MVVM
1 mvvm模式
? MVVM是Model-View-ViewModel的簡寫连舍,即模型-視圖-視圖模型没陡。它本質(zhì)上就是MVC 的改進(jìn)版。MVVM 就是將其中的View 的狀態(tài)和行為抽象化索赏,讓我們將視圖 UI 和業(yè)務(wù)邏輯分開盼玄。這些事是 ViewModel
自動(dòng)處理的,viewmodel 可以在取出 Model 的數(shù)據(jù)同時(shí)幫忙處理 View 中需要涉及的業(yè)務(wù)邏輯潜腻。
? 它有兩個(gè)方向:一是將【模型】轉(zhuǎn)化成【視圖】埃儿,即將后端傳遞的數(shù)據(jù)轉(zhuǎn)化成所看到的頁面。實(shí)現(xiàn)的方式是:數(shù)據(jù)綁定融涣。
? 二是將【視圖】轉(zhuǎn)化成【模型】童番,即將所看到的頁面轉(zhuǎn)化成后端的數(shù)據(jù)。實(shí)現(xiàn)的方式是:DOM 事件監(jiān)聽威鹿。這兩個(gè)方向都實(shí)現(xiàn)的剃斧,我們稱之為數(shù)據(jù)的雙向綁定。
2 MVVM模式的組成部分
-
模型 (model)
【模型】指的是后端傳遞的數(shù)據(jù)忽你。模型 是指代表真實(shí)狀態(tài)內(nèi)容的領(lǐng)域模型(面向?qū)ο螅┯锥蛑复韮?nèi)容的數(shù)據(jù)訪問層(以數(shù)據(jù)為中心)。
-
視圖 (view)
【視圖】指的是所看到的頁面。就像在MVC和MVP模式中一樣根蟹,視圖是用戶在屏幕上看到的結(jié)構(gòu)脓杉、布局和外觀(UI)。
-
視圖模型 (viewModel)
【視圖模型】mvvm模式的核心简逮,主要處理業(yè)務(wù)邏輯和獲取數(shù)據(jù)丽已,它是連接view和model的橋梁。視圖模型 是暴露公共屬性和命令的視圖的抽象买决。
MVVM
沒有MVC模式的控制器,也沒有MVP模式的presenter
吼畏,有的是一個(gè)綁定器督赤。在視圖模型中,綁定器在視圖和數(shù)據(jù)綁定器之間進(jìn)行通信泻蚊。 -
綁定器
聲明性數(shù)據(jù)和命令綁定隱含在MVVM模式中躲舌。在Microsoft解決方案堆中,綁定器是一種名為XAML的標(biāo)記語言性雄。綁定器使開發(fā)人員免于被迫編寫樣板式邏輯來同步視圖模型和視圖没卸。在微軟的堆之外實(shí)現(xiàn)時(shí),聲明性數(shù)據(jù)綁定技術(shù)的出現(xiàn)是實(shí)現(xiàn)該模式的一個(gè)關(guān)鍵因素秒旋。
ViewModel是Vue.js的核心约计,它是一個(gè)Vue實(shí)例。Vue和React都是MVVM模式的框架迁筛。
3 MVVM優(yōu)點(diǎn)
MVVM模式和MVC模式一樣煤蚌,主要目的是分離視圖(View)和模型(Model),有幾大優(yōu)點(diǎn):
1. 低耦合细卧。視圖(View)可以獨(dú)立于Model變化和修改尉桩,一個(gè)ViewModel可以綁定到不同的"View"上,當(dāng)View變化的時(shí)候Model可以不變贪庙,當(dāng)Model變化的時(shí)候View也可以不變蜘犁。
2. 可重用性。你可以把一些視圖邏輯放在一個(gè)ViewModel里面止邮,讓很多view重用這段視圖邏輯这橙。
3. 獨(dú)立開發(fā)。開發(fā)人員可以專注于業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel)农尖,設(shè)計(jì)人員可以專注于頁面設(shè)計(jì)析恋,使用Expression Blend可以很容易設(shè)計(jì)界面并生成xaml代碼。
4. 可測試盛卡。界面素來是比較難于測試的助隧,而現(xiàn)在測試可以針對ViewModel來寫。
4 MVVM模式的框架
- Vue
- React
5 MVC與MVVM區(qū)別
- MVVM是MVC是改進(jìn)版,MVVM中ViewModel存在目的在于抽離Controller中展示的業(yè)務(wù)邏輯并村,而不是替代Controller巍实。MVVM實(shí)現(xiàn)的是業(yè)務(wù)邏輯組件的重用。
- 使用MVC的目的就是將M和V的代碼分離哩牍∨锪剩‘MVC是單向通信。也就是View跟Model膝昆,必須通過Controller來承上啟下丸边。