大家好,我是前端嵐楓移必,一枚二線城市的程序媛,下半年對于我們來說是比較特殊的幾個月遭殉,7月底石挂,鄭州出現(xiàn)好多年不遇的水災(zāi),沒法出行险污,在家休息誊稚,8月出現(xiàn)了疫情,在家辦公一個月罗心,9月疫情過去里伯,終于能來公司上班了。博客也荒廢了一段時間渤闷,接下來疾瓮,我會陸續(xù)更新一些vue相關(guān)的文章,跟一家一起努力進步
Vue (讀音 /vju?/飒箭,類似于 view) 是一套用于構(gòu)建用戶界面的漸進式框架狼电。
特點: 易用,靈活弦蹂,高效 漸進式框架
可以隨意組合需要用到的模塊 vue + components + vue-router + vuex + vue-cli
一.Vue的概念和特性
1.什么是庫肩碟,什么是框架?
- 庫是將代碼集合成一個產(chǎn)品,庫是我們調(diào)用庫中的方法實現(xiàn)自己的功能。
- 框架則是為解決一類問題而開發(fā)的產(chǎn)品,框架是我們在指定的位置編寫好代碼凸椿,框架幫我們調(diào)用削祈。
框架與庫之間最本質(zhì)區(qū)別在于控制權(quán):you call libs, frameworks call you
Vue屬于框架
2.MVC模型 && MVVM模型
- M:模型(Model) :對應(yīng) data 中的數(shù)據(jù)
- V:視圖(View) :模板
- VM:視圖模型(ViewModel) : Vue 實例對象
在傳統(tǒng)的mvc中除了model和view以外的邏輯都放在了controller中,導(dǎo)致controller邏輯復(fù)雜難以維護,在mvvm中view和model沒有直接的關(guān)系脑漫,全部通過viewModel進行交互
Vue是MVVM模式
3.聲明式和命令式
- 自己寫for循環(huán)就是命令式 (命令其按照自己的方式得到結(jié)果)
- 聲明式就是利用數(shù)組的方法forEach (我們想要的是循環(huán)髓抑,內(nèi)部幫我們?nèi)プ?
二.Vue的基本使用
1.mustache語法
允許開發(fā)者聲明式地將 DOM 綁定至底層 Vue 實例的數(shù)據(jù)。在使用數(shù)據(jù)前需要先聲明
- 編寫三元表達式
- 獲取返回值
- JavaScript 表達式
<div id="app">
{{ 1+1 }}
{{ msg == 'hello'?'yes':'no' }}
{{ {name:1} }}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'hello'
}
})
</script>
2.響應(yīng)式數(shù)據(jù)變化
Vue中使用Object.defineProperty
重新將對象中的屬性定義优幸,如果是數(shù)組的話需要重寫數(shù)組原型上的方法
function notify() {
console.log('視圖更新')
}
let data = {
name: 'jw',
age: 18,
arr: [1,2,3]
}
// 重寫數(shù)組的方法
let oldProtoMehtods = Array.prototype;
let proto = Object.create(oldProtoMehtods);
['push', 'pop', 'shift', 'unshift'].forEach(method => {
proto[method] = function (...args) {
let inserted;
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break;
}
observerArray(inserted)
notify();
oldProtoMehtods[method].call(this, ...args)
}
})
function observerArray(obj) { // 觀察數(shù)組中的每一項
for (let i = 0; i < obj.length; i++) {
observer(obj[i]);
}
}
function observer(obj) {
if(typeof obj !== 'object'){
return obj
}
if (Array.isArray(obj)) {
obj.__proto__ = proto
observerArray(obj);
}else{
for (let key in obj) {
defineReactive(obj, key, obj[key]);
}
}
}
function defineReactive(obj, key, value) {
observer(value); // 再一次循環(huán)value
Object.defineProperty(obj, key, { // 不支持數(shù)組
get() {
return value;
},
set(val) {
notify();
observer(val);
value = val;
}
});
}
observer(data);
data.arr.push({name:'jw'})
console.log(data.arr);
缺陷
- 不能通過通過長度吨拍,索引改變數(shù)組
- 不能給對象新增屬性
- 需要通過
vm.$set
和vm.$delete
方法強制添加/刪除響應(yīng)式數(shù)據(jù)
特點: 使用對象的時候 必須先聲明屬性 ,這個屬性才是響應(yīng)式的
- 增加不存在的屬性 不能更新視圖 (vm.$set)
- 默認會遞歸增加 getter和setter
- 數(shù)組里套對象 對象是支持響應(yīng)式變化的网杆,如果是常量則沒有效果
- 修改數(shù)組索引和長度 是不會導(dǎo)致視圖更新的
- 如果新增的數(shù)據(jù) vue中也會幫你監(jiān)控(對象類型)
3.Vue實例上的方法
- vm.$el;
- vm.$data;
- vm.$options;
- vm.$nextTick();
- vm.$mount();
- vm.$watch();
- vm.$set();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">{{name}} {{age.age}}</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {name:'zf',age:{}}
}
});
// 1) vue有個特點 不會在本輪代碼執(zhí)行的時候 去重新渲染dom
// 2) 下一個事件環(huán)中執(zhí)行 (promie.then mutationobserver setimmediate settimeout)
// 這里會等待數(shù)據(jù)更新后重新調(diào)用回調(diào)函數(shù)
// 視圖是異步更新的
vm.$watch("name",function (newValue,oldValue) {
console.log(newValue,'后');
});
// vm.name = 'jw';
// vm.name = 'zf1';
// 數(shù)據(jù)更新后會有一個隊列 將watch的callback放到隊列中,會將nextTick往后疊加
vm.$nextTick(()=>{
console.log(vm.$el.innerHTML); // 渲染后的真實dom
});
console.log('vm的數(shù)據(jù)',vm.$data); // 代表 當(dāng)前實例的數(shù)據(jù)
console.log('vm中的options',vm.$options);
// vm.$set vm.$delete 幫我更新屬性的
// 新增的屬性不會導(dǎo)致視圖更新 羹饰,更改數(shù)組索引也不會更新
// vm.age.age = 100;
vm.$set(vm.age,'age',100); // Object.defineProperty
// vm.$set([1,2,3],'0',100);
// vm.$el
// vm.$options
// vm.$watch
// vm.$nextTick
// vm.$set
</script>
</body>
</html>
三.Vue中的指令
在vue中 指令 (Directives) 是帶有 v- 前綴的特殊特性,主要的功能就是操作DOM
1.v-once
<div v-once>{{state.count}} </div>
2.v-html
永遠不要對用戶輸入使用v-html,可能會導(dǎo)致xss攻擊
<div v-html="text"></div>
3.v-bind
動態(tài)綁定屬性需要使用v-bind
進行綁定
<img v-bind:src="src">
可以使用:來簡寫
v-bind
4.v-for
<template v-for="(fruit,index) in fruits" >
<li :key="`item_${index}`">{{fruit}}</li>
<li :key="`fruit_${index}`">{{fruit}}</li>
</template>
多個元素循環(huán)時外層需要增加
template
標簽,需要給真實元素增加key
,而且key
不能重復(fù),盡量不要采用索引作為key
的值
舉個key
值的例子:
5.v-if/v-else/v-show
v-if
可以切換DOM
元素是否存在,并且v-if
為false
時內(nèi)部指令不會被執(zhí)行
v-show
可以控制元素的顯示及隱藏碳却,主要控制的是元素樣式
6.v-on
- 事件的綁定 v-on綁定事件
- 事件修飾符 (.stop .prevent) .capture .self .once .passive
7.v-model
雙向數(shù)據(jù)綁定
<input type="text" :value="value" @input="input">
<input type="text" v-model="value">
- select
<select v-model="select">
<option
v-for="fruit in fruits"
:value="fruit">
{{fruit}}
</option>
</select>
- radio
<input type="radio" v-model="value" value="男">
<input type="radio" v-model="value" value="女">
- checkbox
<input type="checkbox" v-model="checks" value="游泳" >
<input type="checkbox" v-model="checks" value="健身">
- 修飾符應(yīng)用 .number .lazy .trim
<input type="text" v-model.number="value">
<input type="text" v-model.trim="value">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- {{}} 小胡子語法 取值 能運算(算出來得有返回結(jié)果) 做三元表達式 -->
{{name}}
{{1+1}}
{{[1,2,3]}}
{{true?'是':null}}
<!-- 取對象 必須空格隔開 -->
{{ {name:'123'} }}
<span v-once>一次 {{name}}</span>
<!-- 不要將用戶輸入的內(nèi)容顯示到頁面上 xss攻擊 -->
<!-- 后端返回的數(shù)據(jù) 可以通過v-html來格式化 -->
<span v-html="tmp"></span>
<!-- 動態(tài)綁定 -->
<div v-bind:title="name">你好</div>
<!-- 綁定的是一個變量屬性 -->
<div :title="name">你好</div>
<!-- v-for 循環(huán)數(shù)據(jù) 數(shù)組 對象 數(shù)字 (字符串) -->
<!-- 要循環(huán)誰 就將 v-for 寫到誰的身上 -->
<!-- vue的中的key 有什么作用 區(qū)分元素,如果我有個按鈕做反序 -->
<!-- 只是靜態(tài) 展示可以使用這個索引 使用唯一的key 來區(qū)分元素-->
<!-- 每次循環(huán)時候可以自己拼接一些內(nèi)容保證唯一性 -->
不渲染
<div v-if="false">
<template v-for="(fruit,index) in arr" >
<li :key="`name_${index}`">
{{fruit.name}}
</li>
<li :key="`color_${index}`">
{{fruit.color}}
</li>
</template>
</div>
<!-- v-if (操作dom是否顯示)) v-show(顯示隱藏 style) -->
<!-- 指令的功能是封裝dom 操作的 -->
<!-- v-for 和 v-if 不要一起用 -->
<!-- v-show 不能和template一起用 -->
<!-- vue默認會采用復(fù)用的策略 會復(fù)用代碼 -->
<template v-if="isShow">
<span>你好</span>
<input type="text" key="1">
</template>
<template v-else>
<span>不好</span>
<input type="text" key="2">
</template>
<!-- 雙向綁定 只要能改的 組件也可以雙向綁定 -->
<br>
<!-- 如何綁定方法 v-on是@的全拼-->
<!-- $event指代的是事件源 -->
<input type="text" :value="value" @input="fn($event)">
<!-- 很長 -->
<input type="text" :value="value" @input="e=>value=e.target.value">
<!-- v-model 他就是上面的簡寫 語法糖 -->
<input type="text" v-model="value">
{{value}}
</div>
<!--
v-once
v-html
v-bind
v-for
v-if / else show
v-model 雙向綁定
-->
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
methods:{// 就是把所有的方法的this 都變成vm,bind了 多次bind 不會生效
fn(e){ // this指代的都是window
this.value = e.target.value
}
},
data() {
return {
value:'你好',
isShow:true,
tmp:'<h1>我很帥</h1>',
name: 'zf',
arr:[{name:'橘子',color:'綠色'},{name:'香蕉',color:' 黃色'}]
}
}
});
</script>
</body>
</html>
四.自定義指令
- 全局指令和局部指令
- 編寫一個自定義指令
- 鉤子函數(shù)bind队秩,inserted,update
<input type="text" v-focus.color="'red'">
Vue.directive('focus',{
inserted:(el,bindings)=>{
let color = bindings.modifiers.color;
if(color){
el.style.boxShadow = `1px 1px 2px ${bindings.value}`
}
el.focus();
}
});
- clickoutside指令
<div v-click-outside="change">
<input type="text" @focus="flag=true" >
<div v-show="flag">
contenter
</div>
</div>
<script>
let vm = new Vue({
el:'#app',
data:{
flag:false
},
methods:{
change(){
this.flag = false
}
},
directives:{
'click-outside'(el,bindings,vnode){
document.addEventListener('click',(e)=>{
if(!el.contains(e.target,vnode)){
let eventName = bindings.expression;
vnode.context[eventName]()
}
})
}
}
})
</script>
五.Vue中的生命周期
- beforeCreate 在實例初始化之后追城,數(shù)據(jù)觀測(data observer) 和 event/watcher 事件配置之前被調(diào)用刹碾。
- created 實例已經(jīng)創(chuàng)建完成之后被調(diào)用燥撞。在這一步座柱,實例已完成以下的配置:數(shù)據(jù)觀測(data observer)迷帜,屬性和方法的運算, watch/event 事件回調(diào)色洞。這里沒有$el
- beforeMount 在掛載開始之前被調(diào)用:相關(guān)的 render 函數(shù)首次被調(diào)用戏锹。
- mounted el 被新創(chuàng)建的 vm.$el 替換,并掛載到實例上去之后調(diào)用該鉤子火诸。
- beforeUpdate 數(shù)據(jù)更新時調(diào)用锦针,發(fā)生在虛擬 DOM 重新渲染和打補丁之前。
- updated 由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補丁置蜀,在這之后會調(diào)用該鉤子奈搜。
- beforeDestroy 實例銷毀之前調(diào)用。在這一步盯荤,實例仍然完全可用馋吗。
- destroyed Vue 實例銷毀后調(diào)用。調(diào)用后秋秤,Vue 實例指示的所有東西都會解綁定宏粤,所有的事件監(jiān)聽器會被移除,所有的子實例也會被銷毀灼卢。 該鉤子在服務(wù)器端渲染期間不被調(diào)用绍哎。
鉤子函數(shù)中該做的事情
- created 實例已經(jīng)創(chuàng)建完成,因為它是最早觸發(fā)的原因可以進行一些數(shù)據(jù)鞋真,資源的請求崇堰。
- mounted 實例已經(jīng)掛載完成,可以進行一些DOM操作
- beforeUpdate 可以在這個鉤子中進一步地更改狀態(tài)涩咖,這不會觸發(fā)附加的重渲染過程赶袄。
- updated 可以執(zhí)行依賴于 DOM 的操作。然而在大多數(shù)情況下抠藕,你應(yīng)該避免在此期間更改狀態(tài)饿肺,因為這可能會導(dǎo)致更新無限循環(huán)。 該鉤子在服務(wù)器端渲染期間不被調(diào)用盾似。
- destroyed 可以執(zhí)行一些優(yōu)化操作,清空定時器敬辣,解除綁定事件