深入理解 Vue.observable:輕量級響應式狀態管理利器

目錄

引言

一、什么是 Vue.observable?

二、為什么需要 Vue.observable?解決什么問題?

三、核心原理:響應式系統如何工作

四、如何使用 Vue.observable

功能說明

技術要點

五、關鍵注意事項與最佳實踐

六、實際應用案例

七、總結


引言

在 Vue.js 應用中,狀態管理是核心挑戰之一。對于大型應用,Vuex 提供了強大的、集中式的解決方案。然而,對于小型到中型的組件間狀態共享需求,或者希望避免引入 Vuex 的復雜度時,Vue 本身提供了一個非常優雅且輕量級的工具:Vue.observable

引入于 Vue 2.6 版本,Vue.observable?是 Vue 響應式系統底層能力的直接暴露。它允許你將一個普通的 JavaScript 對象轉化為一個響應式對象。這意味著當這個對象的屬性發生變化時,任何依賴這些屬性的地方(如 Vue 組件的模板、計算屬性、偵聽器等)都會自動更新。

一、什么是 Vue.observable?

  • 核心定義:?Vue.observable(object)?是一個全局 API,它接收一個普通的 JavaScript 對象作為參數,并返回該對象的響應式代理版本

  • 核心能力:?使傳入的對象變得“可觀察”(observable)。Vue 內部會追蹤對該對象屬性的訪問(get?操作)和修改(set?操作)。

  • 響應式基礎:?它是 Vue 實現數據綁定的基石。Vue 組件實例中的?data?選項返回的對象,在內部就是通過類似?observable?的機制(實際上是?Observer?類)處理的。

  • 輕量級狀態管理:?它本身不是一個完整的狀態管理庫(如 Vuex),而是提供了創建響應式狀態片段的能力。你可以利用它和簡單的 JavaScript 模塊模式來構建小型的狀態存儲。

二、為什么需要 Vue.observable?解決什么問題?

  1. 小型/簡單狀態共享:

    • 當你有幾個組件需要共享一些簡單的狀態(如用戶偏好設置、全局彈窗開關、小型的表單狀態),引入 Vuex 可能顯得過于臃腫和繁瑣。

    • Vue.observable?提供了一種極其輕量的方式創建一個共享的、響應式的狀態源。

  2. 避免“Prop Drilling”:

    • 在組件層級較深時,如果子組件需要祖先組件的數據,你可能需要一層層通過?props?傳遞下去,這被稱為“Prop Drilling”,代碼會變得冗余且難以維護。

    • 使用?Vue.observable?創建一個共享狀態對象,需要數據的組件可以直接導入并使用這個對象,無需層層傳遞。

  3. 復用非組件邏輯的響應式狀態:

    • 有時你可能有一些與 UI 組件解耦的純 JavaScript 邏輯(如工具函數、服務層),但這些邏輯內部也需要管理一些狀態,并且希望狀態變化能驅動 UI 更新。

    • 用?Vue.observable?包裝這些狀態,就能讓它們融入 Vue 的響應式系統。

  4. 理解 Vue 響應式原理的實踐:

    • 直接使用?Vue.observable?有助于開發者更深入地理解 Vue 響應式系統是如何追蹤依賴和觸發更新的。

三、核心原理:響應式系統如何工作

理解?Vue.observable?的關鍵在于理解 Vue 的響應式原理(Vue 2.x 基于?Object.defineProperty,Vue 3 基于?Proxy,但概念相通)。這里以 Vue 2.x 為例:

  1. 依賴收集 (Tracking Dependencies):

    • 當你訪問一個響應式對象的屬性(例如?obj.a)時,Vue 會記錄下“當前正在運行的代碼”(通常是一個組件的渲染函數?render、一個計算屬性?computed?或一個偵聽器?watcher)依賴于?obj.a

    • 這個“正在運行的代碼”被稱為?Watcher?(觀察者)。

    • Vue 通過?Object.defineProperty?的?getter?攔截屬性訪問,并在?getter?中將當前的?Watcher?添加到該屬性的依賴列表 (dep) 中。Dep?(依賴) 是管理某個特定屬性所有?Watcher?的類。

  2. 派發更新 (Triggering Updates):

    • 當你修改一個響應式對象的屬性(例如?obj.a = 2)時,Vue 通過?Object.defineProperty?的?setter?攔截修改。

    • 在?setter?中,Vue 會通知該屬性對應的?Dep

    • Dep?會遍歷它所管理的所有?Watcher,告訴它們:“你們依賴的數據變了!”

    • 每個?Watcher?收到通知后,會重新執行它關聯的代碼(比如重新運行?render?函數更新視圖、重新計算計算屬性的值、執行偵聽器回調函數)。

Vue.observable?的作用就是:?將一個普通對象包裝起來,給它的每個屬性(以及嵌套對象的屬性)添加這些?getter?和?setter?攔截器,使其具備上述的依賴收集和派發更新的能力。

四、如何使用 Vue.observable

使用?Vue.observable?通常遵循以下模式:

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue.observable 響應式狀態管理</title><script src="https://cdn.staticfile.net/vue/2.7.14/vue.min.js"></script><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);color: #333;min-height: 100vh;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;}header {text-align: center;padding: 30px 0;color: white;text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);}h1 {font-size: 2.8rem;margin-bottom: 10px;}.subtitle {font-size: 1.2rem;opacity: 0.9;max-width: 800px;margin: 0 auto;line-height: 1.6;}.content {display: grid;grid-template-columns: 1fr 1fr;gap: 30px;margin-top: 30px;}@media (max-width: 768px) {.content {grid-template-columns: 1fr;}}.card {background: rgba(255, 255, 255, 0.92);border-radius: 16px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);padding: 25px;transition: transform 0.3s ease;}.card:hover {transform: translateY(-5px);}.card h2 {color: #1a2a6c;margin-bottom: 20px;padding-bottom: 10px;border-bottom: 2px solid #fdbb2d;}.counter-display {font-size: 5rem;font-weight: bold;text-align: center;color: #b21f1f;margin: 20px 0;text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);}.btn-group {display: flex;justify-content: center;gap: 15px;margin: 20px 0;}button {background: linear-gradient(to right, #1a2a6c, #2a4a9c);color: white;border: none;padding: 12px 25px;border-radius: 50px;font-size: 1rem;font-weight: 600;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);}button:hover {transform: translateY(-3px);box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);background: linear-gradient(to right, #2a4a9c, #3a6adc);}button:active {transform: translateY(1px);}.secondary-btn {background: linear-gradient(to right, #fdbb2d, #ffcc5c);color: #333;}.secondary-btn:hover {background: linear-gradient(to right, #ffcc5c, #ffdd8c);}.info-box {background: #e3f2fd;border-left: 4px solid #2196f3;padding: 15px;border-radius: 4px;margin: 15px 0;}.code-block {background: #2d2d2d;color: #f8f8f2;padding: 15px;border-radius: 8px;font-family: 'Consolas', monospace;font-size: 0.95rem;overflow-x: auto;margin: 15px 0;}.user-list {list-style: none;margin: 15px 0;}.user-list li {background: white;padding: 12px 15px;margin-bottom: 10px;border-radius: 8px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);display: flex;justify-content: space-between;align-items: center;}.user-list li button {padding: 6px 12px;font-size: 0.85rem;}.computed-value {text-align: center;font-size: 1.2rem;padding: 15px;background: #e8f5e9;border-radius: 8px;margin: 15px 0;font-weight: bold;color: #2e7d32;}.notification {position: fixed;bottom: 20px;right: 20px;background: #4caf50;color: white;padding: 15px 25px;border-radius: 8px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);animation: slideIn 0.5s, fadeOut 0.5s 2.5s;}@keyframes slideIn {from {transform: translateX(100%);opacity: 0;}to {transform: translateX(0);opacity: 1;}}@keyframes fadeOut {from {opacity: 1;}to {opacity: 0;}}.theme-toggle {position: fixed;top: 20px;right: 20px;z-index: 100;}.dark-theme {background: linear-gradient(135deg, #0f1b3a, #2a0c4e, #5a1e5a);color: #e0e0e0;}.dark-theme .card {background: rgba(30, 30, 40, 0.92);color: #e0e0e0;}.dark-theme .card h2 {color: #64b5f6;}.dark-theme .info-box {background: #1e3a5f;border-left-color: #64b5f6;color: #e0e0e0;}.dark-theme .computed-value {background: #1b5e20;color: #a5d6a7;}.dark-theme .user-list li {background: #252536;color: #e0e0e0;}.dark-theme .code-block {background: #1a1a2a;}footer {text-align: center;color: white;padding: 30px 0;margin-top: 30px;font-size: 0.9rem;opacity: 0.8;}</style>
</head><body><div id="app"><div class="container"><header><h1>Vue.observable</h1><p class="subtitle">輕量級響應式狀態管理解決方案 - 無需Vuex即可在組件間共享狀態</p></header><div class="theme-toggle"><button @click="toggleTheme">{{ darkMode ? '淺色模式' : '深色模式' }}</button></div><div class="content"><!-- 計數器組件 --><div class="card"><h2>計數器演示</h2><div class="counter-display">{{ sharedState.count }}</div><div class="btn-group"><button @click="increment">增加</button><button @click="decrement" class="secondary-btn">減少</button><button @click="reset">重置</button></div><div class="computed-value">計數器平方: {{ countSquare }}</div><div class="info-box"><p>此計數器狀態使用 Vue.observable 創建,可以在多個組件間共享。</p></div></div><!-- 用戶管理組件 --><div class="card"><h2>用戶管理</h2><div class="btn-group"><button @click="addUser">添加用戶</button><button @click="clearUsers" class="secondary-btn">清空用戶</button></div><div v-if="sharedState.users.length"><ul class="user-list"><li v-for="(user, index) in sharedState.users" :key="index"><span>{{ user.name }} ({{ user.email }})</span><button @click="removeUser(index)">刪除</button></li></ul></div><div v-else class="info-box"><p>暫無用戶,請點擊"添加用戶"按鈕創建</p></div><div class="computed-value">用戶總數: {{ userCount }}</div></div><!-- 通知系統 --><div class="card"><h2>通知系統</h2><div class="btn-group"><button @click="showNotification('success', '操作成功!')">成功通知</button><button @click="showNotification('error', '發生錯誤!')" class="secondary-btn">錯誤通知</button><button @click="showNotification('info', '這是信息通知')">信息通知</button></div><div class="info-box"><p>通知狀態也是響應式的,可以在應用的任何地方觸發。</p></div></div><!-- 代碼示例 --><div class="card"><h2>實現代碼</h2><div class="code-block">// 使用 Vue.observable 創建響應式狀態const store = {state: Vue.observable({count: 0,users: [],notification: {show: false,message: '',type: 'info'}}),// 修改狀態的方法increment() {this.state.count++;},decrement() {this.state.count--;},reset() {this.state.count = 0;},addUser() {const users = ['張三', '李四', '王五', '趙六', '錢七'];const domains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'example.com'];const name = users[Math.floor(Math.random() * users.length)];const email = `${name.toLowerCase()}@${domains[Math.floor(Math.random() * domains.length)]}`;this.state.users.push({ name, email });},removeUser(index) {this.state.users.splice(index, 1);},clearUsers() {this.state.users = [];},showNotification(type, message) {this.state.notification = {show: true,type,message};// 3秒后自動隱藏setTimeout(() => {this.state.notification.show = false;}, 3000);}};</div></div></div><footer><p>Vue.observable 示例 | Vue 2.7.14 | 響應式狀態管理</p></footer></div><!-- 通知組件 --><div v-if="sharedState.notification.show" class="notification" :class="sharedState.notification.type">{{ sharedState.notification.message }}</div></div><script>// 使用 Vue.observable 創建響應式狀態const store = {state: Vue.observable({count: 0,users: [],darkMode: false,notification: {show: false,message: '',type: 'info'}}),// 修改狀態的方法increment() {this.state.count++;},decrement() {this.state.count--;},reset() {this.state.count = 0;},addUser() {const users = ['張三', '李四', '王五', '趙六', '錢七'];const domains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'example.com'];const name = users[Math.floor(Math.random() * users.length)];const email = `${name.toLowerCase()}@${domains[Math.floor(Math.random() * domains.length)]}`;this.state.users.push({ name, email });},removeUser(index) {this.state.users.splice(index, 1);},clearUsers() {this.state.users = [];},toggleTheme() {this.state.darkMode = !this.state.darkMode;document.body.classList.toggle('dark-theme', this.state.darkMode);},showNotification(type, message) {this.state.notification = {show: true,type,message};// 3秒后自動隱藏setTimeout(() => {this.state.notification.show = false;}, 3000);}};// 創建Vue實例new Vue({el: '#app',data: {sharedState: store.state},computed: {countSquare() {return this.sharedState.count * this.sharedState.count;},userCount() {return this.sharedState.users.length;},darkMode() {return this.sharedState.darkMode;}},methods: {increment() {store.increment();},decrement() {store.decrement();},reset() {store.reset();},addUser() {store.addUser();},removeUser(index) {store.removeUser(index);},clearUsers() {store.clearUsers();},toggleTheme() {store.toggleTheme();},showNotification(type, message) {store.showNotification(type, message);}},mounted() {// 初始添加2個用戶store.addUser();store.addUser();}});</script>
</body></html>

功能說明

這個示例展示了Vue.observable的核心功能:

  1. 響應式計數器

    • 使用Vue.observable創建共享狀態

    • 實現增加、減少和重置功能

    • 顯示計算屬性(計數器平方)

  2. 用戶管理系統

    • 動態添加/刪除用戶

    • 顯示用戶總數

    • 清空用戶功能

  3. 通知系統

    • 顯示不同類型(成功、錯誤、信息)的通知

    • 通知自動消失功能

  4. 主題切換

    • 深色/淺色模式切換

  5. 代碼展示

    • 展示Vue.observable的實現代碼

技術要點

  1. 使用Vue.observable()創建響應式狀態對象

  2. 所有狀態變更都通過集中管理的方法進行

  3. 多個組件共享同一狀態源

  4. 使用計算屬性派生狀態

  5. 演示了狀態管理的完整生命周期

這個示例可以直接保存為HTML文件并在瀏覽器中打開運行,無需任何服務器環境。

五、關鍵注意事項與最佳實踐

  1. 修改狀態:

    • 直接修改屬性:?state.count = 5;?這種方式是有效的,因為?state?是響應式的,修改會觸發更新。

    • 推薦使用 Actions/Mutations:?強烈建議將所有修改狀態的邏輯封裝在導出的?actions?方法中。這樣做的好處是:

      • 集中管理:?所有狀態變更邏輯都在一個地方,易于理解和維護。

      • 可追蹤性:?更容易追蹤狀態是如何被修改的,尤其是在調試時。

      • 潛在擴展性:?如果將來需要添加日志記錄、時間旅行調試(雖然?observable?本身不支持,但模式相似)或異步操作,修改?actions?內部即可。

    • 新增/刪除屬性:?Vue 2.x 的響應式系統對對象屬性的添加或刪除默認無法檢測。需要使用?Vue.set(object, propertyName, value)?或?Vue.delete(object, propertyName)?來確保新屬性也是響應式的。Vue 3 的?reactive?基于?Proxy?則沒有此限制。

  2. 性能考慮:

    • Vue.observable?創建的響應式對象,其性能開銷與 Vue 組件?data?中的對象相同。

    • 對于非常大或嵌套非常深的對象,響應式轉換可能會有一些初始開銷。但在大多數應用場景下,這種開銷是可以忽略不計的。

    • 避免將整個龐大應用的狀態都塞進一個?observable?對象。它更適合管理特定領域的、規模有限的狀態。如果狀態變得非常復雜,Vuex 或 Pinia 仍然是更好的選擇,它們提供了模塊化、開發工具集成等高級特性。

  3. 與 Vuex 的比較:

    特性Vue.observableVuex
    定位輕量級響應式狀態創建工具完整的、功能豐富的狀態管理庫
    復雜度極低,核心 API 只有一個中等,涉及概念 (state, getters, mutations, actions, modules)
    開發工具支持無 (Vue Devtools 能看到狀態變化)強大的時間旅行調試、狀態快照等
    模塊化需自行組織 (JS 模塊)內置模塊系統 (modules)
    嚴格模式支持 (strict: true)
    插件系統
    適用場景小型應用、組件間簡單共享、工具函數中大型復雜應用、需要高級功能
    異步處理需在?actions?中自行處理原生支持?actions?(可異步)
    服務端渲染 (SSR)需自行處理狀態共享有較好的 SSR 支持方案
  4. Vue 3 中的變化:
    在 Vue 3 中,Vue.observable?API 被重命名為?reactive,并作為?vue?包導出的一個獨立函數使用(不再掛載在?Vue?對象上)。它的底層實現也從?Object.defineProperty?換成了更強大的?Proxy,解決了 Vue 2 中無法檢測屬性添加/刪除的限制。

    // Vue 3
    import { reactive } from 'vue';const state = reactive({count: 0
    });
     

    Vue 3 還引入了?ref?用于處理基本類型的響應式,以及?computed,?watch?等 Composition API,與?reactive?結合使用可以構建出非常靈活的狀態邏輯。

六、實際應用案例

  1. 全局 UI 狀態管理:

    • 管理側邊欄的展開/折疊狀態 (isSidebarOpen)。

    • 管理全局加載指示器的顯示/隱藏 (isLoading)。

    • 管理主題切換 (亮色/暗色模式) (currentTheme)。

    • 管理全局通知/消息條 (notification?對象包含?text,?type,?visible)。

  2. 表單狀態共享:

    • 一個復雜的多步驟表單,每個步驟是獨立的組件,但共享同一個表單數據對象 (formData)。observable?狀態可以讓每個步驟組件實時讀寫表單數據并保持同步。

  3. 簡單的購物車:

    • 管理購物車中的商品列表 (cartItems)。

    • 計算購物車總價 (totalPrice?計算屬性可以在 store 中定義,組件直接使用)。

    • 添加商品 (addToCart?action)、移除商品 (removeFromCart?action)、更新數量 (updateQuantity?action)。

  4. 用戶偏好設置:

    • 存儲用戶的語言設置 (language)。

    • 存儲用戶的時區設置 (timezone)。

    • 存儲用戶的自定義視圖偏好 (viewPreferences?對象)。這些設置可以在不同組件中讀取和修改,并持久化到?localStorage

  5. 跨組件實時通信:

    • 簡單的實時聊天組件,共享當前消息列表 (messages) 和在線用戶列表 (onlineUsers)。

七、總結

Vue.observable?(Vue 3 中的?reactive) 是 Vue.js 框架提供的一個強大而基礎的工具,它揭示了 Vue 響應式系統的核心能力。通過將一個普通對象轉化為響應式對象,它使得狀態的變化能夠自動驅動依賴該狀態的視圖更新。

核心價值在于:

  • 輕量級:?無需引入額外的庫,API 簡單直接。

  • 解決簡單狀態共享:?完美應對小型應用、組件間簡單數據共享、避免 Prop Drilling 的場景。

  • 理解響應式原理:?使用它是深入理解 Vue 響應式工作機制的良好實踐。

  • 靈活性:?可以與 JavaScript 模塊模式結合,自由構建適合項目需求的狀態管理結構。

何時選擇 Vue.observable:

  • 你的狀態共享需求相對簡單,集中在幾個屬性或小型對象上。

  • 你希望避免引入 Vuex 或 Pinia 的額外概念和復雜度。

  • 項目規模較小,或者只在應用的特定局部需要共享狀態。

  • 你需要為一些非組件的工具邏輯添加響應式能力。

何時考慮 Vuex/Pinia:

  • 應用狀態變得龐大且復雜。

  • 需要嚴格的單向數據流、狀態變更追蹤、時間旅行調試。

  • 需要模塊化組織狀態和邏輯。

  • 需要處理復雜的異步操作流。

  • 需要更好的服務端渲染 (SSR) 支持。

  • 需要利用豐富的插件生態系統。

最佳實踐建議:

  1. 封裝 Actions:?始終將修改狀態的邏輯封裝在函數 (actions) 中,不要直接在組件里隨意修改狀態屬性。這提高了代碼的可維護性和可預測性。

  2. 模塊化組織:?根據功能域將狀態劃分到不同的模塊文件中。

  3. 注意屬性增刪 (Vue 2):?在 Vue 2 中,使用?Vue.set?和?Vue.delete?來確保新屬性響應式。

  4. 優先計算屬性:?在組件中使用計算屬性 (computed) 來訪問?observable?狀態,而不是在模板中寫復雜的表達式或在?methods?中頻繁訪問。

  5. 命名清晰:?給你的狀態存儲文件和導出的變量 (state,?actions) 起清晰、有意義的名字。

總而言之,Vue.observable?是 Vue 開發者工具箱中一件精悍的利器。它巧妙地在框架內置能力和輕量級狀態管理之間找到了平衡點,為構建簡潔、響應式的小型應用或功能模塊提供了優雅的解決方案。理解并善用它,可以讓你在合適的場景下寫出更簡潔、更高效的 Vue 代碼。

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

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

相關文章

JS設計模式(5): 發布訂閱模式

解鎖JavaScript發布訂閱模式&#xff1a;讓代碼溝通更優雅 在JavaScript的世界里&#xff0c;我們常常會遇到這樣的場景&#xff1a;多個模塊之間需要相互通信&#xff0c;但是又不想讓它們產生過于緊密的耦合。這時候&#xff0c;發布訂閱模式就像一位優雅的信使&#xff0c;…

【電路物聯網】SDN架構與工作原理介紹

(??? )&#xff0c;Hello我是祐言QAQ我的博客主頁&#xff1a;C/C語言&#xff0c;數據結構&#xff0c;Linux基礎&#xff0c;ARM開發板&#xff0c;網絡編程等領域UP&#x1f30d;快上&#x1f698;&#xff0c;一起學習&#xff0c;讓我們成為一個強大的攻城獅&#xff0…

vscode 保存 js 時會自動格式化,取消設置也不好使

vscode 里的設置搜索 Editor: Format On Save 取消勾選 卸載 Prettier - Code formatter 這個插件后好使了&#xff0c;本來以為是插件的問題&#xff0c;后來發現是工作區設置的問題。 因為我是用 GitHub 下載的工程打開后&#xff0c; vscode 認為是工作區了, 因為 .vscode…

xcode中project.pbxproj點開為空白問題

由于需要修改signing里面的配置&#xff0c;點擊了project.pbxproj。但是發現一片空白&#xff0c;如圖 以為是配置文件損壞&#xff0c;郵件show in Finder看了一通后沒看出什么所以然。并且發現entitlement文件、list文件全都是點開為白&#xff0c;并且沒有任何保存 最后發…

JUC并發編程(四)常見模式

目錄 一 同步與協調模式 1 保護性暫停模式 2 順序控制模式 3 生產者消費者模式 4 Balking模式&#xff08;猶豫模式&#xff09; 二 線程管理/生命周期模式 1 兩階段終止模式 一 同步與協調模式 1 保護性暫停模式 一個線程需要等待另一個線程提供特定條件&#xff08;通常是…

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

Vue 數據代理機制對屬性名的要求 在 Vue 的數據代理機制中,屬性名需遵循以下關鍵規則: 1. 禁止以 _ 或 $ 開頭 ?? Vue 會跳過代理以 _ 或 $ 開頭的屬性原因:這些前綴被 Vue 保留用于內部屬性(如 _data, _uid, $refs, $el 等)示例:data() {return {count: 1, // ?…

pdf.js在iOS移動端分頁加載優化方案(ios移動端反復刷新加載問題)

背景與問題 在iOS移動端加載大型PDF文件時&#xff0c;由于設備內存限制&#xff0c;經常遇到以下問題&#xff1a; 內存不足導致頁面崩潰大文件加載緩慢頁面反復重新加載 ##解決方案 采用PDF.js的分頁加載策略&#xff0c;實現按需加載當前可視頁面及相鄰頁面&#xff0c;…

【C++】來學習使用set和map吧

各位大佬好&#xff0c;我是落羽&#xff01;一個堅持不斷學習進步的大學生。 如果您覺得我的文章有所幫助&#xff0c;歡迎多多互三分享交流&#xff0c;一起學習進步&#xff01; 也歡迎關注我的blog主頁: 落羽的落羽 文章目錄 一、set和map是什么二、set系列1. set2. mult…

h5st逆向分析

h5st最新5.1版本逆向分析 申明定位h5st生成的位置動態插樁,事半功倍日志分析,十分鐘還原算法邏輯申明 本文僅用來記錄學習過程以免日后忘了,如有侵權請聯系刪除。 定位h5st生成的位置 通過關鍵字“sign”搜索,可以定位到window.PSign.sign(f)這個位置,f參數的值為{ &qu…

湖北理元理律師事務所企業債務優化路徑:司法重整中的再生之道

一、企業債務危機的核心矛盾&#xff1a;生存與清償的博弈 通過分析湖北理元理律師事務所經辦的17件企業債務案件&#xff0c;發現共性難題&#xff1a; 債權人要求立即清償 → 企業需持續經營造血 → 司法程序存在時間差 解決方案&#xff1a;構建“三重防火墻”機制 經…

鏈家Android面試題及參考答案

目錄 請詳細解釋類加載的過程,包括每一步的具體實現。并說明Android中的dex分包技術及其在熱更新中的應用 比較JVM和DVM的區別。在JVM中一個程序崩潰是否可能導致系統崩潰?DVM中呢? 請解釋網絡IP協議、TCP、UDP、HTTP、HTTPS、Socket的概念,并說明它們之間的區別 請深入…

LeetCode-多語言實現冒泡排序以及算法優化改進

目錄 一、冒泡排序算法 二、應用場景/前提條件 &#x1f308; 優點 &#x1f4e2; 缺點 三、經典算法實現并優化改進 方法一&#xff1a;記錄最后一次交換位置&#xff0c;下一輪只遍歷到該位置 方法二&#xff1a;添加標志位跟蹤是否發生交換&#xff0c;無交換則提前終…

JAVA畢業設計227—基于SpringBoot+hadoop+spark+Vue的大數據房屋維修系統(源代碼+數據庫)

畢設所有選題&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于SpringBoothadoopsparkVue的大數據房屋維修系統(源代碼數據庫)227 一、系統介紹 本項目前后端分離&#xff0c;分為業主、維修人員、管理員三種角色 1、業主&#xff1a; 登…

MADlib —— 基于 SQL 的數據挖掘解決方案(9)—— 數據探索之概率統計

目錄 一、概率 1. 概率的定義 2. 概率質量函數與概率密度函數 3. 條件概率 4. 期望值 二、MADlib 的概率相關函數 1. 函數語法 2. 示例 &#xff08;1&#xff09;求標準正態分布下&#xff0c;1 的概率密度函數 &#xff08;2&#xff09;求標準正態分布下&#xff…

耳蝸里的春天

早春的鄭州飄著細雨&#xff0c;我牽著女兒小滿的手走進市殘疾人康復中心時&#xff0c;玻璃門內突然傳來一陣清脆的笑聲。穿天藍色毛衣的小女孩戴著粉色耳蝸&#xff0c;正踮腳拍打著墻上的卡通貼畫&#xff0c;銀色的連接線在她耳后晃動&#xff0c;像一只折翼卻仍在起舞的蝴…

OCR(光學字符識別)算法

OCR&#xff08;光學字符識別&#xff09;算法在景區護照閱讀器中的應用是核心技術之一&#xff0c;它通過圖像處理和機器學習快速提取護照信息&#xff0c;顯著提升自動化水平。以下是其具體應用場景、技術實現及優化方向&#xff1a; 一、OCR在護照閱讀器中的核心作用 關鍵信…

html打印合同模板

概述&#xff08;吐槽&#xff09;&#xff1a;記錄一個html打印合同模板的功能&#xff0c;技術棧有點雜&#xff0c;千禧年出產老系統的數據庫是sqlserver2008&#xff0c;原系統框架是c#&#xff0c;無法二開&#xff0c;因為原系統的合同生成功能出現bug&#xff0c;沒有供…

DeepCritic: SFT+RL兩階段訓練突破LLM自我監督!顯著提升大模型的自我批判能力!!

摘要&#xff1a;隨著大型語言模型&#xff08;LLMs&#xff09;的迅速發展&#xff0c;對其輸出進行準確反饋和可擴展監督成為一個迫切且關鍵的問題。利用LLMs作為批評模型以實現自動化監督是一個有前景的解決方案。在本研究中&#xff0c;我們專注于研究并提升LLMs在數學批評…

【深度學習】深度學習中的張量:從多維數組到智能計算單元

? 一、n維數組&#xff08;張量&#xff0c;Tensor&#xff09; 1. 定義 張量&#xff08;Tensor&#xff09;是一個通用的n維數組數據結構。 它的維度&#xff08;維數&#xff09;決定了它的形狀&#xff0c;例如&#xff1a; 維度名稱舉例說明0維標量&#xff08;scalar…

以太網MDI信號PCB EMC設計要點

1. PHY側和RJ45連接器側通用MDI布局建議 1. MDI差分對保持對稱走線&#xff0c;走線上的焊盤封裝應一致&#xff0c;焊盤放置位置也應對稱。可以減少EMI測試中的模式轉換。 ??2. MDI走線應保持阻抗匹配&#xff0c;從而減少信號線上的反射。 ??3. MDI走線下需有連續完整的接…