一、 Vue核心
1、Vue 簡介
(1)官網
? 英文官網
? 中文官網
(2)介紹與描述
Vue是一套用來動態構建用戶界面的漸進式JavaScript框架- 構建用戶界面:把資料通過某種辦法變成用戶界面
- 漸進式:
Vue可以自底向上逐層的應用,簡單應用只需要一個輕量小巧的核心庫,復雜應用可以引入各式各樣的 Vue 插件 - 作者:尤雨溪

(3)特點
- 采用組件化模式,提高代碼復用率、且讓代碼更好維護

2.宣告式編碼,讓編碼人員無需之間操作DOM,提高開發效率

3.使用虛擬DOM+優秀的Diff演算法,盡量復用DOM節點


(4)與其他 JS 框架的關聯
- 借鑒 angular 的 模板 和 資料系結 技術
- 借鑒 react 的 組件化 和 虛擬DOM 技術
(5) Vue 周邊庫
- vue-cli:vue 腳手架
- vue-resource(axios):ajax 請求
- vue-router:路由
- vuex:狀態管理(它是 vue 的插件但是沒有用 vue-xxx 的命名規則)
- vue-lazyload:圖片懶加載
- vue-scroller:頁面滑動相關
- mint-ui:基于 vue 的 UI 組件庫(移動端)
- element-ui:基于 vue 的 UI 組件庫(PC 端)
2、初識 Vue
(1)前置作業
- 給瀏覽器安裝[Vue Devtools](安裝 — Vue.js (vuejs.org))
- 標簽引入
Vue包 - (可選)阻止 vue 在啟動時生成生產提示
Vue.config.productionTip = false; - favicon 需要將頁簽圖示放在專案根路徑,重新打開就有了(shfit+F5 強制重繪)
(2)初識Vue:
- 想讓 Vue 作業,就必須創建一個 Vue實體 ,且要傳入一個配置物件
- root 容器里的代碼依然符合 html規范 ,只不過混入了一些特殊的 Vue語法
- root 容器里的代碼被稱為 Vue模板
- Vue 實體與容器是一一對應的
- 真實開發中只有一個 Vue實體 ,并且會配合著組件一起使用
- {{xxx}} 中的 xxx 要寫 js 運算式,且 xxx 可以自動讀取到 data 中的所有屬性
? 注意區分:js 運算式 和 js代碼(陳述句)
? a. 運算式:一個運算式會產生一個值,可以放在任何一個需要值的地方
? ①a
? ② a+b
? ③demo(1)
? ④x === y ? 'a' : 'b'
? b. js代碼(陳述句)
? ①if(){}
? ② for(){}
? 7.. 一旦 data 中的資料發生變化,那么模板中用到該資料的地方也會自動更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始Vue</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 初識Vue:
1. 想讓 Vue 作業,就必須創建一個 Vue實體 ,且要傳入一個配置物件
2. root 容器里的代碼依然符合 html規范 ,只不過混入了一些特殊的 Vue語法
3. root 容器里的代碼被稱為 Vue模板 -->
<!-- 準備好一個容器 -->
<div id="root">
<h1>Hello,{{name.toUpperCase()}},{{address}}}</h1>
</div>
<script type="text/javascript">
Vue.config.productionTip = false; // 阻止啟動vue在啟動時生成生產提示
// 創建一個Vue實體
new Vue({
el:'#root' ,//el用于指定當前Vue實體為哪個容器服務,值通常為css選擇器字串
data:{//data用于指儲存資料,資料供el所指定的容器使用,值我們暫時先寫成一個物件
name:'DFshmily',
address:'China'
}
})
</script>
</body>
</html>
3、模板語法
Vue 模板語法包括兩大類
-
插值語法 (雙大括號運算式)
功能:用于決議標簽體內容 寫法: {{xxx}} ,xxx 是 js 運算式,可以直接讀取到 data 中的所有區域
-
指令語法 (以v-開頭)
功能:用于決議標簽(包括:標簽屬性、標簽體內容、系結事件…)
舉例: 或簡寫為 ,xxx 同樣要寫 js 運算式,可以直接讀取到 data 中的所有屬性
備注: Vue 中有很多的指令,且形式都是 v-xxx ,此處只是拿
v-bind舉例<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板語法</title> <!-- 引入Vue.js --> <script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script> </head> <body> <!-- 準備好一個容器 --> <div id="root"> <h1>模板語法</h1> <h3>你好,{{name}}</h3> <hr> <h1>指令語法</h1> <a v-bind:href="https://www.cnblogs.com/DFshmily/archive/2022/10/24/url" x="hello">點我開始學習</a><br> <a :href="https://www.cnblogs.com/DFshmily/archive/2022/10/24/url.toUpperCase()" x="school.hello">點我開始學習</a><br> <a :href="https://www.cnblogs.com/DFshmily/archive/2022/10/24/school.url" x="school.hello">點我開始{{school.name}}學習</a> </div> <script type="text/javascript"> Vue.config.productionTip = false; // 阻止啟動vue在啟動時生成生產提示 new Vue({ el:'#root', data:{ name:'DFshmily', url:'https://www.cnblogs.com/DFshmily', school:{ name:'Vue', url:'https://www.cnblogs.com/DFshmily/p/16799543.html', hello:'你好' } } }) </script> </body> </html>
4、資料系結
Vue 中有2種資料系結的方式
a. 單向系結 v-bind 資料只能從 data 流向頁面
b. 雙向系結 v-model 資料不僅能從 data 流向頁面,還可以從頁面流向 data
備注 :a. 雙向系結一般都應用在表單類元素上,如 <input> <select> <textearea> 等
? b. v-model:value 可以簡寫為 v-model ,因為 v-model 默認收集的就是 value 值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板語法</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 準備好一個容器 -->
<div id="root">
<!-- 普通寫法 -->
單向資料系結:<input type="text" v-bind:value="https://www.cnblogs.com/DFshmily/archive/2022/10/24/name"><br>
雙向資料系結:<input type="text" v-model:value="https://www.cnblogs.com/DFshmily/archive/2022/10/24/name"><br>
<!-- 簡寫 -->
單向資料系結:<input type="text" :value="https://www.cnblogs.com/DFshmily/archive/2022/10/24/name"><br>
雙向資料系結:<input type="text" v-model="name"><br>
<!-- 如下代碼是錯誤的,因為v-model只能應用在表單元素(輸入類元素)上 -->
<h2 v-model:x="name">你好!</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false; // 阻止啟動vue在啟動時生成生產提示
// 創建一個Vue實體
new Vue({
el:'#root' ,
data:{
name:'DFshmily',
}
})
</script>
</body>
</html>

5、el與data的兩種寫法
el 與 data 的兩種寫法:
(1)el 有2種寫法
? a. 創建 Vue 實體物件的時候配置 el 屬性
? b. 先創建 Vue 實體,隨后再通過 vm.$mount('#root') 指定 el 的值
(2)data 有2種寫法 :
? a. 物件式: data: { }
? b. 函式式: data() { return { } }
? 如何選擇:目前哪種寫法都可以,以后到組件時, data 必須使用函式,否則會報錯 一個重要的原則
由 Vue 管理的函式,一定不要寫箭頭函式,否則 this 就不再是 Vue實體 了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板語法</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 準備好一個容器 -->
<div id="root">
<h1>你好,{{name}}</h1>
</div>
<script type="text/javascript">
Vue.config.productionTip = false; // 阻止啟動vue在啟動時生成生產提示
// el的兩種寫法
new Vue({
//el:'#root' , //第一種寫法
data:{
name:'DFshmily',
}
})
console.log(v)
v.$mount('#root') //第二種寫法
//設定時間的例子
setTimeout(()=>{
v.$mount('#root')
},1000)
//data的兩種寫法
new Vue({
el:'#root',
//data的第一種寫法:物件式
// data:{
// name:'DFshmily',
// }
//data的第二種寫法:函式式
data(){//等同于data:function(){}
console.log('@@@',this) //此處的this是Vue實體物件
return{
name:'DFshmily',
}
}
})
</script>
</body>
6、MVVM模型
- M:模型(Model):對應data中的資料
- V:視圖(View):模板代碼
- VM:試圖模板(ViewModel):Vue實體物件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>理解MVVM</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 準備好一個容器 -->
<div id="root">
<h1>學校名稱:{{name}}</h1>
<h1>學校地址:{{address}}</h1>
<h1>測驗一下1:{{1+1}}</h1>
<h1>測驗一下2:{{$options}}</h1>
<h1>測驗一下3:{{$emit}}</h1>
<h1>測驗一下4:{{_c}}</h1>
</div>
</body>
<!--
MVM模型:
1. M:Model,模型,資料
2. V:視圖(View):模板代碼
3. VM:ViewModel,視圖模型,Vue實體
觀察發現:
1.data中所有的屬性,最后都出現在了vm身上
2.vm身上所有的屬性及Vue原型上所有屬性,在Vue模板中都可以直接使用
-->
<script type="text/javascript">
Vue.config.productionTip = false; // 阻止啟動vue在啟動時生成生產提示
// 創建一個Vue實體
const vm = new Vue({
el:'#root' ,
data:{
name:'DFshmily',
address:'China'
}
})
console.log(vm);
</script>
</html>
效果:

7、資料代理
Object.defineProperty方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.回顧Object.defineProperty方法</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<script type="text/javascript">
let number = 18
let person = {
name:'DFshmily',
sex:'男',
//age:18
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制屬性是否可以列舉,默認值是false
// writable:true, //控制屬性是否可以修改,默認值是false
// configurable:true //控制屬性是否可以洗掉,默認值是false
//當有人讀取person的age屬性時,get函式就會被呼叫,且回傳值就是age的值
get(){
console.log('get函式被呼叫了')
return number
},
//當有人修改person的age屬性時,set函式就會被呼叫,且傳入的引數就是修改后的值
set(newValue){
console.log('有人修改了age屬性,且修改后的值是'+newValue)
number = newValue
}
})
//console.log(Object.keys(person))
console.log(person)
</script>
</body>
</html>
資料代理:通過一個物件代理對另一個物件中屬性的操作(讀/寫)
<!-- 資料代理:通過一個物件代理對另一個物件中屬性的操作(讀/寫) -->
<script type="text/javascript">
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(newValue){
obj.x = newValue
}
})
</script>
1.Vue 中的資料代理通過 vm 物件來代理 data 物件中屬性的操作(讀/寫)
-
Vue 中資料代理的好處:更加方便的操作 data 中的資料
-
基本原理
? a. 通過 object.defineProperty() 把 data 物件中所有屬性添加到 vm 上
b. 為每一個添加到 vm 上的屬性,都指定一個 getter setter
c. 在 getter setter 內部去操作(讀/寫) data 中對應的屬

Vue 將 data 中的資料拷貝了一份到 _data 屬性中,又將 _data 里面的屬性提到 Vue實體 中(如name),通過 defineProperty 實作資料代理, 這樣通過 geter/setter 操作 name,進而操作 _data 中的 name,而 _data 又對 data 進行資料劫持,實作回應式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.回顧Object.defineProperty方法</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 1.Vue 中的資料代理通過 vm 物件來代理 data 物件中屬性的操作(讀/寫)
2. Vue 中資料代理的好處:更加方便的操作 data 中的資料
3. 基本原理
a. 通過 object.defineProperty() 把 data 物件中所有屬性添加到 vm 上
b. 為每一個添加到 vm 上的屬性,都指定一個 getter setter
c. 在 getter setter 內部去操作(讀/寫) data 中對應的屬 -->
<div id="root">
<h2>學校名稱:{{name}}</h2>
<h2>學校地址:{{address}}</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
let data=https://www.cnblogs.com/DFshmily/archive/2022/10/24/{
name:'DFshmily',
address:'China'
}
const vm = new Vue({
el:'#root',
data
})
</script>
</body>
</html>
8、事件處理
(1)事件的基本使用:
? 1.使用v-on:xxx或@xxx系結事件,其中xxx是事件名
? 2.事件的回呼需要配置在methods中,最侄訓在vm上
? 3.methods中配置的函式,不要用箭頭函式!否則this就不是vm了
? 4.methods中配置的函式,都是被Vue所管理的函式,this的指向是vm或組件實體物件
? 5.@click='Demo'和@click="demo($event)"效果一致,但后者可以傳參
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件的基本使用</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<!-- 事件的基本使用:
1.使用v-on:xxx或@xxx綁定事件,其中xxx是事件名
2.事件的回呼需要配置在methods中,最侄訓在vm上
3.methods中配置的函式,不要用箭頭函式!否則this就不是vm了
4.methods中配置的函式,都是被Vue所管理的函式,this的指向是vm或組件實體物件
5.@click='Demo'和@click="demo($event)"效果一致,但后者可以傳參 -->
<div id="root">
<h2>歡迎來到{{name}}學習</h2>
<!-- <button v-on:click="showInfo">點我提示資訊</button> -->
<button @click="showInfo1">點我提示資訊1(不傳參)</button>
<button @click="showInfo2($event,666)">點我提示資訊2(傳參)</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
const vm = new Vue({
el:'#root',
data:{
name:'DFshmily'
},
methods:{
showInfo1(event){
alert('你好!')
//console.log(event.target.innerText)
// console.log(this)
},
showInfo2(event,number){
console.log(event,number)
alert('你好2!')
}
}
})
</script>
</body>
</html>
(2)事件修飾符
? Vue 中的事件修飾符
prevent阻止默認事件(常用)stop阻止事件冒泡(常用)once事件只觸發一次(常用)capture使用事件的捕獲模式self只有event.target是當前操作的元素時才觸發事件passive事件的默認行為立即執行,無需等待事件回呼執行完畢
修飾符可以連續寫,比如可以這么用: @click.prevent.stop="showInfo"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件修飾符</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
<style>
*{
margin-top:20px;
}
.demo1{
height: 50px;
background-color: pink;
}
.box1{
padding: 5px;
background-color: yellow;
}
.box2{
padding: 5px;
background-color: green;
}
.list{
width: 200px;
height: 200px;
background-color: pink;
overflow: auto;
}
li{
height: 100px;
}
</style>
</head>
<body>
<div id="root">
<h2>歡迎來到{{name}}學習</h2>
<a href="https://www.cnblogs.com/DFshmily/" @click.prevent="showInfo">點我提示資訊</a>
<!-- 阻止事件冒泡(常用) -->
<div @click="showInfo">
<button @click.stop="showInfo">點我提示資訊</button>
</div>
<!-- 事件只觸發一次(常用) -->
<button @click.once="showInfo">點我提示資訊</button>
<!-- 使用事件的捕獲模式 -->
<div @click.capture="showMsg(1)">
div1
<div @click.capture="showMsg(2)">
div2
</div>
</div>
<!-- 只有event.target是當前操作的元素時才觸發事件 -->
<div @click.self="showInfo">
<button @click="showInfo">點我提示資訊</button>
</div>
<!-- 事件的默認行為立即執行,無需等待事件回呼執行完畢 -->
<ul @wheel.passive="demo" >
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
const vm = new Vue({
el:'#root',
data:{
name:'DFshmily'
},
methods:{
showInfo(e){
//alert('你好!')
console.log(e.target)
},
showMsg(msg){
console.log(msg)
},
demo(){
for(let i=0;i<10000;i++){
console.log('#')
}
console.log("滾動事件")
}
}
})
</script>
</body>
</html>
(3)鍵盤事件
鍵盤上的每個按鍵都有自己的名稱和編碼,例如:Enter(13),而 Vue 還對一些常用按鍵起了別名方便使用
- Vue 中常用的按鍵別名
? 回車 enter
? 洗掉 delete(捕獲“洗掉”和“退格”鍵 )
? 退出 esc
? 空格 space
? 換行tab特殊,必須配合keydown去使用
? 上 up
? 下 down
? 左 left
右 `right`
-
. Vue 未提供別名的按鍵,可以使用按鍵原始的 key 值去系結,但注意要轉為 kebab-case (多單詞小寫短橫線寫法)
-
. 系統修飾鍵(用法特殊)
ctrlaltshiftmeta(meta就是win鍵)a.. 配合
keyup使用:按下修飾鍵的同時,再按下其他鍵,隨后釋放其他鍵,事件才被觸發
? 指定ctr+y使用@keyup.ctr.y
? b.. 配合 keydown 使用:正常觸發事件
- 也可以使用
keyCode去指定具體的按鍵(不推薦) Vue.config.keyCodes.自定義鍵名 = 鍵碼,可以去定制按鍵別名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>鍵盤事件</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>歡迎來到{{name}}學習</h2>
<input type="text" placeholder="按下回車提示輸入" @keyup.huiche="showInfo">
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
Vue.config.keyCode.huiche = 13 //定義了一個別名按鍵
const vm = new Vue({
el:'#root',
data:{
name:'DFshmily'
},
methods:{
showInfo(e){
//console.log(e.key,e.KeyCode)
console.log(e.target.value)
}
}
})
</script>
</body>
</html>
9、計算屬性
(1)差值語法實作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2.姓名案例_methods實作</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/>
名:<input type="text" v-model="lastName"> <br/>
全名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span> <!--.slice表示截取前三位 -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
const vm = new Vue({
el:'#root',
data:{
firstName:'DF',
lastName:'shmily'
}
})
</script>
</body>
</html>
(2)method實作
資料發生變化,模板就會被重新決議
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2.姓名案例_methods實作</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/>
名:<input type="text" v-model="lastName"> <br/>
<!-- 全名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span> .slice表示截取前三位 -->
全名:<span>{{fullName()}}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
const vm = new Vue({
el:'#root',
data:{
firstName:'DF',
lastName:'shmily'
},
methods:{
fullName(){
return this.firstName+'-'+this.lastName
}
}
})
</script>
</body>
</html>
(3)computed計算屬性
- 定義:要用的屬性不存在,需要通過已有屬性計算得來
- 原理:底層借助了
Objcet.defineproperty()方法提供的getter和setter get函式什么時候執行?- . 初次讀取時會執行一次
- 當依賴的資料發生改變時會被再次呼叫
- 優勢:與
methods實作相比,內部有快取機制(復用),效率更高,除錯方便 - 備注
- 計算屬性最侄訓出現在
vm上,直接讀取使用即可 - 如果計算屬性要被修改,那必須寫
set函式去回應修改,且set中要引起計算時依賴的資料發生改變 - 如果計算屬性確定不考慮修改,可以使用計算屬性的簡寫形式
- 計算屬性最侄訓出現在
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3.計算屬性</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/>
名:<input type="text" v-model="lastName"> <br/>
測驗:<input type="text" v-model="x"> <br/> <!-- 這里修改 不會調 fullName的get方法 -->
全名:<span>{{fullName}}</span><br/><br/>
<!-- 全名:<span>{{fullName}}</span><br/><br/>
全名:<span>{{fullName}}</span><br/><br/> -->
<script type="text/javascript">
Vue.config.productionTip = false //阻止啟動生產訊息,常用作指令
const vm = new Vue({
el:'#root',
data:{
firstName:'DF',
lastName:'shmily',
x:'你好!'
},
computed: {
//完整寫法
// fullName: {
// get() {
// console.log('get被呼叫了')
// return this.firstName + '-' + this.lastName
// },
// set(value) {
// console.log('set', value)
// const arr = value.split('-')
// this.firstName = arr[0]
// this.lastName = arr[1]
// }
// }
// 簡寫
fullName() {
console.log('get被呼叫了')
return this.firstName + '-' + this.lastName
}
}
})
</script>
</body>
</html>
10、偵聽屬性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.天氣案例</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>今天天氣很{{info}}</h2>
<button @click="changeWeather">切換天氣</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
isHot: true
},
computed:{
info(){
return this.isHot ? '炎熱' : '涼爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
})
</script>
</body>
</html>

(1)偵聽屬性基本用法
watch監視屬性
- 當被監視的屬性變化時,回呼函式自動呼叫,進行相關操作
- 監視的屬性必須存在,才能進行監視,既可以監視 data ,也可以監視計算屬性
- 配置項屬性
immediate:false,改為true,則初始化時呼叫一次handler(newValue,oldValue) - 監視有兩種寫法
- 創建
Vue時傳入watch: {}配置 - 通過
vm.$watch()監視
- 創建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2.天氣案例_監視屬性</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>今天天氣很{{info}}</h2>
<button @click="changeWeather">切換天氣</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
isHot:true
},
computed:{
info(){
return this.isHot ? '炎熱' : '涼爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
// watch:{
// isHot:{
// immediate:true, //初始化時讓handler呼叫一下
// //handler在isHot發生改變時被呼叫
// handler(newValue,oldValue){
// console.log('isHot被修改了',newValue,oldValue)
// }
// }
// }
})
vm.$watch('isHot',{
immediate:true, //初始化時讓handler呼叫一下
//handler在isHot發生改變時被呼叫
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
</script>
</body>
</html>
(2)深度監聽
-
Vue中的watch默認不監測物件內部值的改變(一層) -
在
watch中配置deep:true可以監測物件內部值的改變(多層)
注意
Vue自身可以監測物件內部值的改變,但 Vue 提供的watch默認不可以- 使用
watch時根據監視資料的具體結構,決定是否采用深度監視
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3.天氣案例_深度監聽</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>今天天氣很{{info}}</h2>
<button @click="changeWeather">切換天氣</button>
<hr/>
<h3>a的值是:{{numbers.a}}</h3>
<button @click="numbers.a++">點我a加1</button>
<h3>b的值是:{{numbers.b}}</h3>
<button @click="numbers.b++">點我b加1</button>
<button @click="numbers = {a:666,b:888}">徹底替換掉numbers</button>
<!-- {{numbers.c.d.e}} -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1,
c:{
d:{
e:100
}
}
}
},
computed:{
info(){
return this.isHot ? '炎熱' : '涼爽'
}
},
methods: {
changeWeather(){
this.isHot = !this.isHot
}
},
watch:{
// 'numbers.a':{
// handler(){
// console.log('a被改變了')
// }
// },
// 'numbers.b':{
// handler(){
// console.log('b被改變了')
// }
// }
numbers:{
deep:true,
handler(){
console.log('numbers被改變了')
}
}
}
})
</script>
</body>
</html>

(3)偵聽屬性簡寫
如果監視屬性除了 handler 沒有其他配置項的話,可以進行簡寫
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>4.天氣案例_深度監聽(簡寫)</title>
<!-- 引入Vue.js -->
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h3>今天天氣很{{ info }}</h3>
<button @click="changeWeather">切換天氣</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {isHot: true,},
computed: {info() {return this.isHot ? '炎熱' : '涼爽'}},
methods: {changeWeather() {this.isHot = !this.isHot}},
watch: {
// 正常寫法
// isHot: {
// immediate:true, //初始化時讓handler呼叫一下
// deep:true, //深度監視
// handler(newValue, oldValue) {
// console.log('isHot被修改了', newValue, oldValue)
// }
// },
//簡寫
isHot(newValue, oldValue) {
console.log('isHot被修改了', newValue, oldValue, this)
}
}
})
//正常寫法
// vm.$watch('isHot', {
// immediate: true, //初始化時讓handler呼叫一下
// deep: true,//深度監視
// handler(newValue, oldValue) {
// console.log('isHot被修改了', newValue, oldValue)
// }
// })l
//簡寫
// vm.$watch('isHot', (newValue, oldValue) => {
// console.log('isHot被修改了', newValue, oldValue, this)
// })
</script>
</body>
</html>
(4)計算屬性VS偵聽屬性
computed 和watch之間的區別
-
computed 能完成的功能, watch 都可以完成
-
watch 能完成的功能, computed 不一定能完成,例如 watch 可以進行異步操作
兩個重要的小原則
-
所有被 Vue 管理的函式,最好寫成普通函式,這樣 this 的指向才是 vm 或 組件實體物件
-
所有不被 Vue 所管理的函式(定時器的回呼函式、ajax 的回呼函式等、Promise 的回呼函式),最好寫成箭頭函式,這樣 this 的指向才是 vm 或 組件實體物件
使用計算屬性
const vm = new Vue({
el:'#root',
data:{
firstName:'DF',
lastName:'shmily',
},
computed: {
fullName() {
console.log('get被呼叫了')
return this.firstName + '-' + this.lastName
}
}
})
使用監聽屬性
new Vue({
el:'#root',
data:{
firstName:'張',
lastName:'三',
fullName:'張-三'
},
watch:{
firstName(val){
setTimeout(()=>{
this.fullName = val + '-' + this.lastName
},1000);
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
})
11、系結樣式
class 樣式
- 寫法:
:,xxx 可以是字串、陣列、物件 :style="[a,b]"其中a、b是樣式物件:style="{fontSize: xxx}"其中 xxx 是動態值- 字串寫法適用于:類名不確定,要動態獲取
- 陣列寫法適用于:要系結多個樣式,個數不確定,名字也不確定
- 物件寫法適用于:要系結多個樣式,個數確定,名字也確定,但不確定用不用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>系結樣式</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
<style>
.basic {
width: 300px;
height: 50px;
border: 1px solid black;
}
.happy {
border: 3px solid red;
background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg, yellow, pink, orange, yellow);
}
.sad {
border: 4px dashed rgb(2, 197, 2);
background-color: skyblue;
}
.normal {
background-color: #bfa;
}
.dfshmily1 {
background-color: yellowgreen;
}
.dfshmily2 {
font-size: 20px;
text-shadow: 2px 2px 10px red;
}
.dfshmily3 {
border-radius: 20px;
}
</style>
</head>
<body>
<div id="root">
<!-- 系結class樣式--字串寫法,適用于:樣式的類名不確定,需要動態指定 -->
<div : @click="changeMood">{{name}}</div><br /><br />
<!-- 系結class樣式--陣列寫法,適用于:要系結的樣式個數不確定、名字也不確定 -->
<div :>{{name}}</div><br /><br />
<!-- 系結class樣式--物件寫法,適用于:要系結的樣式個數確定、名字也確定,但要動態決定用不用 -->
<div :>{{name}}</div><br /><br />
<!-- 系結style樣式--物件寫法 -->
<div :style="styleObj">{{name}}</div><br /><br />
<!-- 系結style樣式--陣列寫法 -->
<div :style="styleArr">{{name}}</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
name: 'DFshmily',
mood: 'normal',
classArr: ['dfshmily1', 'dfshmily2', 'dfshmily3'],
classObj: {
dfshmily1: false,
dfshmily2: false,
},
styleObj: {
fontSize: '40px',
color: 'red',
},
styleObj2: {
backgroundColor: 'orange'
},
styleArr: [
{
fontSize: '40px',
color: 'blue',
},
{
backgroundColor: 'gray'
}
]
},
methods: {
changeMood() {
const arr = ['happy', 'sad', 'normal']
const index = Math.floor(Math.random() * 3)
this.mood = arr[index]
}
},
})
</script>
</body>
</html>

12、條件渲染
v-if
-
寫法 跟 if else 語法類似
v-if="運算式"v-else-if="運算式"v-else -
適用于:切換頻率較低的場景,因為不展示的 DOM 元素直接被移除
-
注意: v-if 可以和 v-else-if v-else 一起使用,但要求結構不能被打斷
v-show
- 寫法: v-show="運算式"
- 適用于:切換頻率較高的場景
- 特點:不展示的 DOM 元素未被移除,僅僅是使用樣式隱藏掉
display: none
備注
使用 v-if 的時,元素可能無法獲取到,而使用v-show一定可以獲取到template標簽不影響結構,頁面 html 中不會有此標簽,但只能配合 v-if ,不能配合 v-show
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>條件渲染</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>當前的n值是:{{ n }}</h2>
<button @click="n++">點我n+1</button>
<!-- 使用v-show做條件渲染 -->
<!-- <h2 v-show="false">歡迎來到{{name}}</h2> -->
<!-- <h2 v-show="1 === 1">歡迎來到{{name}}</h2> -->
<!-- 使用v-if做條件渲染 -->
<!-- <h2 v-if="false">歡迎來到{{name}}</h2> -->
<!-- <h2 v-if="1 === 1">歡迎來到{{name}}</h2> -->
<!-- v-else和v-else-if -->
<!-- <div v-show="n === 1">Angular</div> -->
<!-- <div v-show="n === 2">React</div> -->
<!-- <div v-show="n === 3">Vue</div> -->
<!-- <div v-if="n === 1">Angular</div> -->
<!-- <div v-else-if="n === 2">React</div> -->
<!-- <div v-else-if="n === 3">Vue</div> -->
<!-- <div v-else>哈哈</div> -->
<!-- v-if與template的配合使用 -->
<template v-if="n === 1">
<h3>你好</h3>
<h3>DFshmily</h3>
<h3>China</h3>
</template>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
name: 'DFshmily',
n: 0
}
})
</script>
</body>
</html>

13、串列渲染
(1)基本串列
v-for 指令
- 用于展示串列資料
- 語法:
<li v-for="(item, index) of items" :key="index">,這里 key 可以是 index ,更好的是遍歷物件的唯一標識 - 可遍歷:陣列、物件、字串(用的少)、指定次數(用的少)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基本串列</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 遍歷陣列 -->
<h3>人員串列(遍歷陣列)</h3>
<ul>
<li v-for="(p,index) of persons" :key="index">{{ p.name }}-{{ p.age }}</li>
</ul>
<!-- 遍歷物件 -->
<h3>汽車資訊(遍歷物件)</h3>
<ul>
<li v-for="(value,k) of car" :key="k">{{ k }}-{{ value }}</li>
</ul>
<!-- 遍歷字串 -->
<h3>測驗遍歷字串(用得少)</h3>
<ul>
<li v-for="(char,index) of str" :key="index">{{ char }}-{{ index }}</li>
</ul>
<!-- 遍歷指定次數 -->
<h3>測驗遍歷指定次數(用得少)</h3>
<ul>
<li v-for="(number,index) of 5" :key="index">{{ index }}-{{ number }}</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '張三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 }
],
car: {
name: '奧迪A8',
price: '70萬',
color: '黑色'
},
str: 'hello'
}
})
</script>
</body>
</html>

(2)key的作用與原理


面試題: react vue 中的 key 有什么作用?( key 的內部原理)
-
虛擬DOM 中 key 的作用: key 是 虛擬DOM 中物件的標識,當資料發生變化時, Vue 會根據新資料生成新的 虛擬DOM ,隨后 Vue 進行新 虛 擬DOM 與舊 虛擬DOM 的差異比較,比較規則如下
-
對比規則
? a.舊 虛擬DOM 中找到了與新 虛擬DOM 相同的 key
? i.若 虛擬DOM 中內容沒變, 直接使用之前的 真實DOM
? ii.. 若 虛擬DOM 中內容變了, 則生成新的 真實DOM ,隨后替換掉頁面中之前的 真實DOM
? b. 舊 虛擬DOM 中未找到與新 虛擬DOM 相同的 key
? 創建新的 真實DOM ,隨后渲染到到頁面
-
用 index 作為 key 可能會引發的問題
- 若對資料進行逆序添加、逆序洗掉等破壞順序操作,會產生沒有必要的 真實DOM 更新 ==> 界面效果沒問題,但效率低
- 若結構中還包含輸入類的 DOM :會產生錯誤 DOM 更新 ==> 界面有問題
-
開發中如何選擇 key ?
- 最好使用每條資料的唯一標識作為 key ,比如 id、手機號、身份證號、學號等唯一值
- 如果不存在對資料的逆序添加、逆序洗掉等破壞順序的操作,僅用于渲染串列,使用 index 作為 key 是沒有問題的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>key的原理</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人員串列(遍歷陣列)</h2>
<button @click.once="add">添加一個D</button>
<ul>
<li v-for="(p,index) of persons" :key="p.id"> <!--通過id作為key可以防止內容錯亂 -->
{{p.name}}-{{p.age}}
<input type="text">
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: 'A', age: 18 },
{ id: '002', name: 'B', age: 19 },
{ id: '003', name: 'C', age: 20 }
]
},
methods: {
add() {
const p = { id: '004', name: 'D', age: 20 }
this.persons.unshift(p)
}
},
})
</script>
</body>
</html>

(3)串列過濾
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>串列過濾</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人員串列</h2>
<input type="text" placeholder="請輸入姓名" v-model="keyWord">
<ul>
<li v-for="(p,index) of filPersons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
// 用 watch 實作
// #region
// new Vue({
// el: '#root',
// data: {
// keyWord: '',
// persons: [
// { id: '001', name: '馬冬梅', age: 19, sex: '女' },
// { id: '002', name: '周冬雨', age: 20, sex: '女' },
// { id: '003', name: '周杰倫', age: 21, sex: '男' },
// { id: '004', name: '溫兆倫', age: 22, sex: '男' }
// ],
// filPersons: []
// },
// watch: {
// keyWord: {
// immediate: true,
// handler(val) {
// this.filPersons = this.persons.filter((p) => {
// return p.name.indexOf(val) !== -1
// })
// }
// }
// }
// })
//#endregion
// 用 computed 實作
new Vue({
el: '#root',
data: {
keyWord: '',
persons: [
{ id: '001', name: '馬冬梅', age: 19, sex: '女' },
{ id: '002', name: '周冬雨', age: 20, sex: '女' },
{ id: '003', name: '周杰倫', age: 21, sex: '男' },
{ id: '004', name: '溫兆倫', age: 22, sex: '男' }
]
},
computed: {
filPersons() {
return this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
}
}
})
</script>
</body>
</html>

(4)串列排序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>串列排序</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人員串列</h2>
<input type="text" placeholder="請輸入名字" v-model="keyWord">
<button @click="sortType = 2">年齡升序</button>
<button @click="sortType = 1">年齡降序</button>
<button @click="sortType = 0">原順序</button>
<ul>
<li v-for="(p,index) of filPersons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
keyWord: '',
sortType: 0, // 0原順序 1降序 2升序
persons: [
{ id: '001', name: '馬冬梅', age: 30, sex: '女' },
{ id: '002', name: '周冬雨', age: 31, sex: '女' },
{ id: '003', name: '周杰倫', age: 18, sex: '男' },
{ id: '004', name: '溫兆倫', age: 19, sex: '男' }
]
},
computed: {
filPersons() {
const arr = this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
//判斷一下是否需要排序
if (this.sortType) {
arr.sort((p1, p2) => {
return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
})
}
return arr
}
}
})
</script>
</body>
</html>

(5)資料監視
更新時的一個問題
this.persons[0] = {id:'001',name:'馬老師',age:50,sex:'男'} 更改 data 資料, Vue 不監聽,模板不改變
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>更新時的一個問題</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人員串列</h2>
<button @click="updateMei">更新馬冬梅的資訊</button>
<ul>
<li v-for="(p,index) of persons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '馬冬梅', age: 30, sex: '女' },
{ id: '002', name: '周冬雨', age: 31, sex: '女' },
{ id: '003', name: '周杰倫', age: 18, sex: '男' },
{ id: '004', name: '溫兆倫', age: 19, sex: '男' }
]
},
methods: {
updateMei() {
// this.persons[0].name = '馬老師' //奏效
// this.persons[0].age = 50 //奏效
// this.persons[0].sex = '男' //奏效
// this.persons[0] = {id:'001',name:'馬老師',age:50,sex:'男'} //不奏效
this.persons.splice(0, 1, { id: '001', name: '馬老師', age: 50, sex: '男' })
}
}
})
</script>
</body>
</html>

(6)模擬一個資料監測
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue監測資料改變的原理</title>
<script type="text/javascript" src="https://www.cnblogs.com/DFshmily/archive/2022/10/js/vue.js"></script>
</head>
<body>
<script type="text/javascript">
let data = https://www.cnblogs.com/DFshmily/archive/2022/10/24/{
name:'DFshmily',
address: 'China',
}
// 創建一個監視的實體物件,用于監視data中屬性的變化
const obs = new Observer(data)
console.log(obs)
// 準備一個vm實體物件
let vm = {}
vm._data = https://www.cnblogs.com/DFshmily/archive/2022/10/24/data = obs
function Observer(obj) {
// 匯總物件中所有的屬性形成一個陣列
const keys = Object.keys(obj)
// 遍歷
keys.forEach((k) => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
console.log(`${k}被改了,我要去決議模板,生成虛擬DOM.....我要開始忙了`)
obj[k] = val
}
})
})
}
</script>
