vue3中ref和reactive響應式數據、ref模板引用(組合式和選項式區別)、組件ref的使用

目錄

Ⅰ.ref

1.基本用法:ref響應式數據

2.ref模板引用

3.ref在v-for中的模板引用

?4.ref在組件上使用

?5.TS中ref數據標注類型

Ⅱ.reactive?

?1.基本用法:reactive響應式數據

?2.TS中reactive標注類型

Ⅲ.ref和reactive的使用場景和區別

Ⅳ.小結&常見疑問解答



Ⅰ.ref

1.基本用法:ref響應式數據

ref 可以對原始類型(基本數據類型)和對象(引用類型)的數據進行響應式處理。
ref 的核心作用是將一個普通的 JavaScript 數據轉換成響應式的。它返回一個特殊的對象,這個對象包含一個名為?.value?的屬性,我們在JS中就需要通過操作?.value?訪問和修改這個ref的響應式數據,但是在模板中不需要加.value來訪問這個ref響應式數據的。

基本概念解析
基本數據類型:number, string, boolean, undefined, null
響應式數據:Vue的響應式數據(Reactivity)是Vue.js框架最重要的特性之一,它是Vue實現數據綁定的核心機制。 在Vue中,當數據發生變化時,相關的DOM元素會自動更新,而不需要手動操作DOM。 這種自動更新的機制使得開發者在編寫代碼時可以更加專注于數據的狀態和業務邏輯,而不必擔心如何去更新視圖。

?如果我們想讓一個 名為count的變量?變成響應式的,就可以這樣寫:

import { ref } from 'vue';//count是基本數據類型,變為響應式
const count = ref(0);    

現在,count變量就不再是一個普通的數字了,而是一個包含?.value?屬性的對象,它的值可以通過?count.value?來訪問和修改。當我們修改?count.value?的值時,任何依賴于?count?的頁面元素都會自動更新。
我們在JS中訪問或修改該?count變量的值的時候,需要加上?.value來進行訪問,但是在模板中訪問?count?的時候,不需要加上?.value,直接寫變量名count即可訪問count的值

//在模板中,我們可以不加..value來訪問count變量的值:
<template><div>{{ count }}</div>
</template>//在JS中,我們要加上.value來訪問/修改count變量的值:
console.log(count.value); // 0
count.value = 1; 

我們還可以讓?包含count屬性的對象 變成一個響應式的數據:

//我們可以直接用 ref 包裹整個 對象//count是對象的屬性
const data = ref({ count: 0 })    //對象也可以變成響應式的

這樣一來,data?就變成了一個響應式對象,它的所有屬性,包括?count,都會變成響應式的。我們在JS中訪問或修改該?data對象的屬性的時候,需要加上?.value來進行訪問,并且在模板中訪問?data.count?的時候,也需要加上?.value

//在模板中訪問data對象屬性count
<template>
<div>{{ data.value.count }}</div>
</template>//在JS中訪問data對象對象count
console.log(data.value.count); // 0

假如我們直接將一個?ref 對象賦值給一個對象的屬性,而?ref沒有使用.value進行賦值,那么這個屬性不會變成響應式的。

有一個名為?data?的對象,我們想讓它的?name?屬性變成響應式的,下面這種寫法是錯誤的:

因為?data.name?現在存儲的是?nameRef?對象本身,而不是它的值。
當我們修改改?nameRef.value?時,data.name?并不會隨之改變,頁面也不會更新。

const data = { name: 'John' };
const nameRef = ref('John');
data.name = nameRef;   //ref沒有使用.value進行賦值,data.name是不會變成響應式的

正確的做法是將?nameRef.value 賦值給 data.name?或者可以直接用 ref 包裹整個 data 對象,以下是正確示例:

//使用nameRef.value進行賦值
data.name = nameRef.value;//或者直接用ref包括整個data對象
const data = ref({ name: 'John' });

ref 小結:ref?是 Vue 3 中創建響應式數據的基本方法,但它并不會直接將一個普通的 JavaScript 對象變成響應式的。我們需要通過?.value?來訪問和修改響應式數據,或者直接用?ref?包裹整個對象,才能實現真正的響應式更新。

2.ref模板引用

如果我們需要直接訪問組件中的底層DOM元素,可使用vue提供特殊的ref屬性來進行訪問

我們可以在元素上使用ref屬性來設置需要訪問的DOM元素

  • ref屬性值是?字符串?的形式;
  • ref屬性值還可以是用v-bind::ref形式綁定的函數,該函數的第一個參數是該元素;

如果元素的 ref屬性值 采用的是字符串形式:

  • 在組合式API的JS中,我們需要聲明一個同名的ref變量,來獲得該模板的引用;
  • 在選項式API的JS中,可通過this.$refs來訪問模板的引用;

?組合式API:

<template><!-- 字符串形式的 ref -->賬號輸入框:<input type="text" ref="account"><button @click="accountInputStyle">改變賬號輸入框的樣式</button><!-- 函數形式的 ref ,必須采用 v-bind 或 : 的形式來給ref綁定屬性值 -->密碼輸入框:<input type="password" :ref="passwordFn"><button @click="passwordInputStyle">改變密碼輸入框的樣式</button></template><script setup>
import { ref, reactive, computed, onMounted, nextTick } from 'vue'//定義響應式數據(同名ref變量)
// ref 變量名 和 對應DOM元素的ref屬性值 相等
let account = ref(null)
let password = ref(null)const accountInputStyle = () => {//account是獲取的輸入框DOM元素account.value.style.padding = '15px'account.value.style.caretColor = 'red'account.value.className = 'rounded'account.value.focus()
}// 使用函數給ref綁定屬性值,該函數的第一個參數為該元素
// 在頁面渲染的時候會自動執行
// 函數式生命的 ref,不會在 this.$refs 中獲取
const passwordFn = (el) => {// el是DOM元素,這里是密碼輸入框password.value = elconsole.log(password.value)
}
const passwordInputStyle = () => {//此處設置的 style 均為行內樣式password.value.style.border = '4px solid green'password.value.style.padding = '15px'password.value.focus()
}onMounted(() => {});
</script><style scoped>
</style>

選項式API:

<template><!-- 字符串形式的 ref -->賬號輸入框:<input type="text" ref="account"><button @click="accountInputStyle">改變賬號輸入框的樣式</button><!-- 函數形式的 ref ,必須采用 v-bind 或 : 的形式來給ref綁定屬性值 -->密碼輸入框:<input type="password" :ref="passwordFn"><button @click="passwordInputStyle">改變密碼輸入框的樣式</button></template><script>
export default {data: () => ({accountEl: null,passwordEl: null}),methods: {changeAccountInputStyle() {this.accountEl = this.$refs.account // 獲取賬號輸入框的 DOMconsole.log(this.accountEl)this.accountEl.style = "padding: 15px"this.accountEl.className = "rounded"this.accountEl.focus()},passwordRef(el) { this.passwordEl = el  // el 元素是密碼輸入框},changePasswordInputStyle() {console.log(this.passwordEl) console.log(this.$refs) // 函數式聲明的 ref,不會在this.$refs中獲取this.passwordEl.style = "padding: 15px"this.passwordEl.className = "rounded"this.passwordEl.focus()},}
}
</script><style>
</style>

3.ref在v-for中的模板引用

當在v-for中使用模板引用時:(注意:需要?v3.2.25?及以上的版本;)

  • 如果?ref?值是?字符串?形式,在元素被渲染后包含對應整個?列表的所有元素【數組】
  • 如果?ref?值是?函數?形式,則會每渲染一個列表元素就會執行對應的函數【不推薦使用】;

?組合式API:

<template><ul><li v-for="b in books" :key="b.id" ref="bookList">{{ b.name }}</li></ul>
</template><script setup>
import { onMounted, ref } from "vue";// 書本
let books = ref([{ id: 1, name: "海底兩萬里" },{ id: 2, name: "駱駝祥子" },{ id: 3, name: "老人與海" },{ id: 4, name: "安徒生童話" },
]);let bookList = ref(null);onMounted(() => {console.log(bookList.value); // 獲取引用的 DOM 對象并打印,發現是數組bookList.value[2].className = "error";
});
</script><style>
.error {border: 1px solid red;
}
</style>

選項式API:

<template><ul><!-- 如果 ref 值是字符串形式,在元素被渲染后包含對應整個列表的所有元素【數組】 --><li v-for="b in books" :key="b.id" ref="bookList">{{ b.name }}</li></ul><button @click="changeBookListStyle">點我查看 bookList</button><hr /><!-- 如果ref值是函數形式,則會每渲染一個列表元素則會執行對應的函數【不推薦使用】 --><ul><li v-for="s in students" :key="s.id" :ref="studentsRef">{{ s.name }}</li></ul>
</template><script>
export default {data: () => ({books: [{ id: 1, name: "紅樓夢" },{ id: 2, name: "三國演義" },{ id: 3, name: "水滸傳" },{ id: 4, name: "西游記" },],students: [{ id: 1, name: "Jack" },{ id: 2, name: "Annie" },{ id: 3, name: "Tom" },],}),methods: {changeBookListStyle() {console.log(this.$refs.bookList);this.$refs.bookList[2].style = "color: red";},studentsRef(el) {console.log(el);},},
};
</script>

兩種運行效果:


4.ref在組件上使用

模板引用也可以被用在一個子組件上:這種情況下引用中獲得的值是組件實例

  • 如果子組件使用的是組合式API<script setup>,那么該子組件默認是私有的,則父組件無法訪問該子組件,除非子組件在其中通過defineExpose宏采用對象形式顯示暴露特定的數據或函數
  • 如果子組件使用的選項式API默認情況下父組件可以隨意訪問該子組件的數據和函數,除非在子組件使用expose選項來暴露特定的數據或函數,那么父組件就只能訪問在expose種暴露的數據或函數,沒有暴露的就不能訪問了。expose值為字符串數組

?組合式API:

  • 父組件:
    <template><h3>登錄頁面</h3><hr><!-- 組件上的 ref 的值為該組件的實例 --><Vue1 ref="login_vue"></Vue1><hr><button @click="showSonData">查看子組件的信息</button>
    </template><script setup>
    //組合式API中,默認情況下,子組件中的數據、函數等等都是私有的,不能訪問
    //如果 子組件 通過 defineExpose 宏采用對象形式顯式暴露特定的數據或函數等等import Vue1 from '@/components/src/test.vue'    //導入子組件
    import { ref, onMounted } from 'vue'
    const login_vue = ref(null)
    const showSonData = () => {console.log(login_vue.value.account)console.log(login_vue.value.password)login_vue.value.toLogin()
    }
    onMounted(() => {});
    </script>
  • 子組件:
    <template>賬號:<input type="text" v-model="account"><br>密碼:<input type="text" v-model="password"><hr><button @click="toLogin">登錄</button>
    </template><script setup>
    import { ref } from 'vue'
    const account = ref('admin')
    const password = ref('123456')
    const toLogin = () => {alert('登錄中……')
    }
    // 使用 defineExpose 將指定數據、函數等暴露出去
    defineExpose({account,toLogin
    });
    </script>

?效果展示:


選項式API:

  • 父組件:
<template><h3>登錄頁面</h3><hr><!-- 組件上的 ref 的值為該組件的實例 --><Vue1 ref="loginVue"></Vue1><hr><button @click="showSonData">查看子組件的信息</button>
</template><script>
//選項式API中,默認情況下,父組件可以隨意訪問子組件的數據和函數、計算屬性等等
//如果 子組件 增加 expose 選項之后,就只能訪問 expose 暴露的屬性和函數等等import Vue1 from '@/components/src/test1.vue'
export default {name: 'App',components: { Vue1 },data: () => ({login_vue: null}),methods: {showSonData () {console.log(this.login_vue.account)console.log(this.login_vue.password)this.login_vue.toLogin()}},mounted () {// 打印出來的式子組件的ref對象this.login_vue = this.$refs.loginVueconsole.log(this.login_vue)}
}
</script>

子組件:

<template>賬號:<input type="text" v-model="account"><br>密碼:<input type="text" v-model="password"><hr><button @click="toLogin">登錄</button>
</template><script>
export default {name: 'Vue1',data: () => ({account: 'admin',password: '123456'}),methods: {toLogin () {alert('登錄中……')}},//向外暴露屬性函數,增加這個選項之后,父組件只能訪問該組件暴露的屬性或方法等等expose: ['account', 'password']
}
</script><style scoped lang='scss'>
</style>

效果展示:

5.TS中ref數據標注類型

import { ref, Ref } from 'vue'
const ref1: Ref<number> = ref(0);

Ⅱ.reactive?

?1.基本用法:reactive響應式數據

reactive 不能基本類型的數據變為響應式,只適用于引用類型的數據(對象)。

reactive響應式數據由于是 proxy 代理的對象數據,可以直接獲取到數據,不必添加 .value,即不論是在模板中還是JS中不需要加.value即可訪問或修改reactive響應式數據的值。

const data = reactive({ num: 0});    //只能是引用類型,不能是基本類型
console.log(data.num); // 0

?2.TS中reactive標注類型

傳給 reactive 函數的對象類型是什么,就給返回值對應的什么類型即可。

注意:如果這個對象當中又包含了 ref,這個時候 ref 是不需要添加對應的類型的,vue 會自動將其解包。

import { reactive } from 'vue'
const data: { num: number } = reactive({ num: 0});//如果對象中本身就包含了ref時:
import { reactive } from 'vue'
const reactive1: { num: number } = reactive({ num: ref(0)});

Ⅲ.ref和reactive的使用場景和區別

  1. 如果需要一個響應式原始值,那么使用 ref() 是正確的選擇,要注意是原始值
  2. 如果需要一個響應式對象,層級不深,那么使用 ref 也可以
  3. 如果需要一個響應式可變對象,并且對象層級較深,需要深度跟蹤,那么使用 reactive

Ⅳ.小結&常見疑問解答

1.?為什么在模板中訪問?ref?數據不需要加上?.value
在模板中,Vue 會自動解包?ref?數據,所以我們可以直接使用?count?而不是?count.value,但是在 JavaScript 代碼中,我們需要使用?.value?來訪問?ref?數據的值。

2.?如何在組件之間傳遞?ref?數據?
可以通過 props 傳遞?ref?數據。在子組件中,可以使用?defineProps?來接收?ref?數據,并使用?.value?來訪問它的值。

3. 如何監聽?ref?數據的變化?
可以使用?watch?函數來監聽?ref?數據的變化。watch?函數接收兩個參數:第一個參數是要監聽的數據,第二個參數是一個回調函數,當數據發生變化時,回調函數會被執行。

4.?ref?可以用于哪些類型的數據?
ref?可以用于任何類型的 JavaScript 數據,包括基本類型(例如數字、字符串、布爾值)、對象、數組等等。(所以也可以使用ref貫穿始終...)


參考文章

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

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

相關文章

javascript實現雪花飄落效果

本文實現雪花飄落效果的 JavaScript 網頁設計案例&#xff0c;代碼實現如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

項目準備(flask+pyhon+MachineLearning)- 3

目錄 1.商品信息 2. 商品銷售預測 2.1 機器學習 2.2 預測功能 3. 模型評估 1.商品信息 app.route(/products) def products():"""商品分析頁面"""data load_data()# 計算當前期間和上期間current_period data[data[成交時間] > data[成…

FPGA開發,使用Deepseek V3還是R1(3):系統級與RTL級

以下都是Deepseek生成的答案 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;1&#xff09;&#xff1a;應用場景 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;2&#xff09;&#xff1a;V3和R1的區別 FPGA開發&#xff0c;使用Deepseek V3還是R1&#x…

實現 Leaflet 多類型點位標記與聚合功能的實戰經驗分享

在現代的地理信息系統&#xff08;GIS&#xff09;應用中&#xff0c;地圖功能是不可或缺的一部分。無論是展示商業網點、旅游景點還是公共服務設施&#xff0c;地圖都能以直觀的方式呈現數據。然而&#xff0c;當數據量較大時&#xff0c;地圖上可能會出現大量的標記點&#x…

企微審批中MySQL字段TEXT類型被截斷的排查與修復實踐

在MySQL中&#xff0c;TEXT類型字段常用于存儲較大的文本數據&#xff0c;但在一些應用場景中&#xff0c;當文本內容較大時&#xff0c;TEXT類型字段可能無法滿足需求&#xff0c;導致數據截斷或插入失敗。為了避免這種問題&#xff0c;了解不同文本類型&#xff08;如TEXT、M…

【常見BUG】Spring Boot 和 Springfox(Swagger)版本兼容問題

???歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學習,不斷總結,共同進步,活到老學到老…

HTTP 協議的發展歷程:從 HTTP/1.0 到 HTTP/2.0

HTTP 協議的發展歷程&#xff1a;從 HTTP/1.0 到 HTTP/2.0 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是 Web 的基礎協議&#xff0c;用于客戶端和服務器之間的通信。從 HTTP/1.0 到 HTTP/2.0&#xff0c;HTTP 協議經歷了多次重大改…

apload-lab打靶場

1.提示顯示所以關閉js 上傳<?php phpinfo(); ?>的png形式 抓包&#xff0c;將png改為php 然后放包上傳成功 2.提示說檢查數據類型 抓包 將數據類型改成 image/jpeg 上傳成功 3.提示 可以用phtml&#xff0c;php5&#xff0c;php3 4.先上傳.htaccess文件&#xff0…

金融支付行業技術側重點

1. 合規問題 第三方支付系統的平穩運營&#xff0c;嚴格遵循《非銀行支付機構監督管理條例》的各項條款是基礎與前提&#xff0c;其中第十八條的規定堪稱重中之重&#xff0c;是支付機構必須牢牢把握的關鍵準則。 第十八條明確指出&#xff0c;非銀行支付機構需構建起必要且獨…

Cherry Studio + 火山引擎 構建個人AI智能知識庫

&#x1f349;在信息化時代&#xff0c;個人知識庫的構建對于提高工作效率、知識管理和信息提取尤為重要。尤其是當這些知識庫能結合人工智能來智能化地整理、分類和管理數據時&#xff0c;效果更為顯著。我最近嘗試通過 Cherry Studio 和 火山引擎 來搭建個人智能知識庫&#…

LeetCode 2 - 兩數相加

LeetCode 2 - 兩數相加 是一道經典鏈表操作問題&#xff0c;經常作為面試中基礎題的變體被考察。掌握多種解法及其變體&#xff0c;并熟悉其核心思路和模板代碼&#xff0c;可以快速備戰相關鏈表或大數計算問題。 題目描述 給定兩個非空鏈表&#xff0c;它們代表兩個非負整數&…

Qt之QStateMachine等待

在項目中經常需要等待&#xff0c;我們模擬0-30的數&#xff0c;假如我們其中5&#xff0c; 25的數需要進行等待&#xff0c;等待用戶處理完自己事情后&#xff0c;按下按鈕繼續&#xff0c;找Qt的項目中有一個 QStateMachineqstatemmachine類提供了一個分層有限狀態機。 QSta…

elpis全棧課程學習之elpis-core學習總結

elpis全棧課程學習之elpis-core學習總結 核心原理 elpis-core是全棧框架elpis的服務端內核&#xff0c;主要應用于服務端接口的開發以及頁面的SSR渲染&#xff0c;elpis-core基于約定優于配置的原理&#xff0c;通過一系列的loader來加載對應的文件&#xff0c;大大節約用戶的…

ChatGPT與DeepSeek:開源與閉源的AI模型之爭

目錄 一、模型架構與技術原理 二、性能能力與應用場景 三、用戶體驗與部署靈活性 四、成本與商業模式 五、未來展望與市場影響 六、總結 隨著人工智能技術的飛速發展&#xff0c;ChatGPT和DeepSeek作為兩大領先的AI語言模型&#xff0c;成為了行業內外關注的焦點。它們在…

在筆記本電腦上用DeepSeek搭建個人知識庫

最近DeepSeek爆火&#xff0c;試用DeepSeek的企業和個人越來越多。最常見的應用場景就是知識庫和知識問答。所以本人也試用了一下&#xff0c;在筆記本電腦上部署DeepSeek并使用開源工具搭建一套知識庫&#xff0c;實現完全在本地環境下使用本地文檔搭建個人知識庫。操作過程共…

DeepSeek蒸餾TinyLSTM實操指南

一、硬件準備 階段推薦配置最低要求訓練階段NVIDIA A100 80GB 4RTX 3090 24GB 1量化階段Intel Xeon Gold 6248R CPUi7-12700K + 64GB RAM部署階段Jetson Xavier NX開發套件Raspberry Pi 4B 8GB二、軟件環境搭建 # 創建Python虛擬環境 conda create -n distil python=3.9 conda…

Linux ls 命令

Linux ls&#xff08;英文全拼&#xff1a; list directory contents&#xff09;命令用于顯示指定工作目錄下之內容&#xff08;列出目前工作目錄所含的文件及子目錄)。 語法 ls [-alrtAFR] [name...] 參數 : -a 顯示所有文件及目錄 (. 開頭的隱藏文件也會列出)-d 只列出目…

LeetCode 熱題 100 53. 最大子數組和

LeetCode 熱題 100 | 53. 最大子數組和 大家好&#xff0c;今天我們來解決一道經典的算法題——最大子數組和。這道題在 LeetCode 上被標記為中等難度&#xff0c;要求我們找出一個具有最大和的連續子數組&#xff0c;并返回其最大和。下面我將詳細講解解題思路&#xff0c;并…

【計算機網絡入門】初學計算機網絡(九)

目錄 1.令牌傳遞協議 2. 局域網&IEEE802 2.1 局域網基本概念和體系結構 3. 以太網&IEEE802.3 3.1 MAC層標準 3.1.1 以太網V2標準 ?編輯 3.2 單播廣播 3.3 沖突域廣播域 4. 虛擬局域網VLAN 1.令牌傳遞協議 先回顧一下令牌環網技術&#xff0c;多個主機形成…

Java 大視界 -- Java 大數據中的時間序列數據異常檢測算法對比與實踐(103)

&#x1f496;親愛的朋友們&#xff0c;熱烈歡迎來到 青云交的博客&#xff01;能與諸位在此相逢&#xff0c;我倍感榮幸。在這飛速更迭的時代&#xff0c;我們都渴望一方心靈凈土&#xff0c;而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識&#xff0c;也…