【Vue】 核心特性實戰解析:computed、watch、條件渲染與列表渲染

目錄

一、計算屬性(computed)

? 示例:

計算屬性-methods實現:在插值模塊里,實現函數的調用功能

計算屬性-computed的實現:

計算屬性-簡寫:

? 特點:

?? 與 methods 的區別:

二、監視屬性(watch)

🌟結論:

監視屬性-深度監視:

深度監視-deep:true 簡寫:?

監視屬性- watch實現:

📊 主要區別:

三、綁定條件與屬性(v-bind)

:class 和 原生 JavaScript 的 classList ,v-bind --> :class

@click 和 原生 JavaScript 的 addEventListener, v-on --> @click

四、條件渲染(v-if / v-show)

? 區別總結:

五、列表渲染(v-for)

key的原理:

面試題:react、vue中的key有什么作用?(key的內部原理)

列表的過濾 - filter

列表排序 - computed實現:

模擬一個數據監測:

Vue.set的使用:

Vue監測數據改變的原理:

數據劫持:

💡 Vue監視數據的原理:?

練習:答案在此,寫完可以自行對照一下~

?編輯

總結不易~ 本章節對我有很大收獲,希望對你也是!!!!


在 Vue 的開發過程中,我們經常會遇到以下幾種情況:

  • 頁面中某些值依賴其他數據計算得出

  • 需要根據用戶操作或數據變化自動響應處理邏輯

  • 某些 DOM 元素是否顯示要依賴條件判斷

  • 頁面需要渲染一個數組列表并支持交互

這些需求其實都可以歸結為幾個 Vue 的“基礎核心能力”:計算屬性、監視屬性、條件渲染、列表渲染等。本文將從實戰角度出發,帶你理解這些特性背后的邏輯與使用場景。


這里給大家推薦一個Vue自動補全插件,還是很好用的:

一、計算屬性(computed)

在模板中拼接字符串、進行運算是常見需求,但如果邏輯復雜且會多次使用,直接寫在模板中會導致代碼臃腫且難以維護。

Vue 提供了 computed 計算屬性來解決這個問題。

? 示例:

我們先來實現插值案例 好與 計算屬性進行對比:

  <div class="root">姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br>姓名:<span>{{firstName}}-{{lastName}}</span></div><script>const vm = new Vue({el: '.root',data: {firstName: "張",lastName: "三"}})
</script>

計算屬性-methods實現:在插值模塊里,實現函數的調用功能

<body><div class="root">姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br><!-- 姓名:<span>{{firstName}}-{{lastName}}</span> -->姓名:<span>{{fullName()}}</span></div><script>const vm = new Vue({el: '.root',data: {firstName: "張",lastName: "三"},methods: {fullName() {// return '小豬佩奇'console.log(this.firstName)// 這里的this就是代表著vm 那么就可以直接訪問data里面的屬性值return this.firstName + '-' + this.lastName}}})
</script>

計算屬性-computed的實現:

  1. 定義:要用的屬性不存在,要通過已有屬性計算得來
  2. 原理:底層借助了Objcet.defineproperty方法提供的getter和setter
  3. get函數什么時候執行?
  • (1).初次讀取時會執行一次。
  • (2).當依賴的數據發生改變時會被再次調用。

? ?? 4. 優勢:與methods實現相比,內部有緩存機制(復用),效率更高,調試方便
? ???5 .備注:

  • 計算屬性最終會出現在vm上,直接讀取使用即可。
  • 如果計算屬性要被修改,那必須寫set函數去響應修改,且set中要引起計算時依賴的數據發生改變。
  <div class="root">姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br><!-- 姓名:<span>{{firstName}}-{{lastName}}</span> -->姓名:<span>{{fullName}}</span><br><!-- // 這里會將fullName存入緩存,這樣不用每次都要對對fullName函數進行調用 -->姓名:<span>{{fullName}}</span><br>姓名:<span>{{fullName}}</span><br>姓名:<span>{{fullName}}</span><br></div><script>const vm = new Vue({el: '.root',data: {// data里面寫的都是屬性firstName: "張",lastName: "三"},methods: {demo() {console.log('我是一個函數')}},computed: { // 計算屬性// 這里計算屬性 fullName 你不能看作是一個函數 而是要把它當作是data里面的屬性來一樣看待// 當你訪問fullName 的時候 就會自動調用get() 來獲取返回值, 這個返回值的命名就是你創建的fullName 存入vm中fullName: {// get 有什么作用?// 當有人讀取fullName時, get就會被調用 返回值就作為fullName的值//get 什么時候會被調用? 1. 初次讀取fullName時。 2. 所依賴的數據發生改變的時候get() {console.log('get被調用了')// console.log(this) // 此處的this是vm 系統自動將當前位置的this 指向vmreturn this.firstName + '-' + this.lastName},// set什么時候調用? 當fullName被修改的時候set(value) {console.log('set', value)const arr = value.split('-')this.firstName = arr[0]this.lastName = arr[1]}}}})
</script>

計算屬性-簡寫:

    computed: { // 計算屬性// 簡寫 只有考慮讀取不考慮修改的時候才能 用簡寫形式// 一定要注意,表面上 fullName是一個函數 而實際上 是執行完這個函數后 往vm上放了一個叫fullName屬性的值// 那么以后只要記住一句 我們在上面配置的屬性是 data里面的數據 還是methods里面的方法 還是computed的計算屬性fullName() {return this.firstName + '-' + this.lastName}}

? 特點:

  • 具有緩存能力:只在相關依賴變化時重新計算

  • 更適合用于基于現有數據的“衍生數據”

?? 與 methods 的區別:

特性computedmethods
緩存? 會緩存? 每次都重新執行
使用場景衍生狀態觸發行為、事件

二、監視屬性(watch)

在 Vue 中,watch 用來“觀察”某個響應式數據的變化,并在變化時執行指定的回調函數,常用于異步操作、手動監聽等場景。

? 示例:

監視屬性-watch:hanlder是真正的處理函數,必須要寫!否則 Vue 不知道回調函數是誰。

這里watch監聽的是isHot,所以在isHot發生改變的時候,就會調用handler處理函數!

handler(newValue, oldValue) 傳入的參數就是新值舊值

immediate: true, // 初始化的時候讓handler調用一下

  <div class="root"><h2>今天天氣很{{info}}</h2><button @click="changeWeather">切換天氣</button></div><script>const vm = new Vue({el: '.root',data: {isHot: true},computed: {info() {return this.isHot ? '炎熱' : '涼爽'}},methods: {changeWeather() {this.isHot = !this.isHot}},// 第一種寫法watch: {isHot: {immediate: true, // 初始化的時候讓handler調用一下// handler 什么時候調用? 當isHot發生改變時handler(newValue, oldValue) {console.log('isHost被修改了', newValue, oldValue)}}}})// 第二種寫法vm.$watch('isHot', {immediate: true, // 初始化的時候讓handler調用一下// handler 什么時候調用? 當isHot發生改變時handler(newValue, oldValue) {console.log('isHost被修改了', newValue, oldValue)}})</script>

🌟結論:

只要 isHot 發生改變,計算屬性 info 會立刻重新計算(自動觸發)watch 的監聽器也會立刻觸發(前提是你監聽了它)。這個過程是響應式系統自動完成的,你不用手動調用

監視屬性-深度監視:

深度監視:

  1. Vue中的watch默認不監測對象內部值的改變(一層)。
  2. 配置deep:true可以監測對象內部值改變(多層)。

?備注:

  1. Vue自身可以監測對象內部值的改變,但Vue提供的watch默認不可以!
  2. 使用watch時根據數據的具體結構,決定是否采用深度監視。

當我們對vm._data里面的對象里面的屬性進行監視的時候,可以采用一個一個單獨監視:

  const vm = new Vue({el: '.root',data: {isHot: true,numbers: {a: 1,b: 1}},watch: {// 這是在只有監視a一個屬性下 如果我們要監視100個呢 不能寫100個numbers.吧'numbers.a': {handler(newValue, oldValue) {console.log('a改變了', newValue, oldValue)}}})

但是我們不可能對一個對象里面的一百個屬性 都單獨寫一個監視函數吧,所以這里就引入了一個深度監視的概念- deep:true,當該對象里面的任何一個屬性發生變化時,該Vue都能進行監測到,因為深度監視是遞歸式發生的~

<script>const vm = new Vue({el: '.root',data: {isHot: true,numbers: {a: 1,b: 1}},watch: {// 監視numbers里面的所有屬性 深度監視numbers: {// deep: true 開啟深度監視 能夠監視numbers 里面的所有屬性的變化, // 否則numbers里面的value就相當于是一個地址,只要地址沒有發生變化,這個numbers就不會變化,handler就會監視失敗deep: true,handler() {console.log('numbers改變了')}}}})
</script>

深度監視-deep:true 簡寫:?

簡寫 的代價就是不能配置其他屬性,所以要配置任何一項屬性的時候,都還是要老實些handler處理函數

  // 正常寫法vm.$watch('isHot', {immediate: true,deep: true,handler(newValue, oldValue) {console.log('監視的是isHot', newValue, oldValue)}})// 簡寫 的代價就是不能配置其他屬性vm.$watch('isHot', function (newValue, oldValue) {console.log('isHot被修改了', newValue, oldValue)})

監視屬性- watch實現:

computed和watch之間的區別:

  1. computed能完成的功能,watch都可以完成。
  2. watch能完成的功能,computed不一定能完成,例如:watch可以進行異步操作。

兩個重要的小原則:

  1. 所被Vue管理的函數,最好寫成普通函數,這樣this的指向才是vm 或 組件實例對象。
  2. 所有不被Vue所管理的函數(定時器的回調函數、ajax的回調函數等、Promise的回調函數),最好寫成箭頭函數,這樣this的指向才是vm 或 組件實例對象。

  <div class="root">姓:<input type="text" v-model="firstName"><br>名:<input type="text" v-model="lastName"><br><!-- 姓名:<span>{{firstName}}-{{lastName}}</span> -->姓名:<span>{{fullName}}</span><br><!-- // 這里會將fullName存入緩存,這樣不用每次都要對對fullName函數進行調用 -->姓名:<span>{{fullName}}</span><br>姓名:<span>{{fullName}}</span><br>姓名:<span>{{fullName}}</span><br><span>{{a}}</span></div><script>const vm = new Vue({el: '.root',data: {// data里面寫的都是屬性firstName: "張",lastName: "三",fullName: '張-三',x: 1,y: 2},computed: { // 計算屬性a() {return this.x + this.y},// 簡寫fullName() {return this.firstName + '-' + this.lastName}},watch: {firstName(val) {// setTimeout(function() {// 這里要寫成箭頭函數!!!// 原因就是如果寫成function 這個function就不是vue所管理的 而是瀏覽器引擎管理的 // 那么就是調用的setTimeout的this,這個this指向windows// 但是如果寫成箭頭函數 就會跳過setTimeout 指向firstName ,這個firstName是vm里面的普通函數 firstName里面的this又是vm//  所以此時的this就是指向vm的setTimeout(() => {console.log(this)this.fullName = val + '-' + this.lastName}, 1000)},//   firstName(newValue, oldValue) {//     this.fullName = newValue + '-' + this.lastName//   },lastName(newValue) {this.fullName = this.firstName + newValue}}})
</script>

📊 主要區別:

特性計算屬性 (computed)監視屬性 (watch)
功能用于派生(計算)新值,依賴于響應式數據。用于監聽數據變化,并在數據變化時執行某些操作。
返回值返回計算的結果,通常是一個新值沒有返回值,通常用于執行副作用(如異步操作、數據更新等)。
依賴緩存計算結果,只有相關依賴數據變化時才會重新計算。每次監聽的數據發生變化時都會觸發回調,不會進行緩存。
用例用于簡單的、派生的值(例如根據已有數據計算出一個新值)。用于處理副作用(例如異步請求、手動 DOM 操作、或數據變更后的邏輯)。
適用場景當你希望在模板中展示基于已有數據計算的內容時。當你需要在數據變化時執行一些復雜的操作時,如請求API、改變其他數據等。

記住,如果你只是單純地需要計算一個新值,選擇 計算屬性;如果你需要做復雜的操作或副作用,選擇 監視屬性

三、綁定條件與屬性(v-bind)

:class 和 原生 JavaScript 的 classList ,v-bind --> :class

:class 是 Vue 中用于動態綁定 class 類名的指令,它相當于原生 JavaScript 中使用 classList 來動態添加、移除類名。

@click 和 原生 JavaScript 的 addEventListener, v-on --> @click

@click 是 Vue 中的事件監聽器簡寫,它相當于原生 JavaScript 中使用 addEventListener 來監聽 click 事件。

<div class="root"><!-- 綁定class樣式 :class 字符串寫法 適用于: 樣式的類名不確定 需要動態綁定--><div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br><!-- 綁定class樣式 :class 數組寫法 適用于: 樣式的個數不確定、名字也不確定--><div class="basic" :class="classArr">{{name}}</div> <br><!-- 綁定class樣式 :class 對象寫法 適用于: 樣式的個數確定、名字也確定 但要動態決定用不用--><div class="basic" :class="classObj">{{name}}</div> <br></div><script>const vm = new Vue({el: '.root',data: {name: "我是哈哈",mood: 'normal',// 數組形式classArr: ['atguigu1', 'atguigu2', 'atguigu3'],// 對象形式classObj: {atguigu1: false,atguigu2: false},styleObj: {fontSize: '40px',color: 'red',backgroundColor: 'orange'}},methods: {changeMood() {const arr = ['happy', 'sad', 'normal']let index = Math.floor(Math.random() * 3)}},})</script><style>.basic {width: 400px;height: 100px;border: 1px solid black;}.happy {border: 4px solid red;;background-color: rgba(255, 255, 0, 0.644);background: linear-gradient(30deg, yellow, pink, orange, yellow);}.sad {border: 4px dashed rgb(2, 197, 2);background-color: gray;}.normal {background-color: skyblue;}.atguigu1 {background-color: yellowgreen;}.atguigu2 {font-size: 30px;text-shadow: 2px 2px 10px red;}.atguigu3 {border-radius: 20px;}</style>

四、條件渲染(v-if / v-show)

Vue 提供了兩種方式來控制元素的顯示與隱藏v-ifv-show

?條件渲染:

  1. v-if
  • 寫法:
  • (1).v-if="表達式"
  • (2).v-else-if="表達式"
  • (3).v-else="表達式"
  • 適用于:切換頻率較低的場景。
  • 特點:不展示的DOM元素直接被移除。
  • 注意:v-if可以和:v-else-if、v-else一起使用,但要求結構不能被“打斷”。
  1. v-show
  • 寫法:v-show="表達式"
  • 適用于:切換頻率較高的場景。
  • 特點:不展示的DOM元素未被移除,僅僅是使用樣式隱藏掉? ? ??
  1. 備注:使用v-if的時,元素可能無法獲取到,而使用v-show一定可以獲取到。

? 示例:

  <div class="root"><!-- 使用v-show做條件渲染 隱藏和顯示 如果變換的頻率比較快 就推薦使用 --><h2 v-show="a">歡迎來到{{name}}學習</h2><h2>當前的n值是:{{n}}</h2><button @click="n++">點我助力n+1</button><div v-show="n === 1">Angular</div><div v-show="n === 2">React</div><div v-show="n === 3">Vue</div><div v-if="n === 1">Angular</div><div v-else-if="n === 2">React</div><div v-else-if="n === 3">Vue</div><div v-else>哈哈</div><!--template 只能與 v-if 配合使用 --><!-- template 能夠完全脫掉這一層的標簽 從而不破壞內層的結構 --><template v-if="n === 1"><div>hha</div><div>hha</div><div>hha</div></template><!-- 使用v-if做條件渲染 直接刪除結構 不是隱藏了 --><h2 v-if="a">歡迎來到{{name}}學習</h2></div><script>const vm = new Vue({el: '.root',data: {name: "武漢傳媒學院",a: true,n: 0}})
</script>

? 區別總結:

特性v-ifv-show
控制方式動態添加/移除 DOM控制 display: none
首次渲染性能較慢較快
切換頻率建議用于不頻繁切換頻繁切換更適合

五、列表渲染(v-for)

當你需要展示一個數組時,v-for 是你必須掌握的工具。

v-for指令:

  1. 用于展示列表數據
  2. 語法:v-for="(item, index) in xxx" :key="yyy"
  3. 可遍歷:數組、對象、字符串(用的很少)、指定次數(用的很少)

? 基礎寫法:

  <div id="root"><h2>人員列表(遍歷數組 用的最多)</h2><ul><li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}}</li><li v-for="(p,index) in persons" :key="index"><!-- // p 結構 , index 是當前p元素的索引值 -->{{p}}----{{index}}</li></ul><h2>歡迎來到{{name}}學習</h2><!-- 遍歷對象  跟遍歷數組不一樣 第一個參數是value值 第二個參數是key屬性名 --><h2>汽車信息</h2><ul><li v-for="(value, key) in car" :key="key">{{key}} - {{value}}</li></ul><!-- 遍歷字符串 --><h2>遍歷字符串(用的少)</h2><ul><li v-for="(char,index) in str" :key="index">{{char}}-{{index}}</li></ul><!-- 遍歷指定次數 --><h2>遍歷指定次數(用的少)</h2><ul><li v-for="(num,index) in 5" :key="index">{{index}}-{{num}}</li></ul></div><script>const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',// 遍歷數組類型數據persons: [{ id: '001', name: '張三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 }],// 遍歷對象數據類型car: {name: '奧迪A8',price: '80萬',color: '黑色',},// 遍歷字符串str: "abcdefg"}})
</script>

key的原理:

面試題:react、vue中的key有什么作用?(key的內部原理)

1. 虛擬DOM中key的作用:

  • ?key是虛擬DOM對象的標識,當數據發生變化時,Vue會根據【新數據】生成【新的虛擬DOM】,隨后Vue進行【新虛擬DOM】與【舊虛擬DOM】的差異比較,比較規則如下:? ? ??

?2.對比規則:

?(1).舊虛擬DOM中找到了與新虛擬DOM相同的key:

?①.若虛擬DOM中內容沒變, 直接使用之前的真實DOM!

②.若虛擬DOM中內容變了, 則生成新的真實DOM,隨后替換掉頁面中之前的真實DOM。

(2).舊虛擬DOM中未找到與新虛擬DOM相同的key

創建新的真實DOM,隨后渲染到到頁面。

3. 用index作為key可能會引發的問題:

  1. 若對數據進行:逆序添加、逆序刪除等破壞順序操作:會產生沒有必要的真實DOM更新 ==> 界面效果沒問題, 但效率低。
  2. ? ?如果結構中還包含輸入類的DOM:會產生錯誤DOM更新 ==> 界面有問題。

4. 開發中如何選擇key?:

  1. 最好使用每條數據的唯一標識作為key, 比如id、手機號、身份證號、學號等唯一值。
  2. 如果不存在對數據的逆序添加、逆序刪除等破壞順序操作,僅用于渲染列表用于展示,使用index作為key是沒有問題的。
  <div id="root"><h2>人員列表(遍歷數組 用的最多)</h2><button @click.once="add">點擊添加</button><ul><li v-for="p in persons" :key="p.id">{{p.name}}-{{p.age}} <input type="text"></li></ul><h2>歡迎來到{{name}}學習</h2></div>
</body><script>const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',// 遍歷數組類型數據persons: [{ id: '001', name: '張三', age: 18 },{ id: '002', name: '李四', age: 19 },{ id: '003', name: '王五', age: 20 },],},methods: {add() {const p = { id: '004', name: '老牛', age: 30 }this.persons.unshift(p)}},})
</script>

    <ul><li v-for="(p, index) in persons" :key="index">{{p.name}}-{{p.age}} <input type="text"></li></ul><ul>
<!-- 不寫 默認就是就是key 為 index --><li v-for="p in persons">{{p.name}}-{{p.age}} <input type="text"></li></ul> 
  • 這兩種都是以index索引來進行標記當前li 的序號?
  • 這樣就會導致如果往數組首位置插入一個元素就會導致當前li的序號被改變
  • 從而讓vue內部進行虛擬內存對比算法的時候 比較不到相同的li序號下標,會導致重寫再次生成一份p.name 而input會在原位置不變
  • 所以 在數組有id標記的時候 還是要用id來標記當前的:key 這樣就不會讓當前的li序號隨著數組的索引改變而改變

列表的過濾 - filter

? 場景一:filter 傳自定義參數(推薦)

🧠 示例:過濾掉某個指定的值

filterHobby(target) {const arr = this.student.hobby.filter(item => item !== target);console.log(arr);
}

使用:

this.filterHobby('抽煙');

? 場景二:寫成獨立函數,傳多個參數

function excludeTarget(item, target1, target2) {return item !== target1 && item !== target2;
}filterHobby(target1, target2) {const arr = this.student.hobby.filter(item => excludeTarget(item, target1, target2));console.log(arr);
}

?

#region 和 #endregion實現折疊代碼

  <div id="root"><h2>人員列表(遍歷數組 用的最多)</h2><!-- placeholder 顯示提示文本 --><input type="text" placeholder="請輸入搜索的名字" v-model="keyWord"><ul><li v-for="p in filPerons" :key="p.id">{{p.name}}-{{p.age}}</li></ul><h2>歡迎來到{{name}}學習</h2></div><script>// 用watch實現const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',keyWord: "",// 遍歷數組類型數據persons: [{ id: '001', name: '馬冬梅', age: 19, sex: '女' },{ id: '002', name: '周冬雨', age: 20, sex: '女' },{ id: '003', name: '周杰倫', age: 21, sex: '男' },{ id: '004', name: '溫兆倫', age: 22, sex: '男' }],filPerons: []},watch: {keyWord: {immediate: true,handler(val) {// filter 方法會遍歷原數組中的每一個元素,// 并根據提供的回調函數來判斷每個元素是否滿足條件,// 如果滿足條件,就將該元素加入到返回的新數組中。this.filPersons = this.persons.filter((p) => {// 這里構造新數組 不會使用這里的返回值, 這里的返回值就只相當于回調函數 倆判斷是否可以添加到新數組中return p.name.indexOf(val) !== -1})// indexOf 返回指定元素在字符串或數組中首次出現的位置(索引)。// 如果沒有找到該元素,則返回 -1。}}}})</script>
  // 用computed實現const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',keyWord: '',// 遍歷數組類型數據persons: [{ id: '001', name: '馬冬梅', age: 19, sex: '女' },{ id: '002', name: '周冬雨', age: 20, sex: '女' },{ id: '003', name: '周杰倫', age: 21, sex: '男' },{ id: '004', name: '溫兆倫', age: 22, sex: '男' }],},computed: {
// 表面上是一個函數 但實際上就是 返回一個數組后 放入data數據內的 然后該數組就由filPersons來命名filPerons() {return this.persons.filter((p) => {return p.name.indexOf(this.keyWord) !== -1})}}})

列表排序 - computed實現:

?

  <div id="root"><h2>人員列表(遍歷數組 用的最多)</h2><!-- placeholder 顯示提示文本 --><input type="text" placeholder="請輸入搜索的名字" v-model="keyWord"><button @click="sortType = 2">年齡升序</button><button @click="sortType = 1">年齡降序</button><button @click="sortType = 0">原順序</button><ul><li v-for="p in filPerons" :key="p.id">{{p.name}}-{{p.age}}</li></ul><h2>歡迎來到{{name}}學習</h2></div> // 用computed實現const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',keyWord: '',sortType: 0, // 0原順序 1降序 2升序 @click=""// 遍歷數組類型數據persons: [{ id: '001', name: '馬冬梅', age: 30, sex: '女' },{ id: '002', name: '周冬雨', age: 31, sex: '女' },{ id: '003', name: '周杰倫', age: 18, sex: '男' },{ id: '004', name: '溫兆倫', age: 19, sex: '男' }],},computed: {filPerons() {const arr = this.persons.filter((p) => {return p.name.indexOf(this.keyWord) !== -1})// 這里只是將arr進行排序 那么 每次改變的都是只是arr數組 判斷一下是否需要排序 vocal 好聰明if (this.sortType) {arr.sort((p1, p2) => {return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age})}return arr}}})let arr = [1, 3, 2, 6, 4, 5]arr.sort((a, b) => {return a - b})console.log(arr)

模擬一個數據監測:

    let data = {name: '我是哈哈',address: '武漢'}// 創建一個監視的實例對象 用于監視data中屬性的變化const obs = new Observer(data)// Observer對象function Observer(obj) {// 匯總對象中所有的屬性形成一個數組const keys = Object.keys(obj)// 遍歷keys.forEach((k) => {Object.defineProperty(this, k, {get() { return obj[k] },set(val) {console.log(`${k}被改了, 我要去解析模板,生成虛擬DOM......我要開始忙了`)obj[k] = val}})})}// setInterval(() => {//   if (data.name !== '武漢') {//     console.log('name被我改了')//   }// }, 100)// 這里會進行死循環遞歸調用// 每次一要訪問data.name 就要調用get 然后又要訪問data.name// Object.defineProperties(data, 'name', {//   get() {//     return data.name//   },//   set(val) {//     data.name = val//   }// })

Vue.set的使用:

?

?

?

?

  <div id="root"><button @click="addLeader">點我給call校長出來</button><h1>學校信息</h1><h2>學習的名稱:{{name}}</h2><h2>學習的地址:{{address}}</h2><h2 v-if="school.leader">校長是{{school.leader}}</h2><hr><h1>學生信息</h1><button @click="addSex">添加一個學生信息 點我讓學生變性</button><h2>學生姓名:{{student.name}}</h2><h2 v-if="student.sex">學生性別:{{student.sex}}</h2><h2>學生年齡:{{student.age.rAge}},對外{{student.age.sAge}}</h2><h2>朋友們</h2><ul><li v-for="(f,index) in student.friends" :key="index">{{f.name}} --- {{f.age}}</li></ul></div><script>const vm = new Vue({el: '#root',data: {name: "武漢傳媒學院",address: '武漢',student: {name: 'tom',age: {rAge: 40,sAge: 29,},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],},school: {}},methods: {addSex() {// Vue.set(target(要添加的目標位置), key(屬性名), val(屬性值))// Vue.set(this.student, 'sex', "男")// 不過set有局限性 只能給data里面的某一個對象進行追加屬性 而不能直接往data里面進行追加屬性this.$set(this.student, 'sex', "男")},addLeader() {this.$set(this.school, 'leader', "小帥")}}})
</script>

Vue監測數據改變的原理:

?那么也就是說,對于vm里面的數組和對象進行修改的操作是不同的:

對于數組:

我們直接拿著數組的下標進行修改,會發現Vue根本就不會響應!

是因為對于作者而已,Vue內對數組下標直接訪問是沒有另外進行Vue的封裝的,觀察上面對數組進行修改的七個函數,才會讓Vue對數組的修改進行響應!!!

也就是說,對于Vue內部對 對象和數組的修改響應各有千秋,而對數組的修改卻只能操作函數來進行修改,不然Vue是不會響應的。

總結一下對于數組 和 對象的各種修改的場景:

數組:修改數組內容

  // 用computed實現const vm = new Vue({el: '#root',data: {name: '武漢傳媒學院',// 遍歷數組類型數據persons: [{ id: '001', name: '馬冬梅', age: 30, sex: '女' },{ id: '002', name: '周冬雨', age: 31, sex: '女' },{ id: '003', name: '周杰倫', age: 18, sex: '男' },{ id: '004', name: '溫兆倫', age: 19, sex: '男' }],},methods: {updateMei() {// this.persons[0].name = '馬老師'// this.persons[0].age = '50'// this.persons[0].sex = '男'// 這就說明了為什么這樣修改 界面不響應的原因// this.persons[0] = { id: '001', name: '馬老師', age: 50, sex: '男' } const p = { id: '001', name: '馬老師', age: 50, sex: '男' }this.persons.splice(0, 1, p)}}})

?

對象:添加性別屬性 和 修改性別屬性

  const vm = new Vue({el: '#root',data: {student: {name: 'tom',age: 18,// sex: '男',hobby: ['抽煙', '喝酒', '燙頭'],friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }]}},methods: {addSex() {this.$set(this.student, 'sex', '男')},changeSex() {this.$set(this.student, 'sex', '女' === this.student.sex ? '男' : '女')},},})

數據劫持:

💡 Vue監視數據的原理:?

<body><div id="root"><button @click="addLeader">點我給call校長出來</button><h1>學校信息</h1><h2>學習的名稱:{{name}}</h2><h2>學習的地址:{{address}}</h2><h2 v-if="school.leader">校長是{{school.leader}}</h2><hr><h1>學生信息</h1><button @click="addSex">添加一個學生信息 點我讓學生變性</button><h2>學生姓名:{{student.name}}</h2><h2 v-if="student.sex">學生性別:{{student.sex}}</h2><h2>學生年齡:{{student.age.rAge}},對外{{student.age.sAge}}</h2><h2>愛好</h2><ul><li v-for="(h,index) in student.hobby" :key="index">{{h}} --- {{index}}</li></ul><h2>朋友們</h2><ul><li v-for="(f,index) in student.friends" :key="index">{{f.name}} --- {{f.age}}</li></ul></div>
</body><script>const vm = new Vue({el: '#root',data: {name: "武漢傳媒學院",address: '武漢',student: {name: 'tom',age: {rAge: 40,sAge: 29,},friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }],hobby: ["喝酒", "抽煙", "燙頭"]// Vue內對數組進行修改// vm.student.hobby.push('打游戲')},school: {}},methods: {addSex() {// Vue.set(target(要添加的目標位置), key(屬性名), val(屬性值))// Vue.set(this.student, 'sex', "男")// 不過set有局限性 只能給data里面的某一個對象進行追加屬性 而不能直接往data里面進行追加屬性this.$set(this.student, 'sex', "男")},addLeader() {this.$set(this.school, 'leader', "小帥")}}})
</script>
  1. Vue會監視data中所有層次的數據。

  2. 如何監測對象中的數據?

    • 通過 setter 實現監視,且要在 new Vue 時就傳入要監測的數據。

    • 注意:

      • (1) 對象中后追加的屬性,Vue 默認不做響應式處理。

      • (2) 如需給后添加的屬性做響應式,請使用以下 API:

        • Vue.set(target, propertyName/index, value)vm.$set(target, propertyName/index, value)

  3. 如何監測數組中的數據?

    • 通過 包裹數組更新元素的方法 實現,具體做了兩件事:

      • (1) 調用原生對應的方法對數組進行更新。

      • (2) 重新解析模板,進而更新頁面。

  4. 在 Vue 修改數組中的某個元素一定要用如下方法:

    • 使用以下 API:push()pop()shift()unshift()splice()sort()reverse()

    • 或者使用:Vue.set()vm.$set()

💡 特別注意

  • Vue.set()vm.$set() 不能vmvm 的根數據對象添加屬性!!!

  • 不能應用在 vmvm._data 上。

練習:答案在此,寫完可以自行對照一下~

https://gitee.com/liu-yihao-hhh/i-love---vue/blob/master/vue-02/05.%E5%88%97%E8%A1%A8%E6%B8%B2%E6%9F%93/10.%E6%80%BB%E7%BB%93Vue%E6%95%B0%E6%8D%AE%E6%80%BB%E7%BB%93.html?

  <div id="root"><h1>學生信息</h1><button>年齡+1歲</button> <br /><button>添加性別屬性,默認值:男</button> <br /><button>修改性別</button> <br /><button>在列表首位添加一個朋友</button> <br /><button>修改第一個朋友的名字為:張三</button> <br /><button>添加一個愛好</button> <br /><button>修改第一個愛好為:開車</button> <br /><button>過濾掉愛好中的抽煙</button> <br /><h3>姓名:{{student.name}}</h3><h3>年齡:{{student.age}}</h3><h3 v-if="student.sex">性別:{{student.sex}}</h3><h3>愛好:</h3><ul><li v-for="(h,index) in student.hobby" :key="index">{{h}}</li></ul><h3>朋友們:</h3><ul><li v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。const vm = new Vue({el: '#root',data: {student: {name: 'tom',age: 18,hobby: ['抽煙', '喝酒', '燙頭'],friends: [{ name: 'jerry', age: 35 },{ name: 'tony', age: 36 }]}},})
</script>

總結不易~ 本章節對我有很大收獲,希望對你也是!!!!

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

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

相關文章

二叉樹 遞歸

本篇基于b站靈茶山艾府的課上例題與課后作業。 104. 二叉樹的最大深度 給定一個二叉樹 root &#xff0c;返回其最大深度。 二叉樹的 最大深度 是指從根節點到最遠葉子節點的最長路徑上的節點數。 示例 1&#xff1a; 輸入&#xff1a;root [3,9,20,null,null,15,7] 輸出&…

與 AI 共舞:解鎖自我提升的無限可能

與 AI 共舞&#xff1a;解鎖自我提升的無限可能 在數字化浪潮的洶涌沖擊下&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的速度重塑著世界的每一個角落。從日常生活的點滴便利到復雜工作的高效推進&#xff0c;AI 的力量無處不在。然而&#xff0c;面對 AI 的強…

【網絡安全論文】筑牢局域網安全防線:策略、技術與實戰分析

【網絡安全論文】筑牢局域網安全防線:策略、技術與實戰分析 簡述一、引言1.1 研究背景1.2 研究目的與意義1.3 國內外研究現狀1.4 研究方法與創新點二、局域網網絡安全基礎理論2.1 局域網概述2.1.1 局域網的定義與特點2.1.2 局域網的常見拓撲結構2.2 網絡安全基本概念2.2.1 網絡…

MoE Align Sort在醫院AI醫療領域的前景分析(代碼版)

MoE Align & Sort技術通過優化混合專家模型(MoE)的路由與計算流程,在醫療數據處理、模型推理效率及多模態任務協同中展現出顯著優勢,其技術價值與應用意義從以下三方面展開分析: 一、方向分析 1、提升醫療數據處理效率 在醫療場景中,多模態數據(如醫學影像、文本…

[ctfshow web入門] web4

前置知識 robots.txt是機器人協議&#xff0c;在使用爬蟲爬取網站內容時應該遵循的協議。協議并不能阻止爬蟲爬取&#xff0c;更像是一種道德規范。 假設robots.txt中寫道 Disallow: /admind.php&#xff0c;那我就暴露了自己的后臺&#xff0c;這屬于信息泄漏&#xff0c;攻擊…

innodb如何實現mvcc的

InnoDB 實現 MVCC&#xff08;多版本并發控制&#xff09;的機制主要依賴于 Undo Log&#xff08;回滾日志&#xff09;、Read View&#xff08;讀視圖&#xff09; 和 隱藏的事務字段。以下是具體實現步驟和原理&#xff1a; 1. 核心數據結構 InnoDB 的每一行數據&#xff08…

coding ability 展開第九幕(位運算——進階篇)超詳細!!!!

文章目錄 前言丟失的數字兩整數之和只出現一次的數字II消失的兩個數字總結 前言 上一篇博客&#xff0c;我們已經把位運算的基礎知識&#xff0c;以及基本運算都掌握啦 上次的習題還是讓人意猶未盡&#xff0c;今天我們來嘗試一下難一點的題目 位運算熟練起來真的讓人覺得做題是…

【數據結構篇】算法征途:穿越時間復雜度與空間復雜度的迷霧森林

文章目錄 【數據結構篇】算法征途&#xff1a;穿越時間復雜度與空間復雜度的迷霧森林 一、 什么是算法1. 算法的定義1.1 算法的五個特征1.2 好算法的特質 2. 時間復雜度3. 空間復雜度 【數據結構篇】算法征途&#xff1a;穿越時間復雜度與空間復雜度的迷霧森林 &#x1f4ac;歡…

Logo語言的系統監控

Logo語言的系統監控 引言 在信息技術飛速發展的時代&#xff0c;系統監控成為了確保計算機系統和網絡平穩運行的重要手段。系統監控不僅可以實時跟蹤系統的性能、資源使用情況和安全風險等&#xff0c;還能夠在出現問題時及時發出警報&#xff0c;從而避免潛在的故障和損失。…

STP學習

{所有內容均來自于西安歐鵬的陳俊老師} STP生成樹 當二層交換機意外成環路的時候會發生&#xff1a; 1.廣播風暴&#xff1a;當廣播幀進入環路時&#xff0c;會被不斷復制并傳輸&#xff0c;導致網絡中的廣播流量急劇增加&#xff0c;消耗大量的網絡帶寬&#xff0c;降低網絡…

使用RKNN進行yolo11-cls部署

文章目錄 概要制作數據集模型訓練onnx導出rknn導出概要 YOLO(You Only Look Once)是一系列高效的目標檢測算法,其核心思想是將目標檢測任務轉化為一個回歸問題,通過單個神經網絡直接在圖像上預測邊界框和類別概率。當將其用于分類任務時,會去除目標檢測相關的邊界框預測部…

【MySQL】01.MySQL環境安裝

注意&#xff1a;在MYSQL的安裝與卸載中&#xff0c;需要使用root用戶進行。 一、卸載不必要的環境 ? 查看是否有運行的服務 [rootVM-24-10-centos etc]# ps axj |grep mysql1 22030 22029 22029 ? -1 Sl 27 0:00 /usr/sbin/mysqld --daemonize --pid-fi…

程序化廣告行業(59/89):廣告驗證與反作弊實戰技巧

程序化廣告行業&#xff08;59/89&#xff09;&#xff1a;廣告驗證與反作弊實戰技巧 大家好&#xff01;在程序化廣告領域&#xff0c;想要做好投放&#xff0c;除了了解基本的架構和原理&#xff0c;還得掌握一些關鍵的技能&#xff0c;比如廣告驗證和反作弊。今天就和大家一…

矢量瓦片切片工具

1.geoserver 可以生成geojson mvt(pbf) tojson 三種格式矢量瓦片 2.mapbox的tippecanoe 可以生成pbf矢量瓦片&#xff0c;文件夾形式和mbtiles兩種 3.TileStache python工具&#xff0c;可以生成geojson瓦片 4.PostGis mapbox插件可以生成pbf瓦片&#xff0c;據說是動態切片…

Windows 系統 Git 2.15.0 (64位) 下載與安裝教程

1. 下載 Git 2.15.0 (64位) 安裝包 下載地址&#xff1a;https://pan.quark.cn/s/f817ab9285dc 2. 運行安裝程序 雙擊下載的 Git-2.15.0-64-bit.exe。 如果系統提示安全警告&#xff0c;選擇 “運行”&#xff08;確認來源可信&#xff09;。 3. 安裝向導設置 按以下步驟配…

MCP服務器:AI與外部工具交互的橋梁——Python和代理AI工具集成指南

&#x1f9e0; 向所有學習者致敬&#xff01; “學習不是裝滿一桶水&#xff0c;而是點燃一把火。” —— 葉芝 我的博客主頁&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 歡迎點擊加入AI人工智能社區&#xff01; &#x1f680; 讓我們一起努力&#xff0c;共創…

AIGC8——大模型生態與開源協作:技術競逐與普惠化浪潮

引言&#xff1a;大模型發展的分水嶺時刻 2024年成為AI大模型發展的關鍵轉折點&#xff1a;OpenAI的GPT-4o實現多模態實時交互&#xff0c;中國DeepSeek-MoE-16b模型以1/8成本達到同類90%性能&#xff0c;而開源社區如Mistral、LLama 3持續降低技術門檻。這場"閉源商業巨…

Muduo網絡庫實現 [十五] - HttpContext模塊

目錄 設計思路 類的設計 解碼過程 模塊的實現 私有接口 請求函數 解析函數 公有接口 疑惑點 設計思路 記錄每一次請求處理的進度&#xff0c;便于下一次處理。 上下文模塊是Http協議模塊中最重要的一個模塊&#xff0c;他需要記錄每一次請求處理的進度&#xff0c;需…

解決GraalVM Native Maven Plugin錯誤:JAVA_HOME未指向GraalVM Distribution

目錄 問題描述解決方案為什么需要這樣配置&#xff1f; 問題描述 在你的項目中&#xff0c;如果你遇到了以下錯誤信息&#xff1a; [ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:0.10.5:test (native-test) on project DIctSystemInJavaUsing…

java 代碼錯誤分析

錯誤代碼 class Test {private static String name; // 聲明一個私有靜態變量 namename "World"; // 靜態初始化塊&#xff0c;給 name 賦值為 "World"System.out.print(name); // 打印 name 的值public static void main(String[] args) {System.out.p…