VUE-第二季-01

目錄

1.Vue程序初體驗

1.1 下載并安裝vue.js

1.2 第一個Vue程序

1.3 Vue的data配置項

1.4 Vue的template配置項

1.5 Vue實例 和 容器 的關系是:一夫一妻制

2.Vue核心技術

2.0 Vue的模板語法

2.0.1 插值語法

插值語法總結:

2.0.2 指令語法

指令語法總結

v-bind指令詳解總結

2.0.3 數據綁定v-bind和v-model

2.0.4 初始MVVM架構模式

2.0.4.1 MVVM架構模式

2.0.4.2 MVVM架構模式好處

2.0.4.3 Vue和MVVM的關系

2.0.4.4 vm總結

2.1 數據代理機制

2.1.1 Object.defineProperty()

2.1.1.1 Object.defineProperty總結

2.1.2 數據代理機制

數據代理機制總結:

2.1.3 Vue數據代理機制對屬性名的要求

2.1.4 模擬Vue的數據代理

2.1.5 Vue數據代理源碼跟蹤

2.1.6 _date屬性

2.1.7 data可以寫成函數?

2.2 事件處理

2.2.1 事件處理的核心語法

2.2.2 事件修飾符

事件修飾符代碼總結:

2.2.3 按鍵修飾符

按鍵修飾符總結

2.3 計算屬性

1. 案例:用戶輸入信息,然后翻轉用戶輸入的字符串。

js知識之-join()方法的使用

語法:

示例:

1. 默認(不傳參數,使用逗號?,?連接)

2. 使用空字符串?''(無分隔符,直接拼接)

3. 使用自定義分隔符

4. 處理包含非字符串元素(會自動調用?toString()?轉換)

js知識之-split()方法的使用

split()?方法語法

參數說明

返回值

split()?的常見用法

1. 按字符拆分(split(''))

2. 按單詞拆分(split(' '))

3. 按特定符號拆分(如逗號?,)

4. 限制拆分數量(split(separator, limit))

5. 使用正則表達式拆分

更靈活的拆分方式(如按多個分隔符拆分):``js"2023/10-15".split(/[\/-]/);// 輸出: ['2023', '10', '15'](同時匹配 `/` 和 `-`)``

特殊情況的處理

1. 不傳參數(split())

2. 分隔符不存在于字符串中

3. 空字符串?split('')

4. 開頭或結尾有分隔符

2. 什么是計算屬性?

3. 計算屬性的使用

2.4 偵聽屬性的變化

2.5 class與style綁定

2.4.1 class綁定

2.4.1.1 綁定字符串

2.4.1.2 綁定數組

2.4.1.3 綁定對象

2.5 條件渲染

2.5.1 v-if

2.5.2 v-else-if、v-else

2.5.3 template與v-if

2.5.5 v-if VS v-show

條件渲染總結

2.6 列表渲染

2.6.1 遍歷數組、對象、字符串、指定次數

2.6.2 虛擬dom和diff算法

2.6.3 v-for的key的作用以及實現原理

1. 用index作為key

2. 用vip.id作為key

3. key的作用

4. diff算法是如何比較的?

5. index作為key存在兩個問題

6. index作為key和vip.id作為key對比

2.7 列表過濾

2.8 列表排序

2.9 收集表單數據

2.10 過濾器

2.11 Vue的其它指令

2.11.1 v-text

2.11.2 v-html

2.11.3 v-cloak

2.11.4 v-once

2.11.5 v-pre

2.12 vue的自定義指令

函數式:

對象式:可以使用對象式完成更加細致的功能。

以上是局部指令,全局指令怎么定義:

2.13 響應式與數據劫持

1.什么是響應式?

2.Vue的響應式是如何實現的?

3.Vue會給data中所有的屬性,以及屬性中的屬性,都會添加響應式。

4. 后期添加的屬性,不會有響應式,怎么處理?

5.Vue沒有給數組下標0,1,2,3....添加響應式,怎么處理?

數組相關方法

1.?push()?- 末尾添加元素

2.?pop()?- 移除末尾元素

3.?reverse()?- 反轉數組

4.?splice()?- 添加/刪除元素

5.?shift()?- 移除首元素

6.?unshift()?- 開頭添加元素

7.?sort()?- 數組排序

重要注意事項

2.14 Vue的生命周期

2.14.1 什么是生命周期

2.14.2 掌握Vue的生命周期有什么用

2.14.3 Vue生命周期的4個階段8個鉤子

2.14.4 初始階段做了什么事兒

2.14.5 掛載階段做了什么事兒

2.14.6 更新階段做了什么事兒

2.14.7 銷毀階段做了什么事兒


1.Vue程序初體驗

我們可以先不去了解Vue框架的發展歷史、Vue框架有什么特點、Vue是誰開發的,這些對我們編寫Vue程序起不到太大的作用,更何況現在說了一些特點之后,我們也沒有辦法徹底理解它,因此我們可以先學會用,使用一段時間之后,我們再回頭來熟悉一下Vue框架以及它的特點。現在你只需要知道Vue是一個基于JavaScript(JS)實現的框架。要使用它就需要先拿到Vue的js文件。從Vue官網(Vue.js)下載vue.js文件。

1.1 下載并安裝vue.js

第一步:打開Vue2官網,點擊下圖所示的“起步”:

第二步:繼續點擊下圖所示的“安裝”

第三步:在“安裝”頁面向下滾動,直到看到下圖所示位置:

第四步:點擊開發版本,并下載,如下圖所示:

第五步:安裝Vue:
使用script標簽引入vue.js文件。就像這樣:<script src=”xx/vue.js”></script>

第六步:VsCode安裝相關插件(僅參考)
?


還有一個liveserver,是在學習的過程中,主要作用是為靜態網頁(HTML/CSS/JavaScript)提供本地開發服務器,并支持實時刷新功能。liveserver如何使用呢?文件右鍵選擇Open with Live Server,更多功能介紹到插件中選擇liveserver學習

同時我們谷歌瀏覽器裝一下,網頁搜索極簡插件,Vue.js Devtools_7.7.7_Chrome插件下載_極簡插件
,然后搜索vue 選擇舊版的,這個支持vue2,適合我們現在學習。下載安裝以后,打開谷歌擴展程序,開發者模式,將下載的插件拖拽進行就可以了。

1.2 第一個Vue程序

集成開發環境使用VSCode,沒有的可以安裝一個:Visual Studio Code - Code Editing. Redefined
VS Code 也支持基礎模板生成:

  1. 新建文件并保存為?.html?后綴。
  1. 輸入?!?后按?Tab?鍵(需文件類型識別為 HTML),生成效果如下。

第一個Vue程序如下:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>第一個Vue程序</title><!-- 安裝vue:當你使用script進行Vue安裝之后,上下文中就注冊了一個全局變量:Vue --><script src="../js/vue.js"></script></head><body><!-- 指定Vue實例的掛載位置。 --><!-- <div id="app"></div> --><hr><div id="app"></div><script>/*第一步:創建Vue實例1. 為什么要new Vue(),直接調用Vue()函數不行嗎?不行,因為直接調用Vue()函數,不創建實例的話,會出現以下錯誤:Vue is a constructor and should be called with the `new` keyword2. 關于Vue構造函數的參數:options?option翻譯為選項options翻譯為多個選項Vue框架要求這個options參數必須是一個純粹的JS對象:{}在{}對象中可以編寫大量的key:value對。一個key:value對就是一個配置項。主要是通過options這個參數來給Vue實例指定多個配置項。3. 關于template配置項:template翻譯為:模板。template配置項用來指定什么?用來指定模板語句,模板語句是一個字符串形式的。什么是模板語句?Vue框架自己制定了一些具有特殊含義的特殊符號。Vue的模板語句是Vue框架自己搞的一套語法規則。我們寫Vue模板語句的時候,不能亂寫,要遵守Vue框架的模板語法規則。模板語句可以是一個純粹的HTML代碼,也可以是Vue中的特殊規則。也可以是HTML代碼 + Vue的特殊規則。template后面的模板語句會被Vue框架的編譯器進行編譯,轉換成瀏覽器能夠識別的HTML代碼。*/const myVue = new Vue({template : '<h1>Hello Vue!!!!!</h1>'})/*第二步:將Vue實例掛載到id='app'的元素位置。1. Vue實例都有一個$mount()方法,這個方法的作用是什么?將Vue實例掛載到指定位置。2. #app 顯然是ID選擇器。這個語法借鑒了CSS。*/myVue.$mount('#app')//myVue.$mount(document.getElementById('app'))</script></body></html>

運行效果:

對第一個程序進行解釋說明:

  1. 當使用script引入vue.js之后,Vue會被注冊為一個全局變量。就像引入jQuery之后,jQuery也會被注冊為一個全局變量一樣。
  1. 我們必須new一個Vue實例,因為通過源碼可以看到this的存在。

  1. Vue的構造方法參數是一個options配置對象。配置對象中有大量Vue預定義的配置。每一個配置項都是key:value結構。一個key:value就是一個Vue的配置項。
  1. template配置項:value是一個模板字符串。在這里編寫符合Vue語法規則的代碼(Vue有一套自己規定的語法規則)。寫在這里的字符串會被Vue編譯器進行編譯,將其轉換成瀏覽器能夠識別的HTML代碼。template稱之為模板。
  1. Vue實例的$mount方法:這個方法完成掛載動作,將Vue實例掛載到指定位置。也就是說將Vue編譯后的HTML代碼渲染到頁面的指定位置。注意:指定位置的元素被替換。
  1. ‘#app’的語法類似于CSS中的id選擇器語法。表示將Vue實例掛載到id=’app’的元素位置。當然,如果編寫原生JS也是可以的:vm.$mount(document.getElementById(‘app’))
  1. ‘#app’是id選擇器,也可以使用其它選擇器,例如類選擇器:’.app’。類選擇器可以匹配多個元素(位置),這個時候Vue只會選擇第一個位置進行掛載(從上到下第一個)。

1.3 Vue的data配置項

觀察第一個Vue程序,你會發現要完成這種功能,我們完全沒有必要使用Vue,直接在body標簽中編寫以下代碼即可:

<!DOCTYPE html>  
<html lang="en">  
<head>  <meta charset="UTF-8">  <title>沒必要使用Vue呀</title>  
</head>  
<body>  <h1>Hello Vue!</h1>  
</body>  
</html> 

那我們為什么還要使用Vue呢?在Vue中有一個data配置項,它可以幫助我們動態的渲染頁面。代碼如下:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模板語句的數據來源</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!-- 指定掛載位置 --><div id="app"></div><!-- vue程序 --><script>/*模板語句的數據來源:1. 誰可以給模板語句提供數據支持呢?data選項。2. data選項的類型是什么?Object | Function (對象或者函數)3. data配置項的專業叫法:Vue 實例的數據對象.(data實際上是給整個Vue實例提供數據來源的。)4. 如果data是對象的話,對象必須是純粹的對象 (含有零個或多個的 key/value 對)5. data數據如何插入到模板語句當中?{{}} 這是Vue框架自己搞的一套語法,別的框架看不懂的,瀏覽器也是不能夠識別的。Vue框架自己是能夠看懂的。這種語法在Vue框架中被稱為:模板語法中的插值語法。(有的人把他叫做胡子語法。)怎么用?{{data的key}}插值語法的小細節:{這里不能有其它字符包括空格{}這里不能有其它字符包括空格}*/new Vue({template : `<h1>最近非常火爆的電視劇{{name}},它的上映日期是{{releaseTime}}。主角是{{lead.name}},年齡是{{lead.age}}歲。其他演員包括:{{actors[0].name}}({{actors[0].age}}歲),{{actors[1].name}}({{actors[1].age}}歲)。{{a.b.c.d.e.name}}</h1>`,data : {name : '狂飆!!!',releaseTime : '2023年1月2日',lead : {name : '高啟強',age : 41},actors : [{name : '安欣',age : 41},{name : '高啟蘭',age : 29}],a : {b : {c : {d : {e : {name : '呵呵'}}}}}}}).$mount('#app')</script></body></html>

運行結果如下:

對以上程序進行解釋說明:

  1. data是Vue 實例的數據對象。并且這個對象必須是純粹的對象 (含有零個或多個的 key/value 對)。
  1. {{message}}是Vue框架自己搞的一個語法,叫做插值語法(或者叫做胡子語法),可以從data中根據key來獲取value,并且將value插入到對應的位置。
  1. data可以是以下幾種情況,但不限于這幾種情況:
1.???? data?:?{??2.???? ??name?:?'老杜',??3.???? ??age?:?18??4.???? }??5.???? //取值:??6.???? {{name}}??7.???? {{age}}??8.???? ??9.???? data?:?{??10.? ??user?:?{??11.? ????name?:?'老杜',??12.? ????age?:?18??13.? ??}??14.? }??15.? //取值:??16.? {{user.name}}??17.? {{user.age}}??18.? ??19.? data?:?{??20.? ??colors?:?['紅色',?'黃色',?'藍色']??21.? }??22.? //取值:??23.? {{colors[0]}}??24.? {{colors[1]}}??25.  {{colors[2]}}
  1. 以上程序執行原理:Vue編譯器對template進行編譯,遇到胡子{{}}時從data中取數據,然后將取到的數據插到對應的位置。生成一段HTML代碼,最終將HTML渲染到掛載位置,呈現。
  1. 當data發生改變時,template模板會被重新編譯,重新渲染。

1.4 Vue的template配置項

(1) template只能有一個根元素。
請看如下代碼:

<!DOCTYPE html>  
<html lang="en">  
<head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>Vue選項template</title>  <!-- 安裝vue -->  <script src="../js/vue.js"></script>  
</head>  
<body>  <!-- 指定掛載位置 -->  <div id="app"></div>  <!-- vue程序 -->  <script>  new Vue({  template : '<h1>{{message}}</h1><h1>{{name}}</h1>',  data : {  message : 'Hello Vue!',  name : '動力節點老杜'  }  }).$mount('#app')  </script>  
</body>  
</html> 

template : '<h1>{{message}}</h1><h1>{{name}}</h1>', 這里如果是兩個根元素,執行結果如下(報錯):
?


控制臺錯誤信息:組件模板應該只能包括一個根元素。
所以如果使用template的話,根元素只能有一個。
代碼修改如下:用一個div標簽包起來

1.???? new?Vue({??2.???? ????template?:?'<div><h1>{{message}}</h1><h1>{{name}}</h1></div>',??3.???? ????data?:?{??4.???? ????????message?:?'Hello?Vue!',??5.???? ????????name?:?'動力節點老杜'??6.???? ????}??7.???? }).$mount('#app')

運行結果如下:

(2) template編譯后進行渲染時會將掛載位置的元素替換。
(3) template后面的代碼如果需要換行的話,建議將代碼寫到``符號當中,不建議使用 + 進行字符串的拼接。
代碼修改如下:

new Vue({  template : `  <div>  <h1>{{message}}</h1>  <h1>{{name}}</h1>  </div>  `,  data : {  message : 'Hello Vue!',  name : '動力節點老杜'  }  
}).$mount('#app') 

運行結果如下:
?


(4) template配置項可以省略,將其直接編寫到HTML代碼當中。
代碼如下:

    <!-- 指定掛載位置 -->  <div id="app">  <div>  <h1>{{message}}</h1>  <h1>{{name}}</h1>  </div>  </div>  <!-- vue程序 -->  <script>  new Vue({  data : {  message : 'Hello Vue!',  name : '動力節點老杜'  }  }).$mount('#app')  </script> 

運行結果如下:
?


需要注意兩點:
第一:這種方式不會產生像template那種的元素替換。

第二:雖然是直接寫到HTML代碼當中的,但以上程序中第3~6行已經不是HTML代碼了,它是具有Vue語法特色的模板語句。這段內容在data發生改變后都是要重新編譯的。

(5) 將Vue實例掛載時,也可以不用$mount方法,可以使用Vue的el配置項。
代碼如下:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>template配置項詳解</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!-- 指定掛載位置 --><!-- 注意:以下代碼就是只有Vue框架能夠看懂的代碼了。下面的代碼就是一個模板語句。這個代碼是需要Vue框架編譯,然后渲染的。 --><div id="app"><div><h1>{{msg}}</h1><h1>{{name}}</h1></div></div><!-- vue程序 --><script>// Vue.config是Vue的全局配置對象。// productionTip屬性可以設置是否生成生產提示信息。// 默認值:true。如果是false則表示阻止生成提示信息。//Vue.config.productionTip = false/*關于template配置項:1.template后面指定的是模板語句,但是模板語句中只能有一個根節點。2.只要data中的數據發生變化,模板語句一定會重新編譯。(只要data變,template就會重新編譯,重新渲染)3.如果使用template配置項的話,指定掛載位置的元素會被替換。4.好消息:目前我們可以不使用template來編寫模板語句。這些模板語句可以直接寫到html標簽中。Vue框架能夠找到并編譯,然后渲染。5.如果直接將模板語句編寫到HTML標簽中,指定的掛載位置就不會被替換了。關于$mount('#app')?也可以不使用$mount('#app')的方式進行掛載了。在Vue中有一個配置項:elel配置項和$mount()可以達到同樣的效果。el配置項的作用?告訴Vue實例去接管哪個容器。el : '#app',表示讓Vue實例去接管id='app'的容器。el其實是element的縮寫。被翻譯為元素。*/new Vue({// 錯誤的//template : '<h1>{{msg}}</h1><h1>動力節點老杜</h1>',/* template : `<div><h1>{{msg}}</h1><h1>{{name}}</h1></div>`, */data : {msg : 'Hello Vue!!!!!!!',name : 'a動力節點老杜!!!!!!'},el : '#app'//el : document.getElementById('app')})//}).$mount('#app')</script></body></html>

el是element單詞的縮寫,翻譯為“元素”,el配置項主要是用來指定Vue實例關聯的容器。也就是說Vue所管理的容器是哪個。

1.5 Vue實例 和 容器 的關系是:一夫一妻制

在Vue中:一個Vue實例只服務于一個容器(一對一,一夫一妻制)。
編寫程序做一個簡單的測試:先來看一下,一個Vue實例,兩個容器,結果會是怎樣?

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>一個Vue實例服務于一個容器</title><!-- 引入vue --><script src="../js/vue.js"></script></head><body><button onclick="hello()">hello</button><!-- 準備兩個容器 --><div class="app">{{name}}</div><div class="app">{{name}}</div><script>Vue.config.productionTip = falsefunction hello() {// 這是一個Vue實例new Vue({el : '.app',data : {name : 'jackson'}})}</script></body></html>

執行結果:
?


測試結果:如果有多個容器的話,優先服務于第一個容器。
再來看一下,兩個Vue實例,一個容器,結果會怎樣?

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>兩個Vue實例,1個容器</title><!-- 引入Vue --><script src="../js/vue.js"></script></head><body><button onclick="hello()">hello</button><div id="app">姓名:{{name}},年齡:{{age}}</div><script>function hello(){// 第一個Vue實例new Vue({el : '#app',data : {name : 'jackson'}})// 第二個Vue實例new Vue({el : '#app',data : {age : 30}})}</script></body></html>

運行代碼

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>兩個Vue實例,1個容器</title><!-- 引入Vue --><script src="../js/vue.js"></script></head><body><button onclick="hello()">hello</button><div id="app">姓名:{{name}},年齡:{{age}}</div><script>function hello(){// 第一個Vue實例new Vue({el : '#app',data : {name : 'jackson'}})// 第二個Vue實例new Vue({el : '#app',data : {age : 30}})}</script></body></html>

執行結果:
?


將兩個Vue實例的先后順序再次顛倒:

再次執行:

2.Vue核心技術

2.0 Vue的模板語法

2.0.1 插值語法

插值語法格式:{{值}}
插值語法就是我們之前所說的:Mustach,胡子語法。
插值語法出現在標簽體當中。什么是標簽體?html中開始標簽和結束標簽中間的那部分就是標簽體。例如:

<p>{{值}}</p><div>{{值}}</div><h1>{{值}}</h1><span>{{值}}</span>

為什么只能放到標簽體當中,這是Vue語法規定的,因為只有放到標簽體當中,Vue才會把你當成模板進行解析。放在其他位置,它是不理會的,不解析的。例如:以上這個插值語法的代碼出現在屬性的位置上,Vue自然會忽略它的。可以測試一下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>插值語法</title><!-- 引入Vue --><script src="../js/vue.js"></script></head><body><div id="app"><a href="{{url}}">{{name}}</a></div><script>Vue.config.productionTip = falsenew Vue({el : '#app',data : {name : '百度',url : 'http://www.baidu.com'}})</script></body></html>

提示錯誤了

以上報錯信息翻譯為:屬性內的插值刪掉。改用v-bind或冒號速記。例如,使用<div :id="val"></div>代替<div id="{{val}}"></div>

插值語法{{值}} 中的“值”都可以寫什么?除了可以寫Vue對象的data屬性,其它的只要是JS表達式都可以寫。還有Vue官網提到的一些內置的函數,例如Date、Math等,具體案例可以看本節插值語法最后面的代碼演示

什么是JS表達式?

JS表達式:**可以被解析為值的代碼單元。**

常見的JS表達式包括哪些?

原始表達式
算術表達式
字符串表達式
數組初始化器表達式
邏輯表達式
對象創建表達式
調用表達式
屬性訪問表達式

測試程序:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>插值語法</title></head><body><!-- 引入Vue --><script src="../../js/vue.js"></script><!-- 準備容器 --><div id="app"><h1>真實姓名:{{realname}}</h1><h1>城市:{{address.city}}</h1><h1>街道:{{address.street}}</h1><h1>郵編:{{address.zipcode}}</h1><h1>原始表達式:{{100}}、{{'jackson'}}、{{true}}</h1><h1>算術表達式:{{1 + 1}}、{{(10 + 2) / 2}}</h1><h1>字符串表達式:{{realname + ',Mr.du'}}</h1><h1>數組初始化器表達式:{{[1,2,3]}}</h1><h1>邏輯表達式:{{true && false}}</h1><h1>對象創建表達式:{{new String('字符串對象')}}</h1><h1>調用表達式:{{'vue'.toUpperCase()}}</h1><h1>屬性訪問表達式:{{'vue'.length}}</h1><!-- 下面這個sum方法沒有,瀏覽器控制臺是會報錯的 --><h1>調用自定義的函數:{{sum(1, 2)}}</h1></div><script>function sum(a, b){return a + b}Vue.config.productionTip = falsenew Vue({el : '#app',data : {realname : '杜聚賓',address : {city : '北京',street : '大興涼水河二街',zipcode : '100176'}}})</script></body></html>

瀏覽器控制臺輸出結果:

錯誤提示信息翻譯為:屬性或方法“sum”未在實例上定義,但在渲染過程中被引用。通過初始化屬性,確保該屬性在data中或在基于類的組件中是激活的。

大致的意思是:sum要么在Vue對象的data屬性上,要么在類的組件中是被激活的。

結論:當在插值語法中使用“調用表達式”的時候,調用的函數必須是JS內置函數,自定義的函數不好使。

通過測試可以得知:插值語法{{值}}中的“值”可以是:JS表達式、Vue對象data屬性。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模板語法之插值語法{{}}</title><!-- 安裝Vue --><script src="../../js/vue.js"></script></head><body><!--主要研究:{{這里可以寫什么}}1. 在data中聲明的變量、函數等都可以。2. 常量都可以。3. 只要是合法的javascript表達式,都可以。4. 模板表達式都被放在沙盒中,只能訪問全局變量的一個白名單,如 Math 和 Date 等。'Infinity,undefined,NaN,isFinite,isNaN,''parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,''Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,''require'--><!-- 準備容器 --><div id="app"><!-- 在data中聲明的 --><!-- 這里就可以看做在使用msg變量。 --><h1>{{msg}}</h1><h1>{{sayHello()}}</h1><!-- <h1>{{i}}</h1> --><!-- <h1>{{sum()}}</h1> --><!-- 常量 --><h1>{{100}}</h1><h1>{{'hello vue!'}}</h1><h1>{{3.14}}</h1><!-- javascript表達式 --><h1>{{1 + 1}}</h1><h1>{{'hello' + 'vue'}}</h1><h1>{{msg + 1}}</h1><h1>{{'msg' + 1}}</h1><h1>{{gender ? '男' : '女'}}</h1><h1>{{number + 1}}</h1><h1>{{'number' + 1}}</h1><h1>{{msg.split('').reverse().join('')}}</h1><!-- 錯誤的:不是表達式,這是語句。 --><!-- <h1>{{var i = 100}}</h1> --><!-- 在白名單里面的 --><h1>{{Date}}</h1><h1>{{Date.now()}}</h1><h1>{{Math}}</h1><h1>{{Math.ceil(3.14)}}</h1></div><!-- vue程序 --><script>// 用戶自定義的一個全局變量var i = 100// 用戶自定義的一個全局函數function sum(){console.log('sum.....');}new Vue({el : '#app',data : {number : 1,gender : true,msg : 'abcdef', ?// 為了方便溝通,以后我們把msg叫做變量。(這行代碼就可以看做是變量的聲明。)sayHello : function(){console.log('hello vue!');}}})</script></body></html>
插值語法總結:

? ? ? ? 主要研究:{{這里可以寫什么}}

? ? ? ? 1. 在data中聲明的變量、函數等都可以。

? ? ? ? 2. 常量都可以。

? ? ? ? 3. 只要是合法的javascript表達式,都可以。

? ? ? ? 4. 模板表達式都被放在沙盒中,只能訪問全局變量的一個白名單,如 Math 和 Date 等。

? ? ? ? ? ? 'Infinity,undefined,NaN,isFinite,isNaN,'
? ? ? ? ? ? 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,'

? ? ? ? ? ? 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,'

? ? ? ? ? ? 'require'

2.0.2 指令語法

指令語法總結

指令語法:

? ? ? ? ? ? 1. 什么是指令?有什么作用?

? ? ? ? ? ? ? ? 指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用于 DOM

? ? ? ? ? ? 2. Vue框架中的所有指令的名字都以“v-”開始。

? ? ? ? ? ? 3. 插值是寫在標簽體當中的,那么指令寫在哪里呢?

? ? ? ? ? ? ? ? Vue框架中所有的指令都是以HTML標簽的屬性形式存在的,例如:

? ? ? ? ? ? ? ? ? ? <span 指令是寫在這里的>{{這里是插值語法的位置}}

? ? ? ? ? ? ? ? ? ? 注意:雖然指令是寫在標簽的屬性位置上,但是這個指令瀏覽器是無法直接看懂的。

? ? ? ? ? ? ? ? ? ? 是需要先讓Vue框架進行編譯的,編譯之后的內容瀏覽器是可以看懂的。

? ? ? ? ? ? 4. 指令的語法規則:

? ? ? ? ? ? ? ? 指令的一個完整的語法格式:

? ? ? ? ? ? ? ? ? ? <HTML標簽 v-指令名:參數="javascript表達式"></HTML標簽>

? ? ? ? ? ? ? ? ? ? 表達式:

? ? ? ? ? ? ? ? ? ? ? ? 之前在插值語法中{{這里可以寫什么}},那么指令中的表達式就可以寫什么。實際上是一樣的。

? ? ? ? ? ? ? ? ? ? ? ? 但是需要注意的是:在指令中的表達式位置不能外層再添加一個{{}}

? ? ? ? ? ? ? ? ? ? 不是所有的指令都有參數和表達式:

? ? ? ? ? ? ? ? ? ? ? ? 有的指令,不需要參數,也不需要表達式,例如:v-once

? ? ? ? ? ? ? ? ? ? ? ? 有的指令,不需要參數,但是需要表達式,例如:v-if="表達式"

? ? ? ? ? ? ? ? ? ? ? ? 有的指令,既需要參數,又需要表達式,例如:v-bind:參數="表達式"

? ? ? ? ? ? 5. v-once 指令

? ? ? ? ? ? ? ? 作用:只渲染元素一次。隨后的重新渲染,元素及其所有的子節點將被視為靜態內容并跳過。這可以用于優化更新性能。

? ? ? ? ? ? 6. v-if="表達式" 指令

? ? ? ? ? ? ? ? 作用:表達式的執行結果需要是一個布爾類型的數據:true或者false

? ? ? ? ? ? ? ? ? ? true:這個指令所在的標簽,會被渲染到瀏覽器當中。

? ? ? ? ? ? ? ? ? ? false:這個指令所在的標簽,不會被渲染到瀏覽器當中。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模板語法之指令語法 v-??? </title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--指令語法:1. 什么是指令?有什么作用?指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用于 DOM2. Vue框架中的所有指令的名字都以“v-”開始。3. 插值是寫在標簽體當中的,那么指令寫在哪里呢?Vue框架中所有的指令都是以HTML標簽的屬性形式存在的,例如:<span 指令是寫在這里的>{{這里是插值語法的位置}}</span>注意:雖然指令是寫在標簽的屬性位置上,但是這個指令瀏覽器是無法直接看懂的。是需要先讓Vue框架進行編譯的,編譯之后的內容瀏覽器是可以看懂的。4. 指令的語法規則:指令的一個完整的語法格式:<HTML標簽 v-指令名:參數="javascript表達式"></HTML標簽>表達式:之前在插值語法中{{這里可以寫什么}},那么指令中的表達式就可以寫什么。實際上是一樣的。但是需要注意的是:在指令中的表達式位置不能外層再添加一個{{}}不是所有的指令都有參數和表達式:有的指令,不需要參數,也不需要表達式,例如:v-once有的指令,不需要參數,但是需要表達式,例如:v-if="表達式"有的指令,既需要參數,又需要表達式,例如:v-bind:參數="表達式"5. v-once 指令作用:只渲染元素一次。隨后的重新渲染,元素及其所有的子節點將被視為靜態內容并跳過。這可以用于優化更新性能。6. v-if="表達式" 指令作用:表達式的執行結果需要是一個布爾類型的數據:true或者falsetrue:這個指令所在的標簽,會被渲染到瀏覽器當中。false:這個指令所在的標簽,不會被渲染到瀏覽器當中。--><!-- 準備一個容器 --><div id="app"><h1>{{msg}}</h1><h1 v-once>{{msg}}</h1><h1 v-if="a > b">v-if測試:{{msg}}</h1></div><!-- vue程序 --><script>new Vue({el : '#app',data : {msg : 'Hello Vue!',a : 10,b : 11}})</script></body></html>
v-bind指令詳解總結

v-bind指令詳解

? ? ? ? ? ? 1. 這個指令是干啥的?

? ? ? ? ? ? ? ? 它可以讓HTML標簽的某個屬性的值產生動態的效果。

? ? ? ? ? ? 2. v-bind指令的語法格式:

? ? ? ? ? ? ? ? <HTML標簽 v-bind:參數="表達式"></HTML標簽>

? ? ? ? ? ? 3. v-bind指令的編譯原理?

? ? ? ? ? ? ? ? 編譯前:

? ? ? ? ? ? ? ? ? ? <HTML標簽 v-bind:參數="表達式"></HTML標簽>

? ? ? ? ? ? ? ? 編譯后:

? ? ? ? ? ? ? ? ? ? <HTML標簽 參數="表達式的執行結果"></HTML標簽>

? ? ? ? ? ? ? ? 注意兩項:

? ? ? ? ? ? ? ? ? ? 第一:在編譯的時候v-bind后面的“參數名”會被編譯為HTML標簽的“屬性名”

? ? ? ? ? ? ? ? ? ? 第二:表達式會關聯data,當data發生改變之后,表達式的執行結果就會發生變化。

? ? ? ? ? ? ? ? ? ? 所以,連帶的就會產生動態效果。

? ? ? ? ? ? 4. v-bind因為很常用,所以Vue框架對該指令提供了一種簡寫方式:

? ? ? ? ? ? ? ? 只是針對v-bind提供了以下簡寫方式:

? ? ? ? ? ? ? ? ? <i/mg :src="imgPath">

? ? ? ? ? ? 5. 什么時候使用插值語法?什么時候使用指令?

? ? ? ? ? ? ? ? 凡是標簽體當中的內容要想動態,需要使用插值語法。

? ? ? ? ? ? ? ? 只要向讓HTML標簽的屬性動態,需要使用指令語法。

代碼演示:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>v-bind指令詳解(它是一個負責動態綁定的指令)</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--v-bind指令詳解1. 這個指令是干啥的?它可以讓HTML標簽的某個屬性的值產生動態的效果。2. v-bind指令的語法格式:<HTML標簽 v-bind:參數="表達式"></HTML標簽>3. v-bind指令的編譯原理?編譯前:<HTML標簽 v-bind:參數="表達式"></HTML標簽>編譯后:<HTML標簽 參數="表達式的執行結果"></HTML標簽>注意兩項:第一:在編譯的時候v-bind后面的“參數名”會被編譯為HTML標簽的“屬性名”第二:表達式會關聯data,當data發生改變之后,表達式的執行結果就會發生變化。所以,連帶的就會產生動態效果。4. v-bind因為很常用,所以Vue框架對該指令提供了一種簡寫方式:只是針對v-bind提供了以下簡寫方式:<i/mg :src="imgPath">5. 什么時候使用插值語法?什么時候使用指令?凡是標簽體當中的內容要想動態,需要使用插值語法。只要向讓HTML標簽的屬性動態,需要使用指令語法。--><!-- 準備一個容器 --><div id="app"><!-- 注意:以下代碼中 msg 是變量名。 --><!-- 注意:原則上v-bind指令后面的這個參數名可以隨便寫。 --><!-- 雖然可以隨便寫,但大部分情況下,這個參數名還是需要寫成該HTML標簽支持的屬性名。這樣才會有意義。 --><span v-bind:xyz="msg"></span><!-- 這個表達式帶有單引號,這個'msg'就不是變量了,是常量。 --><span v-bind:xyz="'msg'"></span><!-- v-bind實戰 --><i/m/g s/r/c="../img/1.jpg"> <br><i/m/g v-bind:src="imgPath"> <br><!-- v-bind簡寫形式 --><i/mg :src="imgPath"> <br><!-- 這是一個普通的文本框 --><input type="text" name="username" value="zhangsan"> <br><!-- 以下文本框可以讓value這個數據變成動態的:這個就是典型的動態數據綁定。 --><input type="text" name="username" :value="username"> <br><!-- 使用v-bind也可以讓超鏈接的地址動態 --><a href="https://www.baidu.com">走起</a> <br><a :href="url">走起2</a> <br><!-- 不能采用以下寫法嗎? --><!--不能這樣,報錯了,信息如下:Interpolation inside attributes has been removed.Use v-bind or the colon shorthand instead. For example,instead of <div id="{{ val }}">, use <div :id="val">屬性內部插值這種語法已經被移除了。(可能Vue在以前的版本中是支持這種寫法的,但是現在不允許了。)請使用v-bind或冒號速記來代替。請使用 <div :id="val"> 來代替 <div id="{{ val }}">--><!-- <a href="{{url}}">走起3</a> ?--><h1>{{msg}}</h1></div><!-- vue程序 --><script>// 賦值的過程就可以看做是一種綁定的過程。//let i = 100new Vue({el : '#app',data : {msg : 'Hello Vue!',imgPath : '../img/1.jpg',username : 'jackson',url : 'https://www.baidu.com'}})</script></body></html>

2.0.3 數據綁定v-bind和v-model

Vue關于數據綁定,提供了單向綁定和雙向綁定兩種方式。

  • v-bind指令進行的數據綁定是單向的,當數據data更新時,視圖會更新。但當視圖更新后,數據data并不會更新。
  • v-model指令進行數據綁定是雙向的,當數據data更新時,視圖會更新。當視圖更新后,數據data也會隨之更新。

v-bind和v-model除了一個單向一個雙向之外,還有其它區別嗎?有

  • v-bind使用在標簽的任意屬性上,包括自定義的屬性。
  • v-model只能使用在具有value屬性的input標簽以及文本域textarea中。(因為只有input和textarea控件提供了用戶輸入的界面。只有提供了用戶的輸入界面,才可以讓用戶完成視圖的更新。視圖更新了數據data才會更新。另外也之后這種輸入界面才能夠觸發鍵盤事件,通過鍵盤事件Vue底層才能更新去執行代碼,更新數據data。
  • 需要注意:input標簽有很多,例如文本框,單選按鈕,復選框,下拉列表等。
  • v-bind和v-model都有簡寫方式:
    ? ? ? ? ? ? ? ? v-bind簡寫方式:
    ? ? ? ? ? ? ? ? ? ? v-bind:參數="表達式" ? ?簡寫為 ? ? ?:參數="表達式"
    ? ? ? ? ? ? ? ? v-model簡寫方式:
    ? ? ? ? ? ? ? ? ? ? v-model:value="表達式" ?簡寫為 ? ? ?v-model="表達式"

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>v-model指令詳解</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--v-bind和v-model的區別和聯系1. v-bind和v-model這兩個指令都可以完成數據綁定。2. v-bind是單向數據綁定。data ===> 視圖3. v-model是雙向數據綁定。data <===> 視圖4. v-bind可以使用在任何HTML標簽當中。v-model只能使用在表單類元素上,例如:input標簽、select標簽、textarea標簽。為什么v-model的使用會有這個限制呢?因為表單類的元素才能給用戶提供交互輸入的界面。v-model指令通常也是用在value屬性上面的。5. v-bind和v-model都有簡寫方式:v-bind簡寫方式:v-bind:參數="表達式" ? ?簡寫為 ? ? ?:參數="表達式"v-model簡寫方式:v-model:value="表達式" ?簡寫為 ? ? ?v-model="表達式"--><!-- 準備一個容器 --><div id="app">v-bind指令:<input type="text" v-bind:value="name1"><br>v-model指令:<input type="text" v-model:value="name2"><br><!-- 以下報錯了,因為v-model不能使用在這種元素上。 --><!-- <a v-model:href="url">百度</a> -->v-bind指令:<input type="text" :value="name1"><br>v-model指令:<input type="text" v-model="name2"><br>消息1:<input type="text" :value="msg"><br>消息2:<input type="text" v-model="msg"><br></div><!-- vue程序 --><script>new Vue({el : '#app',data : {name1 : 'zhangsan',name2 : 'wangwu',url : 'https://www.baidu.com',msg : 'Hello Vue!'}})</script></body></html>

2.0.4 初始MVVM架構模式

MVVM是一種架構模式(一種系統分層的思想),是Model-View-ViewModel的縮寫。

MVVM 的出現促進了前端開發與后端業務邏輯的分離,極大地提高了前端開發效率。

2.0.4.1 MVVM架構模式

MVVM 的核心是 ViewModel 層,它就像是一個中轉站,負責轉換 Model 中的數據對象來讓數據變得更容易管理和使用,該層向上與視圖層進行雙向數據綁定,向下與 Model 層通過接口請求進行數據交互,起呈上啟下作用。如下圖所示:

  1. Model:數據模型,由服務端(后端)提供,它是數據的來源。
  1. View:視圖,和用戶交互的界面。視圖負責將數據展示到界面。
  1. ViewModel:簡稱vm,是MVVM的核心。它的存在,讓Model和View達到了解耦合(它的存在讓系統分層了,分為Model層和View層,并且這兩層是解耦合的),這個解耦合就是前后端分離。
  1. Model和View是無法直接聯系的,ViewModel是Model和View溝通的“橋梁”。
  1. ViewModel的核心主要是實現了Dom監聽和數據綁定,通過它達到了雙向數據綁定的效果。
  1. DOM監聽:ViewModel可以監聽頁面DOM元素的變化,例如DOM元素的value被更新,DOM元素被點擊等。當監聽到DOM元素發生變化時,會對應更新數據data。(View更新-->data則更新)
  1. 數據綁定:ViewModel可以將數據data和頁面元素進行綁定,當數據data發生改變時,頁面元素也同步更新。(data更新-->View則更新)
  1. 所謂的雙向數據綁定就是:數據data更新時,View隨之更新。當View更新時,數據data也隨之更新。
  1. ViewModel幫我們做了很多事情,像以前沒有ViewModel的時候,第一:我們拿到后端返回的數據之后,親自編寫操作DOM的代碼來更新視圖。第二:當我們獲取表單中的數據時,需要親自編寫操作DOM的代碼來獲取表單數據。有了ViewModel之后,這些代碼都在ViewModel中提前封裝好了,不需要我們寫。大大提高了開發效率。同時也讓我們程序員更加專注業務邏輯的處理。
  1. ViewModel是一個觀察者。(MVVM符合觀察者模式。)

為了幫助大家理解MVVM,畫了一張圖來說明MVVM各層技術的組成部分:

后端業務處理再復雜跟前端也沒有半毛錢關系,只要后端保證對外接口足夠簡單就行了,我請求api,后端你把數據返回即可。

ViewModel是由前端開發人員組織生成和維護的視圖數據層。在這一層,前端開發者對從后端獲取的Model數據進行轉換處理,做二次封裝,以生成符合View層使用預期的視圖數據模型。需要注意的是ViewModel所封裝的數據模型包括視圖的狀態和行為兩部分,而Model層的數據模型只包含狀態的,比如頁面的這一塊展示什么,那一塊展示什么這些都屬于視圖狀態(展示),而頁面加載進行時發生什么,點擊這一塊發生什么,這一塊滾動時發生什么這些都屬于視圖行為(交互),視圖狀態和行為都封裝在了ViewModel里。這樣的封裝使得ViewModel可以完整地去描述View層。由于實現了雙向綁定,ViewModel 的內容會實時展現在 View 層,這是激動人心的,因為前端開發者再也不必低效又麻煩地通過操縱 DOM 去更新視圖,MVVM 框架已經把最臟最累的一塊做好了,我們開發者只需要處理和維護 ViewModel,更新數據視圖就會自動得到相應更新,真正實現數據驅動開發。看到了吧,View 層展現的不是 Model 層的數據,而是 ViewModel 的數據,由 ViewModel 負責與 Model 層交互,這就完全解耦了 View 層和 Model 層,這個解耦是至關重要的,它是前后端分離方案實施的重要一環。

2.0.4.2 MVVM架構模式好處
  1. 低耦合: 視圖(View)可以獨立于Model變化和修改,一個ViewModel可以綁定到不同的View上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
  1. 可重用性: 你可以把一些視圖邏輯放在一個ViewModel里面,讓很多View重用這段視圖邏輯。
  1. 獨立開發: 開發人員可以專注于業務邏輯和數據的開發,設計人員可以專注于頁面設計。
  1. 可測試:界面素來是比較難于測試的,而現在測試可以針對ViewModel來寫。
2.0.4.3 Vue和MVVM的關系

Vue和Angular都是實現MVVM架構模式的框架。

Vue中的Vue實例“new Vue()”就是MVVM中的VM,也就是ViewModel。所以一般會給Vue實例起名:vm,代碼如下:

const vm = new Vue({el : '#app',data : {username : 'zhangsan',age : 20}
})

為了提高編碼速度,可以在VSCode當中配置用戶代碼片段,將以上代碼配置為模板,例如:

{"create json obj": {"prefix": "jsonobj","body": ["let obj = {","    $1","}","$2"]},"create vue instance":{"prefix": "vm","body": ["const vm = new Vue({","    el : '#app',","    data : {","        $1","    }","})",]}
}

然后在VSCode工具中需要使用Vue實例的位置直接輸入vm,代碼片段自動生成:

實際代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>初識MVVM分層思想</title><script src="../js/vue.js"></script></head><body><!--1. MVVM是什么?M:Model(模型/數據)V:View(視圖)VM:ViewModel(視圖模型):VM是MVVM中的核心部分。(它起到一個核心的非常重要的作用。)MVVM是目前前端開發領域當中非常流行的開發思想。(一種架構模式。)目前前端的大部分主流框架都實現了這個MVVM思想,例如Vue,React等。2. Vue框架遵循MVVM嗎?雖然沒有完全遵循 MVVM 模型,但是 Vue 的設計也受到了它的啟發。Vue框架基本上也是符合MVVM思想的。3. MVVM模型當中倡導了Model和View進行了分離,為什么要分離?假如Model和View不分離,使用最原始的原生的javascript代碼寫項目:如果數據發生任意的改動,接下來我們需要編寫大篇幅的操作DOM元素的JS代碼。將Model和View分離之后,出現了一個VM核心,這個VM把所有的臟活累活給做了,也就是說,當Model發生改變之后,VM自動去更新View。當View發生改動之后,VM自動去更新Model。我們再也不需要編寫操作DOM的JS代碼了。開發效率提高了很多。--><!-- 準備容器 --><!-- View V--><div id="app">姓名:<input type="text" v-model="name"></div><!-- vue程序 --><script>// ViewModel ?VMconst vm = new Vue({el : '#app',// Model ?Mdata : {name : 'zhangsan'}})</script></body></html>
2.0.4.4 vm總結
  1. 通過Vue實例都可以訪問哪些屬性?(通過vm都可以vm. 什么。)

? ? ? ? ? ? Vue實例中的屬性很多,有的以 開始,有的以 _ 開始。
? ? ? ? ? ?
? ? ? ? ? ? 所有以 開始的屬性,可以看做是公開的屬性,這些屬性是供程序員使用的。

? ? ? ? ? ? 所有以 _ 開始的屬性,可以看做是私有的屬性,這些屬性是Vue框架底層使用的。一般我們程序員很少使用。
? ? ? ? ? ? 通過vm也可以訪問Vue實例對象的原型對象上的屬性,例如:vm.$delete...

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>認識vm</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--1. 通過Vue實例都可以訪問哪些屬性?(通過vm都可以vm. 什么。)Vue實例中的屬性很多,有的以 $ 開始,有的以 _ 開始。所有以 $ 開始的屬性,可以看做是公開的屬性,這些屬性是供程序員使用的。所有以 _ 開始的屬性,可以看做是私有的屬性,這些屬性是Vue框架底層使用的。一般我們程序員很少使用。通過vm也可以訪問Vue實例對象的原型對象上的屬性,例如:vm.$delete...2.--><div id="app"><h1>{{msg}}</h1></div><script>let dataObj = {msg : 'Hello Vue!'}const vm = new Vue({el : '#app',data : dataObj})// 按說msg是dataObj對象的屬性。console.log('dataObj的msg', dataObj.msg);// 為什么msg屬性可以通過vm來訪問呢?// 這是因為Vue框架底層使用了數據代理機制。// 要想搞明白數據代理機制,必須有一個基礎知識點要學會:Object.defineProperty()。console.log('vm的msg', vm.msg);</script></body></html>

2.1 數據代理機制

2.1.1 Object.defineProperty()

這是ES5的特性,這個方法的作用是:給對象定義新屬性或修改原有的屬性。
語法如下:

Object.defineProperty(對象, 屬性名, 配置項)

對象:指定給哪個對象定義新屬性。

屬性名:新屬性的屬性名。

配置項:給該屬性設置一些配置項,采用 {} 進行配置

編寫程序,測試該方法是否能夠為對象添加新屬性:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ES6新特性:Object.definedProperty(),給對象定義新屬性或修改屬性</title></head><body><script>// 對象let phone = {name : 'iPhone 14',price : 11000}// 給對象phone定義新屬性顏色colorObject.defineProperty(phone, 'color', {})// 讀取color屬性console.log('手機顏色:' + phone.color) </script></body></html>

執行結果:

結果是undefined,這是因為沒有給color屬性指定值,默認值是undefined,可以通過配置項value給屬性指定值:

Object.defineProperty(phone, 'color', {value : '太空灰'
})


可以對新增的color屬性重新賦值嗎?嘗試一下:
?


執行結果:
?


重新賦值失敗,怎么樣才能支持重新賦值呢?需要添加一個配置項writable,將其設置為true:
?


再次執行:
?


重點來了:在defineProperty方法中的配置項中有getter和setter方法,當修改對象的屬性值時,setter方法會被自動調用,當讀取對象的屬性值時,getter方法會被自動調用,測試一下:

Object.defineProperty(phone, 'color', {value : '太空灰', // 給屬性指定值writable : true, // 設置該屬性的值是否可以被重寫,默認false,true表示支持重寫// getterget : function(){console.log('getter執行了')},// setterset : function(){console.log('setter執行了')}
})

執行結果:

這個錯誤原因是:當你使用getter和setter的時候,不能使用writable和value。把這兩個配置項注釋掉:

Object.defineProperty(phone, 'color', {//value : '太空灰', // 給屬性指定值//writable : true, // 設置該屬性的值是否可以被重寫,默認false,true表示支持重寫// getterget : function(){console.log('getter執行了')},// setterset : function(){console.log('setter執行了')}
})


所以在使用getter和setter的時候,配置項writable和value是不能出現的。

setter在什么時候執行的?getter又是在什么時候執行的?

當你給對象屬性賦值的時候setter方法會被自動調用。

當你讀取對象屬性的時候getter方法會被自動調用。

為什么執行結果是:“手機顏色:undefined”,顯然是因為setter方法中什么也沒做,并沒有在該方法中完成賦值,要賦值的話,首先要拿到這個值,也就是拿到'夕陽紅',怎么拿?setter方法上有一個參數,這個參數是專門用來接收'夕陽紅'這個值的,測試一下:
?


注意:setter方法的參數名是隨意的,只是一個變量名而已,都能接收賦值時傳過來的值。

接下來,在setter方法和getter方法中編寫代碼,來完成屬性值的修改以及讀取屬性值,代碼如下:

為什么運行結果報錯了,而且還是棧內存溢出?顯然是因為遞歸導致的。這是因為我們在setter方法中執行了this.color = val,而這個操作執行時setter方法會被調用,setter方法調用后,又執行this.color = val,此時又會去執行setter方法。getter方法也是同理的。不再贅述。結論是:不要在getter中再次獲取該屬性值,也不要在setter中再次設置該屬性,會發生無限遞歸,導致棧內存溢出錯誤的發生。

那該怎么辦?可以在外面定義一個臨時的變量,當getter方法執行時返回該臨時變量的值,當setter方法執行時修改臨時變量的值,代碼如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>ES6新特性:Object.definedProperty(),給對象定義新屬性或修改屬性</title></head><body><script>// 對象let phone = {name : 'iPhone 14',price : 11000}// 臨時變量,用來存儲屬性的值let temp// 給對象phone定義新屬性顏色colorObject.defineProperty(phone, 'color', {//value : '太空灰', // 給屬性指定值//writable : true, // 設置該屬性的值是否可以被重寫,默認false,true表示支持重寫// getterget : function(){console.log('getter執行了')return temp},// setterset : function(val){console.log('setter執行了')console.log('拿到的值:' + val)temp = val}})// 給新增的color屬性重新賦值phone.color = '夕陽紅'// 讀取color屬性console.log('手機顏色:' + phone.color) </script></body></html>


根據ES6新特性來說,在對象中的函數是可以簡寫的,其中“:function”是可以省略的,也就是說以上的代碼可簡寫為如下的代碼:
?


以后大家在編寫代碼的時候,直接采用簡寫形式即可。
那么了解了Object.defineProperty()方法之后,它和數據代理機制有什么關系呢?

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Object.defineProperty()</title></head><body><!--Object.defineProperty()1. 這個方法是ES5新增的。2. 這個方法的作用是:給對象新增屬性,或者設置對象原有的屬性。3. 怎么用?Object.defineProperty(給哪個對象新增屬性, '新增的這個屬性名叫啥', {給新增的屬性設置相關的配置項key:value對})4. 第三個參數是屬性相關的配置項,配置項都有哪些?每個配置項的作用是啥?value 配置項:給屬性指定值writable 配置項:設置該屬性的值是否可以被修改。true表示可以修改。false表示不能修改。getter方法 配置項:不需要我們手動調用的。當讀取屬性值的時候,getter方法被自動調用。* getter方法的返回值非常重要,這個返回值就代表這個屬性它的值。setter方法 配置項:不需要我們手動調用的。當修改屬性值的時候,setter方法被自動調用。* setter方法上是有一個參數的,這個參數可以接收傳過來的值。注意:當配置項當中有setter和getter的時候,value和writable配置項都不能存在。--><script>// 這是一個普通的對象let phone = {}// 臨時變量let temp// 給上面的phone對象新增一個color屬性Object.defineProperty(phone, 'color', {//value : '太空灰',//writable : true,// getter方法配置項get : function(){console.log('getter方法執行了@@@');//return '動態'//return this.colorreturn temp},// setter方法配置項set : function(val){console.log('setter方法執行了@@@',val);//this.color = valtemp = val}})</script></body></html>
2.1.1.1 Object.defineProperty總結

? ? ? ? 1. 這個方法是ES5新增的。

? ? ? ? 2. 這個方法的作用是:給對象新增屬性,或者設置對象原有的屬性。

? ? ? ? 3. 怎么用?

? ? ? ? ? ? Object.defineProperty(給哪個對象新增屬性, '新增的這個屬性名叫啥', {給新增的屬性設置相關的配置項key:value對})

? ? ? ? 4. 第三個參數是屬性相關的配置項,配置項都有哪些?每個配置項的作用是啥?

? ? ? ? ? ? value 配置項:給屬性指定值

? ? ? ? ? ? writable 配置項:設置該屬性的值是否可以被修改。true表示可以修改。false表示不能修改。

? ? ? ? ? ? getter方法 配置項:不需要我們手動調用的。當讀取屬性值的時候,getter方法被自動調用。

? ? ? ? ? ? ? ? * getter方法的返回值非常重要,這個返回值就代表這個屬性它的值。

? ? ? ? ? ? setter方法 配置項:不需要我們手動調用的。當修改屬性值的時候,setter方法被自動調用。

? ? ? ? ? ? ? ? * setter方法上是有一個參數的,這個參數可以接收傳過來的值。

? ? ? ? ? ? 注意:當配置項當中有setter和getter的時候,value和writable配置項都不能存在。

2.1.2 數據代理機制

所謂的數據代理就是:通過訪問代理對象的數據來間接訪問目標對象的數據。可以寫一個程序,給大家演示一下數據代理:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>數據代理</title></head><body><script>// 目標對象var target = {name : 'zhangsan'}// 代理對象var proxy = {}// 為代理對象添加新屬性nameObject.defineProperty(proxy, 'name', {get(){return target.name},set(val){target.name = val}})// 通過訪問代理對象的name屬性來間接訪問目標對象的name屬性proxy.name = 'jackson'console.log('proxy.name = ' + proxy.name)console.log('target.name = ' + target.name)</script></body></html>

執行結果:
通過測試得知,當我們修改代理的name時,目標的name也被修改了。這就是數據代理的實現原理。
?


我們可以把proxy在控制臺輸出一下,看看是什么樣子
通過測試得知,當我們修改代理的name時,目標的name也被修改了。這就是數據代理的實現原理。

我們可以把proxy在控制臺輸出一下,看看是什么樣子
?


你會看到一個name屬性,并且這個name屬性對應了getter和setter方法。

注意:凡是在控制臺輸出的時候,屬性的值是:(...),就表示該屬性使用了數據代理機制,(...) 表示目前未知,必須通過調用getter方法來動態獲取該屬性的值,鼠標停留到"(...)"上面,你會看到如下提示信息:


當我們點擊"(...)"的時候會調用getter方法:

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>數據代理機制</title><script src="../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1></div><script>const vm = new Vue({el : '#app',data : {msg : 'Hello Vue!'}})</script><!--1. 什么是數據代理機制?通過訪問 代理對象的屬性 來間接訪問 目標對象的屬性。數據代理機制的實現需要依靠:Object.defineProperty()方法。2. ES6新特性:在對象中的函數/方法 :function 是可以省略的。--><script>// 目標對象let target = {name : 'zhangsan'}// 代理對象let proxy = {}// 如果要實現數據代理機制的話,就需要給proxy新增一個name屬性。// 注意:代理對象新增的這個屬性的名字 和 目標對象的屬性名要一致。Object.defineProperty(proxy, 'name', {// get : function(){// ? ? // 間接訪問目標對象的屬性// ? ? return target.name// },// set : function(val){// ? ? target.name = val// }get(){console.log('getter方法執行了@@@@');return target.name},set(val){target.name = val}})// let target = {// ? ? name : 'zhangsan'// }// const vm = new Vue({// ? ? el : '#app',// ? ? data : target// })</script></body></html>
數據代理機制總結:
  1. 什么是數據代理機制?

? ? ? ? ? ? 通過訪問 代理對象的屬性 來間接訪問 目標對象的屬性。

? ? ? ? ? ? 數據代理機制的實現需要依靠:Object.defineProperty()方法。

? ? ? ? 2. ES6新特性:

? ? ? ? ? ? 在對象中的函數/方法 :function 是可以省略的。

2.1.3 Vue數據代理機制對屬性名的要求

學習代碼:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue數據代理機制對屬性名的要求</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--1. Vue實例不會給以_和$開始的屬性名做數據代理。2. 為什么?如果允許給_或$開始的屬性名做數據代理的話。vm這個Vue實例上可能會出現_xxx或$xxx屬性,而這個屬性名可能會和Vue框架自身的屬性名沖突。3. 在Vue當中,給data對象的屬性名命名的時候,不能以_或$開始。--><!-- 容器 --><div id="app"><h1>{{msg}}</h1></div><!-- vue程序 --><script>const vm = new Vue({el : '#app',data : {msg : 'Hello Vue!',_name : 'zhangsan',$age : 20}})</script></body></html>

執行結果,這樣寫完以后只要是我們以$和_開頭的自定義的屬性,都不會被Vue識別,其他自定義的屬性都可以。

2.1.4 模擬Vue的數據代理

Vue的代碼是這樣寫的:

const vm = new Vue({el : '#app',data : {name : 'jackson'}
})// 讀取name
console.log('name = ' + vm.name)
// 修改name
vm.name = 'lucy'
// 讀取name
console.log('name = ' + vm.name)

我們可以自己寫一個程序,模擬一下Vue,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Vue的數據代理</title></head><body><script>// ES6新特性(用class關鍵字定義類)class Vue {// ES6新特性(構造函數)constructor(options) {// 獲取目標對象的所有屬性(options.data就是目標對象)let target = options.data// 給代理對象擴展屬性(在構造方法中this就是當前對象,當前對象是Vue實例,所以this就是代理對象)let proxy = this// 遍歷目標對象的所有屬性(屬性可能有多個)// Object.keys(obj) 可以獲取obj對象的所有屬性名,并最終得到一個數組。【ES6新特性】Object.keys(target).forEach((propertyName) => {Object.defineProperty(this, propertyName, {get(){return target[propertyName]},set(val){target[propertyName] = val}})})}}// 目標對象let options = {data : {name : 'xiaoming',age : 20}}// 代理對象const vm = new Vue(options)// 通過代理vm訪問目標options.data中的屬性console.log('vm.name = ' + vm.name)vm.name = 'xiaogang'console.log('vm.name = ' + vm.name)console.log('vm.age = ' + vm.age)vm.age = 18console.log('vm.age = ' + vm.age)</script></body></html>

2.1.5 Vue數據代理源碼跟蹤

以上是我們自己寫的,真正的Vue框架底層是如何實現數據代理的呢?一起跟蹤一下源碼:

以下源碼跟蹤方式是在chrome瀏覽器中添加斷點的方式進行跟蹤:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>解讀Vue框架源代碼</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--Vue框架源代碼中關鍵性代碼:1. var data = vm.$options.data;注意:這是獲取data。程序執行到這里的時候vm上還沒有 _data 屬性。2. data = vm._data = isFunction(data) ? getData(data, vm) : data || {};程序執行完這個代碼之后,vm對象上多了一個_data這樣的屬性。通過以上源碼解讀,可以得知data不一定是一個{},也可以是一個函數。代碼含義:如果data是函數,則調用getData(data, vm)來獲取data。如果data不是函數,則直接將data返回,給data變量。并且同時將data賦值給vm._data屬性了。有一個疑問?程序執行到這里,為什么要給vm擴展一個_data屬性呢?_data屬性,以"_"開始,足以說明,這個屬性是人家Vue框架底層需要訪問的。Vue框架底層它使用vm._data這個屬性干啥呢?vm._data是啥?vm._data 是:{name : 'jackson',age : 35}vm._data 這個屬性直接指向了底層真實的data對象。通過_data訪問的name和age是不會走數據代理機制的。通過vm._data方式獲取name和age的時候,是不會走getter和setter方法的。注意:對于Vue實例vm來說,不僅有_data這個屬性,還有一個$data這個屬性。_data 是框架內部使用的,可以看做私有的。$data 這是Vue框架對外公開的一個屬性,是給我們程序員使用。3. 重點函數:function isReserved(str) {var c = (str + '').charCodeAt(0);return c === 0x24 || c === 0x5f;}這個函數是用來判斷字符串是否以 _ 和 $ 開始的。true表示以_或$開始的。false表示不是以_或$開始的。4. proxy(vm, "_data", key);通過這行代碼直接進入代理機制(數據代理)。5. 重點函數proxyfunction proxy(target, sourceKey, key) { // target是vm,sourceKey是"_data",key是"age"sharedPropertyDefinition.get = function proxyGetter() {return this["_data"]["age"];};sharedPropertyDefinition.set = function proxySetter(val) {this["_data"]["age"] = val;};Object.defineProperty(vm, 'age', sharedPropertyDefinition);}--><!-- 容器 --><div id="app"><h1>姓名:{{name}}</h1><h1>年齡:{{age}}歲</h1></div><!-- vue代碼 --><script>function isReserved(str) {var c = (str + '').charCodeAt(0);return c === 0x24 || c === 0x5f;}const vm = new Vue({el : '#app',data : {name : 'jackson',age : 35}})// 如果我們程序員不想走代理的方式讀取data,想直接讀取data當中的數據,可以通過_data和$data屬性來訪問。// 建議使用$data這個屬性。console.log('name = ' + vm.$data.name)console.log('age = ' + vm.$data.age)</script></body></html>

2.1.6 _date屬性

在之前的源碼追蹤過程中,我們可以看到Vue實例定義了一個_data屬性:

可以在控制臺查看一下,是否存在這樣的屬性:

果然是存在的,那么也就是說,通過_data屬性也可以訪問data的屬性?

_data屬性這個了解一下就行,到目前為止,訪問data的屬性可以通過兩種方式:

  • 第一種方式(常用):vm.name
  • 第二種方式(了解):vm._data.name

在這里再給大家透露一個小技巧,大家在查看Vue實例的時候,發現Vue實例有很多屬性,有的以“$”開始,有的以“_”開始,這里要記住哦:

  • "$"開始的屬性一般都是公開的,供我們開發人員使用的。
  • "_"開始的屬性一般都是私有的,是供Vue核心程序使用的,支撐Vue運行的,這些屬性是不建議我們使用的。(所以_data屬性了解一下即可。)

2.1.7 data可以寫成函數?

如果data是一個函數的話,必須返回一個{}對象
另外還有一點需要大家記住,data如果寫成函數的話,這個函數不能夠使用箭頭函數。因為箭頭函數中的this是window對象。我們需要讓這個this是當前的Vue實例。

到目前為止,大家知道的defineProperty方法的配置項的屬性有兩個:

  • 一個是value:給新增的屬性賦值
  • 一個是writable:默認值false,如果是true表示該屬性的值是可修改的

如果setter和getter使用的話,以上兩個屬性都是不能出現的。這一點還是要記住。
那么除了writable和value之外,還有其他的屬性嗎?當然有,例如:

  • enumerable:值為布爾類型true或者false。默認值false。true表示該屬性可枚舉,可遍歷。
  • configurable:值為布爾類型true或者false。默認值false。true表示該屬性可刪除。
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>data也可以是一個函數</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!-- 容器 --><div id="app"><h1>{{msg}}</h1></div><!-- vue代碼 --><script>const vm = new Vue({el : '#app',// data : {// ? ? msg : 'Hello Vue!'// }// data functions should return an object:data函數應該返回一個對象。// data 也可以是一個函數。// 如果是函數的話,必須使用return語句返回{}對象。// data可以是直接的對象,也可以是一個函數,什么時候使用直接的對象?什么時候使用函數呢?(等你學到組件的時候自然就明白了。)// data : function(){// ? ? return {// ? ? ? ? msg : 'Hello Vue!'// ? ? }// }// 在對象當中,函數的 :function 可以省略data(){return {msg : 'Hello Zhangsan!'}}})// 關于配置項:enumerable、configurablelet phone = {name : '蘋果X'}// 給phone對象新增一個color屬性Object.defineProperty(phone, 'color', {value : '奶奶灰',// true表示該屬性是可以遍歷的。(可枚舉的,可迭代的。)// false表示該屬性是不可遍歷的。enumerable : false,// true表示該屬性是可以被刪除的。// false表示該屬性是不可以被刪除的。configurable : false})</script></body></html>

2.2 事件處理

2.2.1 事件處理的核心語法

(1) 指令的語法格式:<標簽 v-指令名:參數=”表達式”></標簽>

(2) 事件綁定的語法格式:v-on:事件名。例如鼠標單擊事件的綁定使用v-on:click。
(3) 綁定的回調函數需要在Vue實例中使用methods進行注冊。methods可以配置多個回調函數,采用逗號隔開。
(4) 綁定回調函數時,如果回調函數沒有參數,( )可以省略。
(5) 每一個回調函數都可以接收一個事件對象event。
(6) 如果回調函數有參數,并且還需要獲取事件對象,可以使用$event進行占位。
(7) v-on:click可以簡寫為@click。簡寫的語法格式:@事件名

(8) 回調函數中的this是vm。如果回調函數是箭頭函數的話,this是window對象,因為箭頭函數沒有自己的this,它的this是繼承過來的,默認這個this是箭頭函數所在的宿主對象。這個宿主對象其實就是它的父級作用域。而對象又不能構成單獨的作用域,所以這個父級作用域是全局作用域,也就是window。
(9) 回調函數并沒有在vm對象上,為什么通過vm可以直接調用函數呢?嘗試手寫Vue框架。
(10) 可以在函數中改變data中的數據,例如:this.counter++,這樣會聯動頁面上產生動態效果。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue的事件綁定</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!--Vue事件處理:1.指令的語法格式:<標簽 v-指令名:參數名="表達式">{{插值語法}}</標簽>“表達式”位置都可以寫什么?常量、JS表達式、Vue實例所管理的XXX2. 在Vue當中完成事件綁定需要哪個指令呢?v-on指令。語法格式:v-on:事件名="表達式"例如:v-on:click="表達式" 表示當發生鼠標單擊事件之后,執行表達式。v-on:keydown="表達式" 表示當發生鍵盤按下事件之后,執行表達式。3. 在Vue當中,所有事件所關聯的回調函數,需要在Vue實例的配置項methods中進行定義。methods是一個對象:{}在這個methods對象中可以定義多個回調函數。4. v-on指令也有簡寫形式v-on:click 簡寫為 @clickv-on:keydown 簡寫為 @keydownv-on:mouseover 簡寫為 @mouseover....5. 綁定的回調函數,如果函數調用時不需要傳遞任何參數,小括號()可以省略。6. Vue在調用回調函數的時候,會自動給回調函數傳遞一個對象,這個對象是:當前發生的事件對象,并且這個時候是不能帶小括號的,否則event將不會被識別。7. 在綁定回調函數的時候,可以在回調函數的參數上使用 $event 占位符,Vue框架看到這個 $event 占位符之后,會自動將當前事件以對象的形式傳過去。--><!-- 容器 --><div id="app"><h1>{{msg}}</h1><!-- 使用javascript原生代碼如何完成事件綁定。 --><button onclick="alert('hello')">hello</button><!-- 使用Vue來完成事件綁定 --><!-- 以下是錯誤的,因為alert()并沒有被Vue實例管理。 --><!-- <button v-on:click="alert('hello')">hello</button> --><!-- 以下是錯誤的,因為sayHello()并沒有被Vue實例管理。 --><!-- <button v-on:click="sayHello()">hello</button> --><!-- 正確的寫法 --><button v-on:click="sayHello()">hello</button><!-- v-on指令的簡寫形式 --><button @click="sayHi()">hi button</button><!-- <button @click="sayHi($event, 'jack')">hi button2</button> --><!-- 綁定的回調函數,如果不需要傳任何參數,小括號() 可以省略 --><button @click="sayWhat">what button</button></div><!-- vue代碼 --><script>// 自定義一個函數// function sayHello(){// ? ? alert('hello')// }const vm = new Vue({el : '#app',data : {msg : 'Vue的事件綁定'},methods : {// 回調函數// sayHello : function(){// ? ? alert('hello')// }// : function 可以省略sayHello(){alert('hello2')},sayHi(event, name){console.log(name, event)//alert("hi " + name)},sayWhat(event){//console.log(event)//console.log(event.target)//console.log(event.target.innerText)//alert('what...')}}})</script></body></html>

#### 事件處理總結

Vue事件處理:

? ? ? ? ? ? 1.指令的語法格式:

? ? ? ? ? ? ? ? <標簽 v-指令名:參數名="表達式">{{插值語法}}</標簽>

? ? ? ? ? ? ? ? “表達式”位置都可以寫什么?

? ? ? ? ? ? ? ? ? ? 常量、JS表達式、Vue實例所管理的XXX

? ? ? ? ? ? 2. 在Vue當中完成事件綁定需要哪個指令呢?

? ? ? ? ? ? ? ? v-on指令。

? ? ? ? ? ? ? ? 語法格式:

? ? ? ? ? ? ? ? ? ? v-on:事件名="表達式"

? ? ? ? ? ? ? ? 例如:

? ? ? ? ? ? ? ? ? ? v-on:click="表達式" 表示當發生鼠標單擊事件之后,執行表達式。

? ? ? ? ? ? ? ? ? ? v-on:keydown="表達式" 表示當發生鍵盤按下事件之后,執行表達式。

? ? ? ? ? ? 3. 在Vue當中,所有事件所關聯的回調函數,需要在Vue實例的配置項methods中進行定義。

? ? ? ? ? ? ? ? methods是一個對象:{}

? ? ? ? ? ? ? ? 在這個methods對象中可以定義多個回調函數。

? ? ? ? ? ? 4. v-on指令也有簡寫形式

? ? ? ? ? ? ? ? v-on:click 簡寫為 @click

? ? ? ? ? ? ? ? v-on:keydown 簡寫為 @keydown

? ? ? ? ? ? ? ? v-on:mouseover 簡寫為 @mouseover

? ? ? ? ? ? ? ? ....

? ? ? ? ? ? 5. 綁定的回調函數,如果函數調用時不需要傳遞任何參數,小括號()可以省略。

? ? ? ? ? ? 6. Vue在調用回調函數的時候,會自動給回調函數傳遞一個對象,這個對象是:當前發生的事件對象,并且這個時候是不能帶小括號的,否則event將不會被識別。

? ? ? ? ? ? 7. 在綁定回調函數的時候,可以在回調函數的參數上使用 event 占位符,Vue框架看到這個 event 占位符之后,會自動將當前事件以對象的形式傳過去。
還有一點:通過methods注冊的函數,每一個函數同時也會作為Vue實例的屬性,也就是說這些函數也可以通過vm來直接訪問:

const vm = new Vue({el : '#app',methods : {doSome(){alert('hello vue!')}}
})// 可以直接通過Vue實例來訪問doSome()方法
vm.doSome()

#### 關于事件回調函數中的this

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>關于事件回調函數中的this</title><!-- 安裝Vue --><script src="../js/vue.js"></script></head><body><!-- 容器 --><div id="app"><h1>{{msg}}</h1><h1>計數器:{{counter}}</h1><button @click="counter++">點擊我加1</button><button @click="add">點擊我加1</button><button @click="add2">點擊我加1(箭頭函數)</button></div><!-- vue代碼 --><script>const vm = new Vue({el : '#app',data : {msg : '關于事件回調函數中的this',counter : 0},// 1.methods對象中的方法可以通過vm去訪問嗎?可以。// 2.methods對象中的方法有沒有做數據代理呢?沒有。methods : {add(){//counter++; // 錯誤的。// 在這里需要操作counter變量?怎么辦?//console.log(vm === this)//console.log(this)this.counter++;//vm.counter++;},add2:()=>{//this.counter++;//console.log(this === vm)//箭頭函數中沒有this,箭頭函數中的this是從父級作用域當中繼承過來的。//對于當前程序來說,父級作用域是全局作用域:windowconsole.log(this)},sayHi(){alert('hi...')}}})</script></body></html>

2.2.2 事件修飾符

學習代碼

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>事件修飾符</title><!-- 安裝Vue --><script src="../js/vue.js"></script><style>.divList{width: 300px;height: 200px;background-color: aquamarine;overflow: auto;}.item{width: 300px;height: 200px;}</style></head><body><!--Vue當中提供的事件修飾符:.stop : 停止事件冒泡,等同于 event.stopPropagation()。.prevent : 等同于 event.preventDefault() 阻止事件的默認行為。.capture :添加事件監聽器時使用事件捕獲模式添加事件監聽器包括兩種不同的方式:一種是從內到外添加。(事件冒泡模式)一種是從外到內添加。(事件捕獲模式).self :這個事件如果是“我自己元素”上發生的事件,這個事件不是別人給我傳遞過來的事件,則執行對應的程序。.once : 事件只發生一次.passive :passive翻譯為順從/不抵抗。無需等待,直接繼續(立即)執行事件的默認行為。.passive 和 .prevent 修飾符是對立的。不可以共存。(如果一起用,就會報錯。).prevent:阻止事件的默認行為。.passive:解除阻止。--> ? ? ? ?<!-- 容器 --><div id="app"><h1>{{msg}}</h1><!-- 阻止事件的默認行為 --><a href="https://www.baidu.com" @click.prevent="yi">百度</a> <br><br><!-- 停止事件冒泡 --><div @click="san"><div @click.stop="er"><button @click="yi">事件冒泡</button></div></div><br><br><!-- 添加事件監聽器時使用事件捕獲模式 --><div @click.capture="san"><!-- 這里沒有添加.capture修飾符,以下這個元素,以及這個元素的子元素,都會默認采用冒泡模式。 --><div @click="er"><button @click="yi">添加事件監聽器的時候采用事件捕獲模式</button></div></div><br><br><!-- .self修飾符 --><div @click="san"><div @click.self="er"><button @click="yi">self修飾符</button></div></div><br><br><!-- 在Vue當中,事件修飾符是可以多個聯合使用的。但是需要注意:@click.self.stop:先.self,再.stop@click.stop.self:先.stop,再.self--><div @click="san"><div @click="er"><button @click.self.stop="yi">self修飾符</button></div></div><br><br><!-- .once修飾符:事件只發生一次 --><button @click.once="yi">事件只發生一次</button><!-- .passive修飾符 --><div class="divList" @wheel.passive="testPassive"><div class="item">div1</div><div class="item">div2</div><div class="item">div3</div></div></div><!-- vue代碼 --><script>const vm = new Vue({el : '#app',data : {msg : '事件修飾符'},methods : {yi(event){//alert('去百度!!!!!!')// 手動調用事件對象的preventDefault()方法,可以阻止事件的默認行為。// 在Vue當中,這種事件的默認行為可以不采用手動調用DOM的方式來完成,可以使用事件修飾符:prevent。//event.preventDefault();alert(1)},er(){alert(2)},san(){alert(3)},testPassive(event){for(let i = 0; i < 100000; i++){console.log('test passive')}// 阻止事件的默認行為//event.preventDefault()}}})</script></body></html>
事件修飾符代碼總結:

Vue當中提供的事件修飾符:

? ? ? ? .stop : 停止事件冒泡,等同于 event.stopPropagation()。

? ? ? ? .prevent : 等同于 event.preventDefault() 阻止事件的默認行為。

? ? ? ? .capture :添加事件監聽器時使用事件捕獲模式

? ? ? ? ? ? ? ? ? ? 添加事件監聽器包括兩種不同的方式:

? ? ? ? ? ? ? ? ? ? ? ? 一種是從內到外添加。(事件冒泡模式)

? ? ? ? ? ? ? ? ? ? ? ? 一種是從外到內添加。(事件捕獲模式)

? ? ? ? .self :這個事件如果是“我自己元素”上發生的事件,這個事件不是別人給我傳遞過來的事件,則執行對應的程序。

? ? ? ? .once : 事件只發生一次

? ? ? ? .passive :passive翻譯為順從/不抵抗。無需等待,直接繼續(立即)執行事件的默認行為。

? ? ? ? ? ? ? ? ? ? .passive 和 .prevent 修飾符是對立的。不可以共存。(如果一起用,就會報錯。)

? ? ? ? ? ? ? ? ? ? .prevent:阻止事件的默認行為。

? ? ? ? ? ? ? ? ? ? .passive:解除阻止。

2.2.3 按鍵修飾符

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>按鍵修飾符</title><script src="../js/vue.js"></script></head><body><!--9個比較常用的按鍵修飾符:.enter.tab (必須配合keydown事件使用。).delete (捕獲“刪除”和“退格”鍵).esc.space.up.down.left.right怎么獲取某個鍵的按鍵修飾符?第一步:通過event.key獲取這個鍵的真實名字。第二步:將這個真實名字以kebab-case風格進行命名。PageDown是真實名字。經過命名之后:page-down按鍵修飾符是可以自定義的?通過Vue的全局配置對象config來進行按鍵修飾符的自定義。語法規則:Vue.config.keyCodes.按鍵修飾符的名字 = 鍵值系統修飾鍵:4個比較特殊的鍵ctrl、alt、shift、meta對于keydown事件來說:只要按下ctrl鍵,keydown事件就會觸發。對于keyup事件來說:需要按下ctrl鍵,并且加上按下組合鍵,然后松開組合鍵之后,keyup事件才能觸發。--><div id="app"><h1>{{msg}}</h1>回車鍵:<input type="text" @keyup.enter="getInfo"><br>回車鍵(鍵值):<input type="text" @keyup.13="getInfo"><br>delete鍵:<input type="text" @keyup.delete="getInfo"><br>esc鍵:<input type="text" @keyup.esc="getInfo"><br>space鍵:<input type="text" @keyup.space="getInfo"><br>up鍵:<input type="text" @keyup.up="getInfo"><br>down鍵:<input type="text" @keyup.down="getInfo"><br>left鍵:<input type="text" @keyup.left="getInfo"><br>right鍵:<input type="text" @keyup.right="getInfo"><br><!-- tab鍵無法觸發keyup事件。只能觸發keydown事件。 -->tab鍵: <input type="text" @keyup.tab="getInfo"><br>tab鍵(keydown): <input type="text" @keydown.tab="getInfo"><br>PageDown鍵: <input type="text" @keyup.page-down="getInfo"><br>huiche鍵: <input type="text" @keyup.huiche="getInfo"><br>ctrl鍵(keydown): <input type="text" @keydown.ctrl="getInfo"><br>ctrl鍵(keyup): <input type="text" @keyup.ctrl="getInfo"><br>ctrl鍵(keyup): <input type="text" @keyup.ctrl.i="getInfo"><br></div><script>// 自定義了一個按鍵修飾符:.huiche 。代表回車鍵。Vue.config.keyCodes.huiche = 13const vm = new Vue({el : '#app',data : {msg : '按鍵修飾符'},methods : {getInfo(event){// 當用戶鍵入回車鍵的時候,獲取用戶輸入的信息。//if(event.keyCode === 13){console.log(event.target.value)//}console.log(event.key)}}})</script></body></html>
按鍵修飾符總結

9個比較常用的按鍵修飾符:

? ? ? ? ? ? .enter

? ? ? ? ? ? .tab (必須配合keydown事件使用。)

? ? ? ? ? ? .delete (捕獲“刪除”和“退格”鍵)

? ? ? ? ? ? .esc

? ? ? ? ? ? .space

? ? ? ? ? ? .up

? ? ? ? ? ? .down

? ? ? ? ? ? .left

? ? ? ? ? ? .right

? ? ? ? 怎么獲取某個鍵的按鍵修飾符?

? ? ? ? ? ? 第一步:通過event.key獲取這個鍵的真實名字。

? ? ? ? ? ? 第二步:將這個真實名字以kebab-case風格進行命名。

? ? ? ? ? ? ? ? PageDown是真實名字。經過命名之后:page-down

? ? ? ? 按鍵修飾符是可以自定義的?

? ? ? ? ? ? 通過Vue的全局配置對象config來進行按鍵修飾符的自定義。

? ? ? ? ? ? 語法規則:

? ? ? ? ? ? ? ? Vue.config.keyCodes.按鍵修飾符的名字 = 鍵值

? ? ? ? 系統修飾鍵:4個比較特殊的鍵

? ? ? ? ? ? ctrl、alt、shift、meta

? ? ? ? ? ? 對于keydown事件來說:只要按下ctrl鍵,keydown事件就會觸發。

? ? ? ? ? ? 對于keyup事件來說:需要按下ctrl鍵,并且加上按下組合鍵,然后松開組合鍵之后,keyup事件才能觸發。

2.3 計算屬性

1. 案例:用戶輸入信息,然后翻轉用戶輸入的字符串。

(1) 插值語法可以實現,但是有三個問題
① 代碼可讀性差
② 代碼不可復用
③ 代碼難以維護

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>反轉字符串</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1>輸入的信息:<input type="text" v-model="info"> <br><!--三個問題:1. 可讀性差。2. 代碼沒有得到復用。3. 難以維護。-->反轉的信息:{{info.split('').reverse().join('')}} <br>反轉的信息:{{info.split('').reverse().join('')}} <br>反轉的信息:{{info.split('').reverse().join('')}} <br>反轉的信息:{{info.split('').reverse().join('')}} <br>反轉的信息:{{info.split('').reverse().join('')}} <br></div><script>const vm = new Vue({el : '#app',data : {msg : '計算屬性-反轉字符串案例',info : ''}})</script></body></html>

(2) 可以使用methods方式實現,存在1個問題
① 效率低,即使數據沒有發生變化,但每一次調用方法都會調用method一次。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>反轉字符串methods實現</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1>輸入的信息:<input type="text" v-model="info"> <br><!-- 在插值語法中可以調用方法,小括號不能省略。這個方法需要是Vue實例所管理的。 -->反轉的信息:{{reverseInfo()}} <br>反轉的信息:{{reverseInfo()}} <br>反轉的信息:{{reverseInfo()}} <br>反轉的信息:{{reverseInfo()}} <br></div><script>const vm = new Vue({el : '#app',data : {msg : '計算屬性-反轉字符串案例',info : ''},methods : {// 反轉信息的方法reverseInfo(){console.log('@')return this.info.split('').reverse().join('');}}})</script></body></html>
js知識之-join()方法的使用
語法:

array.join([separator])

  • separator(可選):指定連接數組元素的分隔符,默認是?,(逗號)。
  • 返回值:返回連接后的字符串。
示例:
1. 默認(不傳參數,使用逗號?,?連接)
const arr = ['a', 'b', 'c'];
const str = arr.join();
console.log(str); // 輸出: "a,b,c"
2. 使用空字符串?''(無分隔符,直接拼接)
const arr = ['2', '2', '2', '2'];
const str = arr.join('');
console.log(str); // 輸出: "2222"
3. 使用自定義分隔符
const arr = ['2023', '10', '15'];
const str1 = arr.join('-'); // "2023-10-15"
const str2 = arr.join('/'); // "2023/10/15"
console.log(str1, str2);
4. 處理包含非字符串元素(會自動調用?toString()?轉換)
const arr = [1, true, null, { name: 'Tom' }];
const str = arr.join(' | ');
console.log(str); // 輸出: "1 | true |  | [object Object]"
js知識之-split()方法的使用
split()?方法語法
str.split([separator[, limit]])
參數說明

參數

說明

separator(可選)

指定拆分字符串的分隔符,可以是字符串正則表達式
如果省略或傳入?undefined,整個字符串會作為數組的唯一元素。
如果傳入?''(空字符串),則每個字符都會被拆分成數組元素。

limit(可選)

限制返回數組的最大長度(超出部分會被丟棄)。

返回值

返回一個新數組,包含拆分后的子字符串。


split()?的常見用法
1. 按字符拆分(split('')

將字符串拆分成單個字符的數組

"hello".split(''); 
// 輸出: ['h', 'e', 'l', 'l', 'o']
2. 按單詞拆分(split(' ')

空格拆分字符串(適用于句子分詞):

"JavaScript is fun".split(' '); 
// 輸出: ['JavaScript', 'is', 'fun']
3. 按特定符號拆分(如逗號?,

常用于處理?CSV 數據

"apple,banana,orange".split(','); 
// 輸出: ['apple', 'banana', 'orange']

4. 限制拆分數量(split(separator, limit)

只拆分前?n?個匹配項:

"a-b-c-d-e".split('-', 3); 
// 輸出: ['a', 'b', 'c'](只取前 3 個)
5. 使用正則表達式拆分

更靈活的拆分方式(如按多個分隔符拆分):
``js
"2023/10-15".split(/[\/-]/);
// 輸出: ['2023', '10', '15'](同時匹配 `/` 和 `-`)
``

特殊情況的處理
1. 不傳參數(split()

直接返回包含整個字符串的數組:

"hello".split(); 
// 輸出: ['hello']
2. 分隔符不存在于字符串中

返回包含整個字符串的數組:

"hello".split('x'); 
// 輸出: ['hello']
3. 空字符串?split('')

每個字符單獨拆分成數組元素:

"123".split(''); 
// 輸出: ['1', '2', '3']
4. 開頭或結尾有分隔符

會生成空字符串元素:

",a,b,".split(','); 
// 輸出: ['', 'a', 'b', '']

(3) 使用計算屬性可以解決以上問題。

2. 什么是計算屬性?

data中的是屬性。用data的屬性經過計算得出的全新的屬性就是計算屬性。
注意了:計算屬性是全新的屬性

3. 計算屬性的使用

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>反轉字符串計算屬性實現</title><script src="../../js/vue.js"></script></head><body><!--計算屬性:1. 什么是計算屬性?使用Vue的原有屬性,經過一系列的運算/計算,最終得到了一個全新的屬性,叫做計算屬性。Vue的原有屬性: data對象當中的屬性可以叫做Vue的原有屬性。全新的屬性: 表示生成了一個新的屬性,和data中的屬性無關了,新的屬性也有自己的屬性名和屬性值。2. 計算屬性怎么用?語法格式:需要一個新的配置項 computedcomputed : {// 這是一個計算屬性計算屬性1 : {// setter 和 getter方法。// 當讀取計算屬性1的值的時候,getter方法被自動調用。get(){},// 當修改計算屬性1的值的時候,setter方法被自動調用。set(val){}},// 這是另一個計算屬性計算屬性2 : {},}3. 計算屬性的作用?代碼得到了復用。代碼更加便于維護了。代碼的執行效率高了。--><div id="app"><h1>{{msg}}</h1>輸入的信息:<input type="text" v-model="info"> <br>反轉的信息:{{reversedInfo}}<br>反轉的信息:{{reversedInfo}}<br>反轉的信息:{{reversedInfo}}<br>反轉的信息:{{reversedInfo}}<br>反轉的信息:{{reversedInfo}}<br>{{hehe}} <br>{{hehe}} <br>{{hehe}} <br>{{hehe}} <br>{{hehe}} <br>{{hello()}} <br>{{hello()}} <br>{{hello()}} <br>{{hello()}} <br>{{hello()}} <br></div><script>const vm = new Vue({el : '#app',data : {msg : '計算屬性-反轉字符串案例',info : ''},methods : {hello(){console.log('hello方法執行了')return 'hello'}},computed : {// 可以定義多個計算屬性hehe : {// get方法的調用時機包括兩個// 第一個時機:第一次訪問這個屬性的時候。// 第二個時機:該計算屬性所關聯的Vue原有屬性的值發生變化時,getter方法會被重新調用一次。get(){console.log('getter方法調用了')//console.log(this === vm)return 'haha' + this.info},// 不能使用箭頭函數,使用箭頭函數會導致this的指向是:window// get:()=>{// ? ? console.log('getter方法調用了')// ? ? console.log(this === vm)// ? ? return 'haha'// },set(val){console.log('setter方法調用了')//console.log(this === vm)}},// 完整寫法/* reversedInfo : {get(){return this.info.split('').reverse().join('')},// 當修改計算屬性的時候,set方法被自動調用。set(val){//console.log('setter方法被調用了。')// 不能這么做,這樣做就遞歸了。//this.reversedInfo = val// 怎么修改計算屬性呢?原理:計算屬性的值變還是不變,取決于計算屬性關聯的Vue原始屬性的值。// 也就是說:reversedInfo變還是不變,取決于info屬性的值變不變。// 本質上:修改計算屬性,實際上就是通過修改Vue的原始屬性來實現的。this.info = val.split('').reverse().join('')}} */// 簡寫形式:set不需要的時候。reversedInfo(){return this.info.split('').reverse().join('')}}})</script></body></html>

(1) 計算屬性需要使用:computed
(2) 計算屬性通過vm.data 是無法訪問的。計算屬性不能通過vm.data訪問。
(3) 計算屬性的getter/setter方法中的this是vm。
(4) 計算屬性的getter方法的調用時機:
① 第一個時機:初次訪問該屬性。

        <font color="#ff0000">	②	第二個時機:計算屬性所依賴的數據發生變化時。</font>

(5) 計算屬性的setter方法的調用時機:
① 當計算屬性被修改時。(在setter方法中通常是修改屬性,因為只有當屬性值變化時,計算屬性的值就會聯動更新。注意:計算屬性的值被修改并不會聯動更新屬性的值。)
(6) 計算屬性沒有真正的值,每一次都是依賴data屬性計算出來的
(7) 計算屬性的getter和setter方法不能使用箭頭函數,因為箭頭函數的this不是vm。而是window。
4. 計算屬性的簡寫形式
只考慮讀取,不考慮修改時,可以啟用計算屬性的簡寫形式。

2.4 偵聽屬性的變化

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>偵聽/監視 屬性的變化</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1>數字:<input type="text" v-model="number"><br>數字:<input type="text" v-model="a.b"><br>數字:<input type="text" v-model="a.c"><br>數字:<input type="text" v-model="a.d.e.f"><br>數字(后期添加監視):<input type="text" v-model="number2"><br></div><script>const vm = new Vue({el : '#app',data : {number2 : 0,msg : '偵聽屬性的變化',number : 0,// a屬性中保存的值是一個對象的內存地址。// a = 0x2356a : {b : 0,c : 0,d : {e : {f : 0}}}},computed : {hehe(){return 'haha' + this.number}},watch : {// 可以監視多個屬性// 監視哪個屬性,請把這個屬性的名字拿過來即可。// 可以監視Vue的原有屬性/* number : {// 初始化的時候,調用一次handler方法。immediate : true,// 這里有一個固定寫死的方法,方法名必須叫做:handler// handler方法什么時候被調用呢?當被監視的屬性發生變化的時候,handler就會自動調用一次。// handler方法上有兩個參數:第一個參數newValue,第二個參數是oldValue// newValue是屬性值改變之后的新值。// oldValue是屬性值改變之前的舊值。handler(newValue, oldValue){console.log(newValue, oldValue)// this是當前的Vue實例。// 如果該函數是箭頭函數,這個this是window對象。不建議使用箭頭函數。console.log(this)}}, */// 無法監視b屬性,因為b屬性壓根不存在。/* b : { ?handler(newValue, oldValue){console.log('@')}} */// 如果監視的屬性具有多級結構,一定要添加單引號:'a.b'/* 'a.b' : { ?handler(newValue, oldValue){console.log('@')}},'a.c' : { ?handler(newValue, oldValue){console.log('@')}}, */a : {// 啟用深度監視,默認是不開啟深度監視的。// 什么時候開啟深度監視:當你需要監視一個具有多級結構的屬性,并且監視所有的屬性,需要啟用深度監視。deep : true, ?handler(newValue, oldValue){console.log('@')}},// 注意:監視某個屬性的時候,也有簡寫形式,什么時候啟用簡寫形式?// 當只有handler回調函數的時候,可以使用簡寫形式。number(newValue, oldValue){console.log(newValue, oldValue)}// 也可以監視計算屬性/* hehe : {handler(a , b){console.log(a, b)}} */}})// 如何后期添加監視?調用Vue相關的API即可。// 語法:vm.$watch('被監視的屬性名', {})/* vm.$watch('number2', {immediate : true,deep : true,handler(newValue, oldValue){console.log(newValue, oldValue)}}) */// 這是后期添加監視的簡寫形式。vm.$watch('number2', function(newValue, oldValue){console.log(newValue, oldValue)})</script></body></html>

1. 偵聽屬性的變化其實就是監視某個屬性的變化。當被監視的屬性一旦發生改變時,執行某段代碼。

2. 監視屬性變化時需要使用watch配置項。

使用watch實現:比較數字大小的案例

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1>數值1:<input type="text" v-model="number1"><br>數值2:<input type="text" v-model="number2"><br>比較大小:{{compareResult}}</div><script>const vm = new Vue({el: '#app',data: {msg: '偵聽屬性的變化',number1: 1,number2: 1,compareResult: ''},watch: {number1: {immediate: true,handler(newVal, oldVal) {let result = newVal - this.number2if (result > 0) {this.compareResult = newVal + '>' + this.number2} else if (result < 0) {this.compareResult = newVal + '<' + this.number2} else {this.compareResult = newVal + '=' + this.number2}}},number2: {immediate: true,handler(newVal, oldVal) {let result = this.number1 - newValif (result > 0) {this.compareResult = this.number1 + '>' + newVal} else if (result < 0) {this.compareResult = this.number1 + '<' + newVal} else {this.compareResult = this.number1 + '=' + newVal}}}}}) ?</script></body></html>

運行效果:
?


3. 如何深度監視:

(1) 監視多級結構中某個屬性的變化,寫法是:’a.b.c’ : {}。注意單引號哦。
(2) 監視多級結構中所有屬性的變化,可以通過添加深度監視來完成:deep : true
4. 如何后期添加監視:

(1) 調用API:vm.$watch(‘number1’, {})
5. watch的簡寫:

(1) 簡寫的前提:當不需要配置immediate和deep時,可以簡寫。
(2) 如何簡寫?
① watch:{ number1(newVal,oldVal){}, number2(newVal, oldVal){} }
(3) 后期添加的監視如何簡寫?
① vm.$watch(‘number1’, function(newVal, oldVal){})
6. computed和watch如何選擇?

(1) 以上比較大小的案例可以用computed完成,并且比watch還要簡單。所以要遵守一個原則:computed和watch都能夠完成的,優先選擇computed。
(2) 如果要開啟異步任務,只能選擇watch。因為computed依靠return。watch不需要依賴return。
7. 關于函數的寫法,寫普通函數還是箭頭函數?

(1) 不管寫普通函數還是箭頭函數,目標是一致的,都是為了讓this和vm相等。
(2) 所有Vue管理的函數,建議寫成普通函數。
(3) 所有不屬于Vue管理的函數,例如setTimeout的回調函數、Promise的回調函數、AJAX的回調函數,建議使用箭頭函數。

2.5 class與style綁定

數據綁定的一個常見需求場景是操縱元素的 CSS class 列表和內聯樣式。因為 class 和 style 都是 attribute,我們可以和其他 attribute 一樣使用 v-bind 將它們和動態的字符串綁定。但是,在處理比較復雜的綁定時,通過拼接生成字符串是麻煩且易出錯的。因此,Vue 專門為 class 和 style 的 v-bind 用法提供了特殊的功能增強。除了字符串外,表達式的值也可以是對象或數組。

2.4.1 class綁定
2.4.1.1 綁定字符串

適用于樣式的名字不確定,需要動態指定。
適用場景:如果確定動態綁定的樣式個數只有1個,但是名字不確定

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Class綁定之字符串形式</title><script src="../../js/vue.js"></script><style>.static{border: 1px solid black;background-color: aquamarine;}.big{width: 200px;height: 200px;}.small{width: 100px;height: 100px;}</style></head><body><div id="app"><h1>{{msg}}</h1><!-- 靜態寫法 --><div class="static small">{{msg}}</div><br><br><button @click="changeBig">變大</button><button @click="changeSmall">變小</button><!-- 動態寫法:動靜都有 --><!-- 適用場景:如果確定動態綁定的樣式個數只有1個,但是名字不確定。 --><div class="static" :class="c1">{{msg}}</div></div><script>const vm = new Vue({el : '#app',data : {msg : 'Class綁定之字符串形式',c1 : 'small'},methods: {changeBig(){this.c1 = 'big'},changeSmall(){this.c1 = 'small'}},})</script></body></html>

運行效果:
?


通過測試可以看到樣式完成了動態的切換。

2.4.1.2 綁定數組

適用于綁定的樣式名字不確定,并且個數也不確定。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Class綁定之數組形式</title><script src="../../js/vue.js"></script><style>.static {border: 1px solid black;width: 100px;height: 100px;}.active {background-color: green;}.text-danger {color: red;}</style></head><body><div id="app"><h1>{{msg}}</h1><!-- 靜態寫法 --><div class="static active text-danger">{{msg}}</div><br><!-- 動態寫法:動靜結合 --><div class="static" :class="['active','text-danger']">{{msg}}</div><br><div class="static" :class="[c1, c2]">{{msg}}</div><br><!-- 適用場景:當樣式的個數不確定,并且樣式的名字也不確定的時候,可以采用數組形式。 --><div class="static" :class="classArray">{{msg}}</div></div><script>const vm = new Vue({el : '#app',data : {msg : 'Class綁定之數組形式',c1 : 'active',c2 : 'text-danger',classArray : ['active', 'text-danger']}})</script></body></html>

運行效果:

2.4.1.3 綁定對象

適用于樣式名字和個數都確定,但是要動態決定用或者不用。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Class綁定之對象形式</title><script src="../../js/vue.js"></script><style>.static {border: 1px solid black;width: 100px;height: 100px;}.active {background-color: green;}.text-danger {color: red;}</style></head><body><div id="app"><h1>{{msg}}</h1><!-- 動態寫法:動靜結合 --><!-- 對象形式的適用場景:樣式的個數是固定的,樣式的名字也是固定的,但是需要動態的決定樣式用還是不用。 --><div class="static" :class="classObj">{{msg}}</div><br><div class="static" :class="{active:true,'text-danger':false}">{{msg}}</div></div><script>const vm = new Vue({el : '#app',data : {msg : 'Class綁定之對象形式',classObj : {// 該對象中屬性的名字必須和樣式名一致。active : false,'text-danger' : true}}})</script></body></html>

運行效果:
?


#### 2.4.2 style綁定

代碼學習:注意數組綁定和對象綁定都是以對象的形式寫的, 數組里面寫對象格式

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Style綁定</title><script src="../js/vue.js"></script><style>.static {border: 1px solid black;width: 100px;height: 100px;}</style></head><body><div id="app"><h1>{{msg}}</h1><!-- 靜態寫法 --><div class="static" style="background-color: green;">{{msg}}</div><br><!-- 動態寫法:字符串形式 --><div class="static" :style="myStyle">{{msg}}</div><br><!-- 動態寫法:對象形式 --><div class="static" :style="{backgroundColor: 'gray'}">{{msg}}</div><br><div class="static" :style="styleObj1">{{msg}}</div><br><!-- 動態寫法:數組形式 --><div class="static" :style="styleArray">{{msg}}</div></div><script>const vm = new Vue({el : '#app',data : {msg : 'Style綁定',myStyle : 'background-color: gray;',styleObj1 : {backgroundColor: 'green'},// 數組形式的話里面也必須是對象,這里的格式寫法一定要注意styleArray : [{backgroundColor: 'green'},{color : 'red'}]}})</script></body></html>

2.5 條件渲染

2.5.1 v-if

指令用于條件性地渲染一塊內容。這塊內容只會在指令的表達式返回true時才被渲染

<div id="app">  <h1>{{msg}}</h1>  溫度:<input type="number" v-model="temprature"><br>  天氣:  <span v-if="temprature <= 10">寒冷</span>  <span v-if="temprature > 10 && temprature <= 25">涼爽</span>  <span v-if="temprature > 25">炎熱</span>  
</div>  
<script>  const vm = new Vue({  el : '#app',  data : {  msg : '條件渲染',  temprature : 10  }  })  
</script> 

運行效果:

2.5.2 v-else-if、v-else

顧名思義,v-else-if 提供的是相應于 v-if 的“else if 區塊”。它可以連續多次重復使用。
一個使用 v-else-if 的元素必須緊跟在一個 v-if 或一個 v-else-if元素后面
你也可以使用 v-else 為 v-if 添加一個“else 區塊”,當然,v-else元素也是必須緊跟在一個 v-if 或一個 v-else-if元素后面。

    <div id="app">  <h1>{{msg}}</h1>  溫度:<input type="number" v-model="temprature"><br>  天氣:  <span v-if="temprature <= 10">寒冷</span>  <span v-else-if="temprature <= 25">涼爽</span>  <span v-else>炎熱</span>  </div>  <script>  const vm = new Vue({  el : '#app',  data : {  msg : '條件渲染',  temprature : 10  }  })  </script>
2.5.3 template與v-if

因為 v-if 是一個指令,他必須依附于某個元素。但如果我們想要切換不止一個元素呢?在這種情況下我們可以在一個 <template> 元素上使用 v-if,這只是一個不可見的包裝器元素,最后渲染的結果并不會包含個 <template> 元素。v-else 和 v-else-if 也可以在 <template>上使用。

<div id="app">  <h1>{{msg}}</h1>  溫度:<input type="number" v-model="temprature"><br>  天氣:  <template v-if="temprature <= 10">  <span>寒冷</span>  </template>  <template v-else-if="temprature <= 25">  <span>涼爽</span>  </template>  <template v-else>  <span>炎熱</span>  </template>  </div>  <script>  const vm = new Vue({  el : '#app',  data : {  msg : '條件渲染',  temprature : 10  }  })  </script>```#####  <font color="#245bdb">2.5.4 v-show</font>另一個可以用來按條件顯示一個元素的指令是 v-show。其用法基本一樣:
?```html
1.	<div id="app">  
2.	    <h1>{{msg}}</h1>  
3.	    溫度:<input type="number" v-model="temprature"><br>  
4.	    天氣:  
5.	    <span v-show="temprature <= 10">寒冷</span>  
6.	    <span v-show="temprature > 10 && temprature <= 25">涼爽</span>  
7.	    <span v-show="temprature > 25">炎熱</span>  
8.	</div>  
9.	<script>  
10.	    const vm = new Vue({  
11.	        el : '#app',  
12.	        data : {  
13.	            msg : '條件渲染',  
14.	            temprature : 10  
15.	        }  
16.	    })  
17.	</script>  

不同之處在于 v-show 會在 DOM 渲染中保留該元素;v-show 僅切換了該元素上名為 display 的 CSS 屬性。

v-show 不支持在 template元素上使用,也不能和 v-else 搭配使用。

2.5.5 v-if VS v-show

v-if 是“真實的”按條件渲染,因為它確保了在切換時,條件區塊內的事件監聽器和子組件都會被銷毀與重建
v-if 也是惰性的:如果在初次渲染時條件值為 false,則不會做任何事。條件區塊只有當條件首次變為 true 時才被渲染。
相比之下,v-show 簡單許多,元素無論初始條件如何,始終會被渲染,只有 CSS display屬性會被切換。
總的來說,v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。因此,如果需要頻繁切換,則使用 v-show 較好;如果在運行時綁定條件很少改變,則 v-if 會更合適。

條件渲染總結

學習代碼:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>條件渲染</title><script src="../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1><!--v-if指令的值:true/falsetrue: 表示該元素會被渲染到頁面上。false: 表示該元素不會被渲染到頁面上。(注意:不是修改了CSS樣式,是這個元素壓根沒有加載)--><div v-if="false">{{msg}}</div><div v-if="2 === 1">{{msg}}</div><button @click="counter++">點我加1</button><h3>{{counter}}</h3><i/mg :src="imgPath1" v-if="counter % 2 === 1"><!-- 提醒:v-if和v-else之間不能斷開。 --><!-- <div></div> --><!-- <i/mg :src="imgPath2" v-if="counter % 2 === 0"> --><!-- 為了提高效率,可以使用v-else指令 --><i/mg :src="imgPath2" v-else><br><br>溫度:<input type="number" v-model="temprature"><br><br><!-- 天氣:<span v-if="temprature <= 10">寒冷</span><span v-if="temprature > 10 && temprature <= 25">涼爽</span><span v-if="temprature > 25">炎熱</span> -->天氣:<span v-if="temprature <= 10">寒冷</span><!-- v-if v-else-if v-else三者在使用的時候,中間不能斷開。 --><!-- <br> --><span v-else-if="temprature <= 25">涼爽</span><span v-else>炎熱</span><br><br><br><!--v-show指令是通過修改元素的CSS樣式的display屬性來達到顯示和隱藏的。v-if和v-show應該如何選擇?1. 如果一個元素在頁面上被頻繁的隱藏和顯示,建議使用v-show,因為此時使用v-if開銷比較大。2. v-if的優點:頁面加載速度快,提高了頁面的渲染效率。--><div v-show="false">你可以看到我嗎?</div><!-- template標簽/元素只是起到占位的作用,不會真正的出現在頁面上,也不會影響頁面的結構。 --><template v-if="counter === 10"><input type="text"><input type="checkbox"><input type="radio"> ? ? ? ? ? ?</template></div><script>const vm = new Vue({el : '#app',data : {msg : '條件渲染',counter : 1,imgPath1 : '../img/1.jpg',imgPath2 : '../img/2.jpg',temprature : 0}})</script></body></html>

v-if指令的值:true/false

? ? ? ? ? ? ? ? true: 表示該元素會被渲染到頁面上。

? ? ? ? ? ? ? ? false: 表示該元素不會被渲染到頁面上。(注意:不是修改了CSS樣式,是這個元素壓根沒有加載)
? ? ? ? ? ? ? ?
v-if v-else-if v-else三者在使用的時候,中間不能斷開。
v-show指令是通過修改元素的CSS樣式的display屬性來達到顯示和隱藏的。

? ? ? ? ? ? v-if和v-show應該如何選擇?

? ? ? ? ? ? ? ? 1. 如果一個元素在頁面上被頻繁的隱藏和顯示,建議使用v-show,因為此時使用v-if開銷比較大。

? ? ? ? ? ? ? ? 2. v-if的優點:頁面加載速度快,提高了頁面的渲染效率。

2.6 列表渲染

語法格式:v-for指令。該指令用在被遍歷的標簽上。
1. v-for="(element, index) in elements" :key="element.id"
或者
1. v-for="(element, index) of elements" :key="element.id"

2.6.1 遍歷數組、對象、字符串、指定次數

代碼演示:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><script src="../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1><h2>遍歷對象的屬性</h2><ul><li v-for="(value, propertyName) of user">{{propertyName}},{{value}}</li></ul><h2>遍歷字符串</h2><ul><li v-for="(c,index) of str">{{index}},{{c}}</li></ul><h2>遍歷指定的次數</h2><ul><li v-for="(num,index) of counter">{{index}}, {{num}}</li></ul><h2>遍歷數組</h2><!-- 靜態列表 --><ul><li>張三</li><li>李四</li><li>王五</li></ul><!-- 動態列表 --><ul><!--1. v-for要寫在循環項上。2. v-for的語法規則:v-for="(變量名,index) in/of 數組"變量名 代表了 數組中的每一個元素--><li v-for="fdsafds in names">{{fdsafds}}</li></ul><ul><li v-for="name of names">{{name}}</li></ul><ul><li v-for="(name,index) of names">{{name}}-{{index}}</li></ul><ul><li v-for="(vip,index) of vips">會員名:{{vip.name}},年齡:{{vip.age}}歲</li></ul><table><tr><th>序號</th><th>會員名</th><th>年齡</th><th>選擇</th></tr><tr v-for="(vip,index) in vips"><td>{{index+1}}</td><td>{{vip.name}}</td><td>{{vip.age}}</td><td><input type="checkbox"></td></tr></table></div><script>const vm = new Vue({el : '#app',data : {msg : '列表渲染',names : ['jack','lucy','james'],vips : [{id:'111',name:'jack',age:20},{id:'222',name:'lucy',age:30},{id:'333',name:'james',age:40}],user : {id : '111',name : '張三',gender : '男'},str : '動力節點',counter : 10}})</script></body></html>

2.6.2 虛擬dom和diff算法

所謂的虛擬dom就是內存當中的dom對象。vue為了提高渲染的效率,只有真正改變的dom元素才會重新渲染。

2.6.3 v-for的key的作用以及實現原理

1. 用index作為key
1.	<!DOCTYPE html>  
2.	<html lang="en">  
3.	<head>  
4.	    <meta charset="UTF-8">  
5.	    <title>key的原理</title>  
6.	    <script src="../js/vue.js"></script>  
7.	</head>  
8.	<body>  
9.	    <div id="app">  
10.	        <h1>{{msg}}</h1>  
11.	        <button @click="addFirst">在數組第一個位置添加tom</button>  
12.	        <button @click="addLast">在數組最后位置添加vue</button>  
13.	        <table>  
14.	            <tr>  
15.	                <th>序號</th>  
16.	                <th>姓名</th>  
17.	                <th>郵箱</th>  
18.	                <th>選擇</th>  
19.	            </tr>  
20.	            <tr v-for="(vip,index) of vips" :key="index">  
21.	                <td>{{index + 1}}</td>  
22.	                <td>{{vip.name}}</td>  
23.	                <td>{{vip.email}}</td>  
24.	                <td><input type="checkbox"></td>  
25.	            </tr>  
26.	        </table>  
27.	    </div>  
28.	    <script>  
29.	        const vm = new Vue({  
30.	            el : '#app',  
31.	            data : {  
32.	                msg : 'key原理(虛擬dom與diff算法)',  
33.	                vips : [  
34.	                    {id:'100',name:'jack',email:'jack@123.com'},  
35.	                    {id:'200',name:'lucy',email:'lucy@123.com'},  
36.	                    {id:'300',name:'james',email:'james@123.com'}  
37.	                ]  
38.	            },  
39.	            methods : {  
40.	                addFirst(){  
41.	                    this.vips.unshift({id:'400',name:'tom',email:'tom@123.com'})  
42.	                },  
43.	                addLast(){  
44.	                    this.vips.push({id:'500',name:'vue',email:'vue@123.com'})  
45.	                }  
46.	            }  
47.	        })  
48.	    </script>  
49.	</body>  
50.	</html> 

可以看到錯亂了。思考這是為什么?

2. 用vip.id作為key

運行和測試結果正常,沒有出現錯亂。為什么?

3. key的作用

key存在于虛擬dom元素中,代表該虛擬dom元素的唯一標識(身份證號)。我們用數據庫中每條數據的id,這個id一般在數據庫中都是唯一的,所以正好適合用來作為key使用。

4. diff算法是如何比較的?

新的虛擬dom和舊的虛擬dom比較時,先拿key進行比較:

(1) 如果key相同:則繼續比較子元素:
① 子元素不同:直接將新的虛擬dom元素渲染到頁面生成新的真實dom元素。
② 子元素相同:直接復用之前的真實dom。
(2) 如果key不同:直接將新的虛擬dom元素渲染到頁面生成新的真實dom元素。

5. index作為key存在兩個問題

(1) 效率較低。
(2) 對數組的非末尾元素進行增刪時,容易錯亂。

6. index作為key和vip.id作為key對比

當index作為key時:

當vip.id作為key時:

2.7 列表過濾

使用watch和computed分別進行實現:

watch實現

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表過濾</title><script src="../js/vue.js"></script><style>th,td{border: 1px solid black;}</style></head><body><div id="app"><h1>{{msg}}</h1><input type="text" placeholder="請輸入搜索關鍵字" v-model="keyword"><table><tr><th>序號</th><th>英雄</th><th>能量值</th><th>選擇</th></tr><tr v-for="(hero,index) in filteredHeros" :key="hero.id"><td>{{index+1}}</td><td>{{hero.name}}</td><td>{{hero.power}}</td><td><input type="checkbox"></td></tr></table></div><script>const vm = new Vue({el : '#app',data : {keyword : '',msg : '列表過濾',heros : [{id:'101',name:'艾格文',power:10000},{id:'102',name:'麥迪文',power:9000},{id:'103',name:'古爾丹',power:8000},{id:'104',name:'薩爾',power:6000}],filteredHeros : []},watch : {/* keyword(val){// 執行過濾規則this.filteredHeros = this.heros.filter((hero) => {return hero.name.indexOf(val) >= 0})} */keyword : {immediate : true,handler(val){this.filteredHeros = this.heros.filter((hero) => {return hero.name.indexOf(val) >= 0})}}}})// 回顧filterlet arr = [1,2,3,4,5,6,7,8,9]// filter不會破壞原數組的結構,會生成一個全新的數組。let newArr = arr.filter((num) => {//return 過濾規則return num < 5})console.log(newArr)</script></body></html>

注意filter過濾使用的特點:filter不會破壞原數組的結構,會生成一個全新的數組。

computed實現

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表過濾計算屬性實現</title><script src="../js/vue.js"></script><style>th,td{border: 1px solid black;}</style></head><body><div id="app"><h1>{{msg}}</h1><input type="text" placeholder="請輸入搜索關鍵字" v-model="keyword"><table><tr><th>序號</th><th>英雄</th><th>能量值</th><th>選擇</th></tr><tr v-for="(hero,index) in filteredHeros" :key="hero.id"><td>{{index+1}}</td><td>{{hero.name}}</td><td>{{hero.power}}</td><td><input type="checkbox"></td></tr></table></div><script>const vm = new Vue({el : '#app',data : {keyword : '',msg : '列表過濾',heros : [{id:'101',name:'艾格文',power:10000},{id:'102',name:'麥迪文',power:9000},{id:'103',name:'古爾丹',power:8000},{id:'104',name:'薩爾',power:6000}]},computed : {filteredHeros(){// 執行過濾return this.heros.filter((hero) => {return hero.name.indexOf(this.keyword) >= 0})}}})</script></body></html>

2.8 列表排序

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表排序</title><script src="../js/vue.js"></script><style>th,td{border: 1px solid black;}</style></head><body><div id="app"><h1>{{msg}}</h1><input type="text" placeholder="請輸入搜索關鍵字" v-model="keyword"><br><button @click="type = 1">升序</button><button @click="type = 2">降序</button><button @click="type = 0">原序</button><table><tr><th>序號</th><th>英雄</th><th>能量值</th><th>選擇</th></tr><tr v-for="(hero,index) in filteredHeros" :key="hero.id"><td>{{index+1}}</td><td>{{hero.name}}</td><td>{{hero.power}}</td><td><input type="checkbox"></td></tr></table></div><script>const vm = new Vue({el : '#app',data : {type : 0,keyword : '',msg : '列表排序',heros : [{id:'101',name:'艾格文',power:10000},{id:'102',name:'麥迪文',power:9000},{id:'103',name:'古爾丹',power:8000},{id:'104',name:'薩爾',power:11000}]},computed : {filteredHeros(){// 執行過濾const arr = this.heros.filter((hero) => {return hero.name.indexOf(this.keyword) >= 0})// 排序if(this.type === 1){arr.sort((a, b) => {return a.power - b.power})}else if(this.type == 2){arr.sort((a, b) => {return b.power - a.power})}// 返回return arr}}})// 回顧sort方法let arr = [8,9,5,4,1,2,3]// sort方法排序之后,不會生成一個新的數組,是在原數組的基礎之上進行排序,會影響原數組的結構。arr.sort((a, b) => {return b - a})console.log(arr)</script></body></html>

看代碼中是執行了一下過濾方法,然后再執行的排序方法,我本地寫的時候是沒有執行過濾方法的,導致點擊原序按鈕的時候界面是沒有任何反應的,因為我只執行了sort方法,導致原來的數據結構也跟著變化了,所以不會再返回原來的數據顯示到界面。


除了先使用過濾方法外,還有另外的方式,就是先把這個數組賦值給另外一個數組,我們上面的寫法


?

sort方法特點:sort方法排序之后,不會生成一個新的數組,是在原數組的基礎之上進行排序,會影響原數組的結構。所以在使用的過程中一定要注意不要直接用原對象進行排序

2.9 收集表單數據

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>表單數據的收集</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1><!-- form表單點擊提交會直接放松請求所以我們使用@submit.prevent ?禁用屬性原有的事件,適用于向后臺提交數據發送ajax請求 --><form @submit.prevent="send"><!-- 輸入框前后去空字符串的寫法 用v-model.trim -->用戶名:<input type="text" v-model.trim="user.username"><br><br>密碼:<input type="password" v-model="user.password"><br><br><!-- 字符串轉數字的寫法 ?v-model.number -->年齡:<input type="number" v-model.number="user.age"><br><br>性別:<!-- 單選框一定要寫value -->男<input type="radio" name="gender" value="1" v-model="user.gender">女<input type="radio" name="gender" value="0" v-model="user.gender"><br><br>愛好:<!-- 注意:對于checkbox來說,如果沒有手動指定value,那么會拿這個標簽的checked屬性的值作為value -->旅游<input type="checkbox" v-model="user.interest" value="travel">運動<input type="checkbox" v-model="user.interest" value="sport">唱歌<input type="checkbox" v-model="user.interest" value="sing"><br><br>學歷:<select v-model="user.grade"><option value="">請選擇學歷</option><option value="zk">專科</option><option value="bk">本科</option><option value="ss">碩士</option></select><br><br>簡介:<!-- v-model.lazy 懶加載,適用于當你這個輸入框寫完以后才響應數據 --><textarea cols="50" rows="15" v-model.lazy="user.introduce"></textarea><br><br><input type="checkbox" v-model="user.accept">閱讀并接受協議<br><br><!-- <button @click.prevent="send">注冊</button> --><button>注冊</button></form></div><script>const vm = new Vue({el : '#app',data : {user : {username : '',password : '',age : '',gender : '1',interest : ['travel'],grade : 'ss',introduce : '',accept : ''},msg : '表單數據的收集'},methods : {send(){alert('ajax...!!!!')// 將數據收集好,發送給服務器。//console.log(JSON.stringify(this.$data))console.log(JSON.stringify(this.user))}}})</script></body></html>

頁面展示效果:

運行結果:

2.10 過濾器

過濾器filters適用于簡單的邏輯處理,例如:對一些數據進行格式化顯示。他的功能完全可以使用methods,computed來實現。過濾器可以進行全局配置,也可以進行局部配置:
① 全局配置:在構建任何Vue實例之前使用Vue.filter(‘過濾器名稱’, callback)進行配置。
② 局部配置:在構建Vue實例的配置項中使用filters進行局部配置。
過濾器可以用在兩個地方:插值語法和v-bind指令中。
多個過濾器可以串聯:{{msg | filterA | filterB | filterC}} ,' | ' 代表管道符
過濾器也可以接收額外的參數,但過濾器的第一個參數永遠接收的都是前一個過濾器的返回值。具體使用看下面代碼

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>過濾器</title><script src="../../js/vue.js"></script></head><body><!--需求:從服務器端返回了一個商品的價格price,這個price的值可能是這幾種情況:''、null、undefined、60.5要求:如果是''、null、undefined ,頁面上統一顯示為 -如果不是 ''、null、undefined,則頁面上顯示真實的數字即可。在Vue3當中,已經將過濾器語法廢棄了。--><div id="app"><h1>{{msg}}</h1><h2>商品價格:{{formatPrice}}</h2><h2>商品價格:{{formatPrice2()}}</h2><h2>商品價格:{{price | filterA | filterB(3)}}</h2><input type="text" :value="price | filterA | filterB(3)"></div><hr><div id="app2"><h2>商品價格:{{price | filterA | filterB(3)}}</h2></div><script>// 配置全局的過濾器。Vue.filter('filterA', function(val){if(val === null || val === undefined || val === ''){return '-'}return val})Vue.filter('filterB', function(val, number){return val.toFixed(number)})const vm2 = new Vue({el : '#app2',data : {price : 20.3}})const vm = new Vue({el : '#app',data : {msg : '過濾器',price : 50.6},methods: {formatPrice2(){if(this.price === '' || this.price === undefined || this.price === null){return '-'}return this.price}},computed : {formatPrice(){if(this.price === '' || this.price === undefined || this.price === null){return '-'}return this.price}},/* filters : {// 局部過濾器filterA(val){if(val === null || val === undefined || val === ''){return '-'}return val},filterB(val, number){// 確保傳遞過來的數據val,保留兩位小數。return val.toFixed(number)}} */})</script></body></html>

2.11 Vue的其它指令

2.11.1 v-text

將內容填充到標簽體當中,并且是以覆蓋的形式填充,而且填充的內容中即使存在HTML標簽也只是會當做一個普通的字符串處理,不會解析。功能等同于原生JS中的innerText。

2.11.2 v-html

將內容填充到標簽體當中,并且是以覆蓋的形式填充,而且將填充的內容當做HTML代碼解析。功能等同于原生JS中的innerHTML。
v-html不要用到用戶提交的內容上。可能會導致XSS攻擊。XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶加載并執行攻擊者惡意制造的網頁程序。這些惡意網頁程序通常是JavaScript。
例如:用戶在留言中惡意植入以下信息:

其他用戶上當了:如果點擊了以上的留言,就會將cookie發送給惡意的服務器。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue的其它指令</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1>{{msg}},test</h1><!--v-text指令:可以將指令的內容拿出來填充到標簽體當中。和JS的innerText一樣。這種填充是以覆蓋的形式進行的。先清空標簽體當中原有的內容,填充新的內容。即使內容是一段HTML代碼,這種方式也不會將HTML代碼解析并執行。只會當做普通文本來處理。--><h1 v-text="msg">test</h1><h1 v-text="name">test</h1><h1 v-text="s1"></h1><!--v-html指令:和v-text一樣,也是填充標簽體內容。也是采用覆蓋的形式進行。只不過v-html會將內容當做一段HTML代碼解析并執行。--><h1 v-html="s1"></h1></div><script>const vm = new Vue({el : '#app',data : {msg : 'Vue的其它指令',name : 'jack',s1 : '<h1>歡迎大家學習Vue!</h1>'}})</script></body></html>
2.11.3 v-cloak

v-cloak配置css樣式來解決胡子的閃現問題。
v-cloak指令使用在標簽當中,當Vue實例接管之后會刪除這個指令。
這是一段CSS樣式:當前頁面中所有帶有v-cloak屬性的標簽都隱藏起來。

注意:如果使用這個指令的話必須搭配以下代碼使用

? ? <style>[v-cloak] {display: none;}</style>

完整代碼:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue的其它指令</title><style>[v-cloak] {display: none;}</style></head><body><div id="app"><h1 v-cloak>{{msg}}</h1></div><script>setTimeout(() => {let scriptElt = document.createElement('script')scriptElt.src = '../js/vue.js'document.head.append(scriptElt)}, 3000)setTimeout(() => {const vm = new Vue({el : '#app',data : {msg : 'Vue的其它指令'}})}, 4000)</script></body></html>

也就是說按照上面代碼的方式渲染到頁面,如果<h1 v-cloak>{{msg}}</h1>沒有加v-cloak的話,我們使用setTimeout方式延遲渲染Vue,就會導致這個h1標簽內容直接顯示在頁面上(沒有經過Vue處理的),如果加上了這個指令,那么最開始初始化的時候就會隱藏這個h1標簽,如果不加v-cloak的話,打開頁面會顯示這樣,


然后等幾秒中才會正常顯示

2.11.4 v-once

初次接觸指令的時候已經學過了。只渲染一次。之后將被視為靜態內容。沒有動態效果了

2.11.5 v-pre

使用該指令可以提高編譯速度。帶有該指令的標簽將不會被編譯。可以在沒有Vue語法規則的標簽中使用可以提高效率。不要將它用在帶有指令語法以及插值語法的標簽中。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue的其它指令</title><script src="../../js/vue.js"></script></head><body><div id="app"><h1 v-cloak>{{msg}}</h1><h1 v-pre>歡迎學習Vue框架!</h1><h1 v-pre>{{msg}}</h1><ul><!-- 這里只會渲染一次,如果users的值有所改變,這里是不會變的,因為已經變成靜態資源了 --><li v-for="user,index of users" :key="index" v-once>{{user}}</li></ul><ul><li v-for="user,index of users" :key="index">{{user}}</li></ul></div><script>const vm = new Vue({el : '#app',data : {msg : 'Vue的其它指令',users : ['jack', 'lucy', 'james']}})</script></body></html>

2.12 vue的自定義指令

函數式:

directives : {‘text-reverse’ : function(element, binding){// element 是真實dom對象(可以通過 element instanceof HTMLElement 判斷)// binding 是綁定的對象element.innerText = binding.value.split(‘’).reverse().join(‘’)}
}

函數調用時機:

第一時機:模板初次解析時(元素與指令初次綁定)。
第二時機:模板重新解析時。

對象式:可以使用對象式完成更加細致的功能。

directives : {‘bind-parent’ : {// 元素與指令初次綁定時自動調用。bind(element, binding){},// 元素已經被插入頁面后自動調用。inserted(element, binding){},// 模板重新解析時被自動調用。update(element, binding){}}
}

自定義指令的函數中的this是window。

以上是局部指令,全局指令怎么定義:

對象式:

Vue.directive(‘bind-parent’, {bind(element, binding){},inserted(element, binding){},update(element, binding){}
})

函數式:

    Vue.directive(‘text-reverse’, function(element, binding){})

2.13 響應式與數據劫持

1.什么是響應式?

修改data后,頁面自動改變/刷新。這就是響應式。就像我們在使用excel的時候,修改一個單元格中的數據,其它單元格的數據會聯動更新,這也是響應式。

2.Vue的響應式是如何實現的?

數據劫持:Vue底層使用了Object.defineProperty,配置了setter方法,當去修改屬性值時setter方法則被自動調用,setter方法中不僅修改了屬性值,而且還做了其他的事情,例如:重新渲染頁面。setter方法就像半路劫持一樣,所以稱為數據劫持。

3.Vue會給data中所有的屬性,以及屬性中的屬性,都會添加響應式。
4. 后期添加的屬性,不會有響應式,怎么處理?
① Vue.set(目標對象, ‘屬性名’, 值)
② vm.$set(目標對象, ‘屬性名’, 值)

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>響應式與數據劫持</title><script src="../js/vue.js"></script></head><body><div id="app"><h1>{{msg}}</h1><div>姓名:{{name}}</div><div>年齡:{{age}}歲</div><div>數字:{{a.b.c.e}}</div><div>郵箱:{{a.email}}</div></div><script>const vm = new Vue({el : '#app',data : {msg : '響應式與數據劫持',name : 'jackson',age : 20,a : {b : {c : {e : 1}}}}})// 測試:后期給Vue實例動態的追加的一些屬性,會添加響應式處理嗎?// 目前來看,通過這種方式后期給vm追加的屬性并沒有添加響應式處理。//vm.$data.a.email = 'jack@126.com'// 如果你想給后期追加的屬性添加響應式處理的話,調用以下兩個方法都可以:// Vue.set() 、 vm.$set()//Vue.set(目標對象, 屬性名, 屬性值)//Vue.set(vm.$data.a, 'email', 'jack@126.com')//Vue.set(vm.a, 'email', 'jack@123.com')vm.$set(vm.a, 'email', 'jack@456.com')// 避免在運行時向Vue實例或其根$data添加響應式// 不能直接給vm / vm.$data 追加響應式屬性。只能在聲明時提前定義好。//Vue.set(vm, 'x', '1')//Vue.set(vm.$data, 'x', '1')</script></body></html>
5.Vue沒有給數組下標0,1,2,3....添加響應式,怎么處理?

① 調用Vue提供的7個API:
push()
pop()
reverse()
splice()
shift()
unshift()
sort()
或者使用:
Vue.set(數組對象, ‘index’, 值)
vm.$set(數組對象, ‘index’, 值)

數組相關方法

這些數組方法都會直接修改原數組(原地操作),使用時需要注意是否希望改變原數組:

1.?push()?- 末尾添加元素

作用:向數組末尾添加一個或多個元素
返回值:新數組長度
示例
javascript
const arr = [1, 2];
arr.push(3); // arr變為[1, 2, 3]
arr.push(4, 5); // arr變為[1, 2, 3, 4, 5]

2.?pop()?- 移除末尾元素

作用:移除并返回數組的最后一個元素
返回值:被移除的元素
示例

javascript
const arr = [1, 2, 3];
const last = arr.pop(); // last=3, arr變為[1, 2]

3.?reverse()?- 反轉數組

作用:反轉數組元素的順序
返回值:反轉后的數組(原數組也被反轉)
示例

javascript
const arr = [1, 2, 3];
arr.reverse(); // arr變為[3, 2, 1]

4.?splice()?- 添加/刪除元素

作用:在指定位置添加/刪除元素 下標從0開始
返回值:包含被刪除元素的數組
參數

  • start:開始位置
  • deleteCount:要刪除的元素個數
  • items:要添加的元素
    示例
  • javascript
    const arr = [1, 2, 3, 4];
    arr.splice(1, 2); // 從索引1刪除2個元素,arr變為[1, 4]
    arr.splice(1, 0, 'a', 'b'); // 在索引1處插入元素,arr變為[1, 'a', 'b', 4]
5.?shift()?- 移除首元素

作用:移除并返回數組的第一個元素
返回值:被移除的元素
示例

javascript
const arr = [1, 2, 3];
const first = arr.shift(); // first=1, arr變為[2, 3]

6.?unshift()?- 開頭添加元素

作用:向數組開頭添加一個或多個元素
返回值:新數組長度
示例

javascript
const arr = [1, 2];
arr.unshift(0); // arr變為[0, 1, 2]
arr.unshift(-2, -1); // arr變為[-2, -1, 0, 1, 2]

7.?sort()?- 數組排序

作用:對數組元素進行排序
返回值:排序后的數組(原數組也被排序)
參數:比較函數(可選)
示例

javascript
const arr = [3, 1, 2];
arr.sort(); // arr變為[1, 2, 3]
arr.sort((a, b) => b - a); // 降序排列,arr變為[3, 2, 1]

重要注意事項
  1. 這些方法都會修改原數組,如果不想修改原數組:
    javascript
    // 先創建副本再操作
    const newArr = [...arr].sort();
    const newArr = arr.slice().reverse();
  1. 在React/Vue等框架中,直接修改狀態數組可能導致問題,應該: javascript
    // Vue示例
    this.items = [...this.items, newItem]; // 而不是this.items.push(newItem)
    // React示例
    setItems(prev => [...prev, newItem]);
  1. 性能考慮:對于大型數組,創建副本會有性能開銷,在不需要保持原數組時可以直接修改。
  1. 特殊行為
    • sort()默認按字符串Unicode排序,對數字排序需要提供比較函數
    • splice()可以同時實現刪除和插入操作

這些方法都是數組操作中最常用的方法,理解它們的修改行為對編寫可預測的代碼非常重要。

代碼學習:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>數組的響應式處理</title><script src="../../js/vue.js"></script></head><body><!--1. 通過數組的下標去修改數組中的元素,默認情況下是沒有添加響應式處理的。怎么解決?2. 第一種方案:vm.$set(數組對象, 下標, 值)Vue.set(數組對象, 下標, 值)3. 第二種方案:push()pop()reverse()splice()shift()unshift()sort()在Vue當中,通過以上的7個方法來給數組添加響應式處理。--><div id="app"><h1>{{msg}}</h1><ul><li v-for="user in users">{{user}}</li></ul><ul><li v-for="vip in vips" :key="vip.id">{{vip.name}}</li></ul></div><script>const vm = new Vue({el : '#app',data : {msg : '數組的響應式處理',users : ['jack', 'lucy', 'james'],vips : [{id:'111', name:'zhangsan'},{id:'222', name:'lisi'}]}})</script></body></html>

2.14 Vue的生命周期

2.14.1 什么是生命周期

所謂的生命周期是指:一個事物從出生到最終的死亡,整個經歷的過程叫做生命周期。
例如人的生命周期:
(1) 出生:打疫苗
(2) 3歲了:上幼兒園
(3) 6歲了:上小學
(4) 12歲了:上初中
(5) ......
(6) 55歲了:退休
(7) ......
(8) 臨終:遺囑
(9) 死亡:火化

可以看到,在這個生命線上有很多不同的時間節點,在不同的時間節點上去做不同的事兒。

Vue的生命周期指的是:vm對象從創建到最終銷毀的整個過程。
(1) 虛擬DOM在內存中就緒時:去調用一個a函數
(2) 虛擬DOM轉換成真實DOM渲染到頁面時:去調用一個b函數
(3) Vue的data發生改變時:去調用一個c函數
(4) ......
(5) Vue實例被銷毀時:去調用一個x函數
在生命線上的函數叫做鉤子函數,這些函數是不需要程序員手動調用的,由Vue自動調用,程序員只需要按照自己的需求寫上,到了那個時間點自動就會執行。

2.14.2 掌握Vue的生命周期有什么用

研究Vue的生命周期主要是研究:在不同的時刻Vue做了哪些不同的事兒。
例如:在vm被銷毀之前,我需要將綁定到元素上的自定義事件全部解綁,那么這個解綁的代碼就需要找一個地方寫一下,寫到哪里呢?你可以寫到beforeDestroy()這個函數中,這個函數會被Vue自動調用,而且是在vm對象銷毀前被自動調用。像這種在不同時刻被自動調用的函數稱為鉤子函數。每一個鉤子函數都有對應的調用時間節點。
換句話說,研究Vue的生命周期主要研究的核心是:在哪個時刻調用了哪個鉤子函數。

2.14.3 Vue生命周期的4個階段8個鉤子

Vue的生命周期可以被劃分為4個階段:初始階段、掛載階段、更新階段、銷毀階段。
每個階段會調用兩個鉤子函數。兩個鉤子函數名的特點:beforeXxx()、xxxed()。
8個生命周期鉤子函數分別是:
(1) 初始階段
① beforeCreate() 創建前
② created() 創建后
(2) 掛載階段
① beforeMount() 掛載前
② mounted() 掛載后
(3) 更新階段
① beforeUpdate() 更新前
② updated() 更新后
(4) 銷毀階段
① beforeDestroy() 銷毀前
② destroyed() 銷毀后
8個鉤子函數寫在哪里?直接寫在Vue構造函數的options對象當中。
Vue官方的生命周期圖:

翻譯后的生命周期圖:

2.14.4 初始階段做了什么事兒

做了這么幾件事:
(1) 創建Vue實例vm(此時Vue實例已經完成了創建,這是生命的起點)
(2) 初始化事件對象和生命周期(接產大夫正在給他洗澡)
(3) 調用beforeCreate()鉤子函數(此時還無法通過vm去訪問data對象的屬性)
(4) 初始化數據代理和數據監測
(5) 調用created()鉤子函數(此時數據代理和數據監測創建完畢,已經可以通過vm訪問data對象的屬性)
(6) 編譯模板語句生成虛擬DOM(此時虛擬DOM已經生成,但頁面上還沒有渲染)
該階段適合做什么?
beforeCreate:可以在此時加一些loading效果。
created:結束loading效果。也可以在此時發送一些網絡請求,獲取數據。也可以在這里添加定時器。

2.14.5 掛載階段做了什么事兒

做了這么幾件事:
(1) 調用beforeMount()鉤子函數(此時頁面還未渲染,真實DOM還未生成)
(2) 給vm追加el屬性,用它來代替”el”,el代表了真實的DOM元素(此時真實DOM生成,頁面渲染完成)
(3) 調用mounted()鉤子函數
該階段適合做什么?
mounted:可以操作頁面的DOM元素了。

2.14.6 更新階段做了什么事兒

做了這么幾件事:
(1) data發生變化(這是該階段開始的標志)
(2) 調用beforeUpdate()鉤子函數(此時只是內存中的數據發生變化,頁面還未更新)
(3) 虛擬DOM重新渲染和修補
(4) 調用updated()鉤子函數(此時頁面已更新)
該階段適合做什么?
beforeUpdate:適合在更新之前訪問現有的 DOM,比如手動移除已添加的事件監聽器。
updated:頁面更新后,如果想對數據做統一處理,可以在這里完成。

2.14.7 銷毀階段做了什么事兒

做了這么幾件事:
(1) vm.$destroy()方法被調用(這是該階段開始的標志)
(2) 調用beforeDestroy()鉤子函數(此時Vue實例還在。雖然vm上的監視器、vm上的子組件、vm上的自定義事件監聽器還在,但是它們都已經不能用了。此時修改data也不會重新渲染頁面了)
(3) 卸載子組件和監視器、解綁自定義事件監聽器
(4) 調用destroyed()鉤子函數(雖然destroyed翻譯為已銷毀,但此時Vue實例還在,空間并沒有釋放,只不過馬上要釋放了,這里的已銷毀指的是vm對象上所有的東西都已經解綁完成了)
該階段適合做什么?
beforeDestroy:適合做銷毀前的準備工作,和人臨終前寫遺囑類似。例如:可以在這里清除定時器。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917475.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917475.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917475.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android 15 中禁用/啟用應用的系統級方法

在 Android 15 的開發中,有時我們需要以系統級權限來控制應用的啟用狀態。本文將介紹如何使用 PackageManager 來實現應用的禁用和啟用功能。 核心方法 在 Android 15 代碼中,可以使用以下方法來禁用或啟用應用: packageManager.setApplicationEnabledSetting(pkg,Packag…

2025網絡工程師技能圖譜(附思維導圖)

------------比較全面&#xff0c;供學習參考路線圖。-----------------------

【ROS2】rclcpp::Node 常用 API

ROS 系列學習教程(總目錄) ROS2 系列學習教程(總目錄) 目錄1. 構造函數2. 節點名稱相關3. 獲取log對象句柄4. 回調組相關5. Topic發布與訂閱6. Service服務端與客戶端1. 構造函數 public:Node(const std::string & node_name, const NodeOptions & options NodeOptio…

自動駕駛:技術、應用與未來展望——從開創到全面革新交通出行

一、引言1.1 研究背景與意義在過去的幾十年里&#xff0c;隨著科技的飛速發展&#xff0c;自動駕駛技術逐漸從科幻小說中的概念走進了現實生活。從最初簡單的輔助駕駛功能&#xff0c;到如今高度自動化的自動駕駛系統&#xff0c;這一領域的進步正深刻地改變著我們的出行方式和…

【gradle】插件那些事

文章目錄 1. 前言 2. 插件相關介紹 2.1 gradle插件的apply 2.2 引入自定義插件 2.3 常見構建任務 2.4 gradle生命周期 2.5 gradle的惰性屬性&可注入的服務 2.6 常見命令 檢查依賴樹 查看tasks 構建掃描 查看多項目構建的結構 顯示所選項目的構建腳本依賴項 指定控制臺模式來…

測試平臺如何重塑CI/CD流程中的質量協作新范式

測試平臺如何重塑CI/CD流程中的質量協作新范式 在DevOps革命席卷全球軟件行業的今天&#xff0c;測試的角色正在經歷前所未有的轉變。傳統的"測試最后"模式正在被"測試全程"的新理念所取代&#xff0c;這一轉變背后是測試平臺與CI/CD流程深度融合帶來的質量…

node.js不同環境安裝配置

node.js不同環境安裝配置 Windows環境安裝配置 一、Node.js是什么&#xff1f; ? Node.js是一個基于Chrome V8引擎的[JavaScript運行環境]。 Node.js使用了一個事件驅動、非阻塞式I/O 的模型&#xff0c;Node.js是一個讓JavaScript運行在服務端的開發平臺&#xff0c;它讓J…

深度學習-讀寫模型網絡文件

模型網絡文件是深度學習模型的存儲形式&#xff0c;保存了模型的架構、參數等信息。讀寫模型網絡文件是深度學習流程中的關鍵環節&#xff0c;方便模型的訓練、測試、部署與共享。1. 主流框架讀寫方法&#xff08;一&#xff09;TensorFlow保存模型可以使用 tf.saved_model.sav…

智慧能源管理平臺的多層協同控制架構研究

摘要&#xff1a;針對微電網多源異構設備協同難題&#xff0c;提出一種“云-邊-端”三層智慧能源管理架構。平臺集成數據采集、策略優化與全景分析功能&#xff0c;支持光伏、儲能、充電樁等設備的動態調度&#xff0c;通過自適應算法實現防逆流、需量控制及峰谷套利等策略組合…

MySQL面試題及詳細答案 155道(021-040)

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

2025年IntelliJ IDEA最新下載、安裝教程,附詳細圖文

文章目錄下載與安裝IDEA大家好&#xff0c;今天為大家帶來的是IntelliJ IDEA的下載、安裝教程&#xff0c;親測可用&#xff0c;喜歡的朋友可以點贊收藏哦下載與安裝IDEA 首先先到官網下載最新版的IntelliJ IDEA, 下載后傻瓜式安裝就好了 1、下載完后在本地找到該文件&#xf…

深入解析 Apache Tomcat 配置文件

前言 Apache Tomcat 作為最流行的開源 Java Web 應用服務器之一&#xff0c;其強大功能的背后離不開一系列精心設計的配置文件。正確理解和配置這些文件&#xff0c;是部署、管理和優化 Web 應用的關鍵。本篇博客將深入探討 Tomcat 的核心配置文件&#xff0c;涵蓋其結構、關鍵…

ThinkPHP8學習篇(一):安裝與配置

ThinkPHP有非常多的功能庫&#xff0c;我的學習策略很明確&#xff1a;不貪多求全&#xff0c;只掌握最核心的20%功能&#xff0c;解決80%的業務需求。所有學習都圍繞一個目標&#xff1a;夠用就行。遇到復雜問題時&#xff0c;再具體學習對應的內容。 作為ThinkPHP學習的第一…

【Python練習】075. 編寫一個函數,實現簡單的語音識別功能

075. 編寫一個函數,實現簡單的語音識別功能 075. 編寫一個函數,實現簡單的語音識別功能 安裝依賴庫 示例代碼 代碼說明 示例輸出 注意事項 使用 PocketSphinx 進行離線語音識別 注意事項 實現方法 使用SpeechRecognition庫實現語音識別 使用PyAudio和深度學習模型 使用Vosk離…

chrome的數據采集插件chat4data的使用

簡介&#xff1a; Chat4Data是一款Chrome擴展插件&#xff0c;支持AI網頁數據采集與分析。用戶可通過Chrome應用商店安裝后&#xff0c;在網頁上選擇區塊和字段進行數據抓取&#xff0c;設置采集頁數后導出結果。該工具適用于結構化數據提取&#xff0c;操作簡便&#xff0c;為…

《人形機器人的覺醒:技術革命與碳基未來》——類人關節設計:人工肌肉研發進展及一款超生物肌肉Hypermusclet的設計與制造

目錄&#xff1a;一、人工股肉的不同種類及工作原理和比較優勢二、人工肌肉研發的重點難點及成果進展和趨勢三、人工肌肉主要研發機構及其研發成果四、人工肌肉主要性能檢測表征能力及標準體系建設五、人工肌肉主要制造商及其產品性能優勢和供應能力六、人工肌肉在機器人市場應…

【人工智能】AI代理的倫理迷局:自主智能體的責任歸屬之謎

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在人工智能時代,AI代理作為自主決策的代表,正深刻改變著人類社會。然而,其倫理困境日益凸顯:當AI代理做出自主決策時,誰應為其后果負責…

C語言數據結構(6)貪吃蛇項目1.貪吃蛇項目介紹

1. 游戲背景 貪吃蛇是久負盛名的游戲&#xff0c;它也和俄羅斯方塊&#xff0c;掃雷等游戲位列經典游戲的行列。 在編程語言的教學中&#xff0c;我們以貪吃蛇為例&#xff0c;從設計到代碼實現來提升學生的編程能力和邏輯能力。 2. 游戲效果演示 3. 項目目標 使用C語言…

神經網絡的并行計算與加速技術

神經網絡的并行計算與加速技術一、引言隨著人工智能技術的飛速發展&#xff0c;神經網絡在眾多領域展現出了巨大的潛力和廣泛的應用前景。然而&#xff0c;神經網絡模型的復雜度和規模也在不斷增加&#xff0c;這使得傳統的串行計算方式面臨著巨大的挑戰&#xff0c;如計算速度…

工廠方法模式:從基礎到C++實現

引言 在軟件開發中&#xff0c;設計模式是解決常見問題的經過驗證的方案。其中&#xff0c;工廠方法模式是一種創建型設計模式&#xff0c;廣泛應用于需要動態創建對象的場景。本文將詳細介紹工廠方法模式的核心概念、應用場景&#xff0c;并通過C代碼示例展示其具體實現。 核心…