Vue3高級特性:深入理解effectScope及其應用場景

系列文章目錄

Vue3 組合式 API 進階:深入解析 customRef 的設計哲學與實戰技巧
Vue3 watchEffect 進階使用指南:這些特性你可能不知道
Vue3高級特性:深入理解effectScope及其應用場景


文章目錄

  • 系列文章目錄
  • 前言
  • 一、核心概念
    • 1、什么是 effectScope?
    • 2、副作用(Effect)
    • 3、作用域(Scope)
  • 二、為什么需要effectScope?
    • 1、分散的清理邏輯
    • 2、可組合性挑戰
    • effectScope 的核心價值
  • 三、effectScope API詳解
    • 導入
    • 3.1 創建作用域
      • 參數:
      • 返回值:
      • 關鍵特性
        • 1. 批量停止副作用
        • 2.暫停和恢復副作用
        • 3. 嵌套作用域
        • 4. 獨立作用域(detached: true)
    • 3.2 run(fn) 方法詳解
      • 1、自動收集副作用
      • 2、返回執行結果
      • 使用示例
    • 3.3 onScopeDispose 方法詳解
      • 基本使用
  • 四、使用場景示例
    • 場景 1:封裝可復用的組合式函數
    • 場景 2:Vue 插件/庫開發
    • 場景 3:復雜表單驗證
    • 場景 4:虛擬滾動列表優化
    • 場景5:測試用例管理
  • 五、總結


在這里插入圖片描述

前言

在Vue3的響應式系統中,effectScope 是一個用于批量管理響應式副作用(effects) 的高級 API。它主要用于在復雜場景(如組件卸載、Composable 函數)中集中控制一組副作用的生命周期。本文將帶您全面了解這個高級API,探索它如何優雅地管理復雜的副作用場景。


一、核心概念

1、什么是 effectScope?

effectScope 是 Vue3 引入的一個副作用作用域工具,用于將多個響應式副作用(effect、watch、computed 等)包裹在一個獨立的作用域中,實現批量管理。當作用域被銷毀時,內部所有副作用會被自動清理,避免內存泄漏并簡化代碼邏輯。

2、副作用(Effect)

Vue 的響應式系統依賴于副作用(如 watch, watchEffect, computed),這些副作用會在依賴變化時重新運行。

3、作用域(Scope)

effectScope 創建一個作用域,該作用域可以捕獲在其內部創建的所有副作用,并支持統一管理(暫停、停止、重新開始)這些副作用。

快速上手示例:

import { effectScope, reactive, watchEffect } from 'vue';// 1. 創建作用域
const scope = effectScope();scope.run(() => {const state = reactive({ count: 0 });// 2. 在作用域內創建副作用(自動收集)watchEffect(() => {console.log('Count:', state.count);});// 3. 模擬依賴變化state.count++;
});// 4. 停止作用域內的所有副作用
scope.stop(); // 停止監聽,控制臺不再輸出變化

二、為什么需要effectScope?

1、分散的清理邏輯

當組件中使用多個 watch/watchEffect/computed/setInterval 時,需要在 onUnmounted 中逐個清理:

// 沒有effectScope時的典型代碼const timer = setInterval(/*...*/)//定時器const handler = eventEmitter.on(/*...*/)//全局事件const watchStop = watch(/*...*/)//watch監聽const computedRef = computed(/*...*/)//計算屬性//卸載清理副作用onUnmounted(() => {clearInterval(timer)handler.off()watchStop()// 忘記清理computedRef?})}
}

這種手動管理方式存在幾個問題:

  • 需要為每個副作用單獨維護清理邏輯

  • 容易遺漏某些副作用的清理

  • 代碼組織混亂,隨著邏輯復雜化,這種手動維護會變得臃腫且易遺漏。

2、可組合性挑戰

在可復用的組合函數中創建副作用時,調用者可能無法知曉內部需要清理的資源:

// useMouse.js 組合函數
export function useMouse() {const pos = ref({ x: 0, y: 0 })const handler = e => { ... } // 副作用window.addEventListener('mousemove', handler)// 問題:如何讓調用者清理事件監聽?
}

effectScope正是為了解決這些問題而生!

effectScope 的核心價值

  • 批量管理:批量管理副作用生命周期,替代手動調用多個 stop(),簡化代碼邏輯。
  • 避免泄漏:組合函數可自主管理內部副作用,向調用者暴露簡潔的控制接口,防止內存泄漏。
  • 靈活層級:嵌套作用域鏈式停止,天然支持邏輯樹狀結構,符合組件化設計思維。
  • 架構清晰:為復雜功能建立明確的資源管理邊界。

三、effectScope API詳解

導入

import { effectScope} from 'vue';

3.1 創建作用域

調用effectScope函數可以創建獨立作用域

function effectScope(detached?: boolean): EffectScopeinterface EffectScope {run<T>(fn: () => T): T | undefinedstop(): voidpause():voidresume():void active: boolean
}

參數:

  • detached (可選): 是否創建獨立作用域(默認false)

    false: 嵌套在父作用域中,父作用域停止時會自動停止子作用域

    true: 獨立作用域,不受父作用域影響

返回值:

run(): 執行函數并捕獲其中創建的所有副作用

stop(): 停止作用域內所有副作用

pause():暫停作用域內所有副作用(可恢復)

resume():恢復被暫停的所有副作用

active: 作用域是否處于活動狀態(未停止)

關鍵特性

1. 批量停止副作用
const scope = effectScope();scope.run(() => {watchEffect(fn1); // 副作用1watchEffect(fn2); // 副作用2
});// 一次性停止 fn1 和 fn2
scope.stop();
2.暫停和恢復副作用
```javascript
const scope = effectScope();scope.run(() => {watchEffect(fn1); // 副作用1watchEffect(fn2); // 副作用2
});// 暫停fn1、fn2副作用
scope.pause();//恢復fn1、fn2副作用
scope.resume();
3. 嵌套作用域

子作用域會隨父作用域停止而自動停止

const parentScope = effectScope();parentScope.run(() => {const childScope = effectScope();childScope.run(() => {watchEffect(fn); // 子作用域的副作用});
});parentScope.stop(); // 自動停止子作用域中的副作用
4. 獨立作用域(detached: true)

創建不受父作用域影響的作用域:

const parent = effectScope();
const child = effectScope({ detached: true }); // 獨立作用域parent.run(() => {child.run(/* ... */);
});parent.stop(); // child 中的副作用不受影響

3.2 run(fn) 方法詳解

function run<T>(fn: () => T): T
  • 功能:在作用域內執行一個函數,并捕獲函數中創建的所有響應式副作用。

  • 參數:fn 是包含響應式操作的函數。

  • 返回值:返回 fn 的執行結果。

1、自動收集副作用

const scope = effectScope();
scope.run(() => {const count = ref(0);watch(count, () => console.log('Count changed')); // 被作用域收集
});

2、返回執行結果

const result = scope.run(() => 100); // result = 100

使用示例

import { effectScope, ref, watch, watchEffect } from 'vue';// 1. 創建作用域
const scope = effectScope();// 2. 在作用域內執行函數
const state = scope.run(() => {const count = ref(0);// 副作用自動注冊到作用域watch(count, (val) => console.log('Watch:', val));watchEffect(() => console.log('Effect:', count.value));return { count }; // 返回狀態
});// 修改值觸發副作用
state.count.value++; // 輸出 "Watch: 1" 和 "Effect: 1"// 3. 一鍵停止所有副作用
scope.stop(); // 所有 watch/watchEffect 停止響應
state.count.value++; // 無輸出

3.3 onScopeDispose 方法詳解

onScopeDispose是一個注冊回調函數的方法,該回調會在所屬的 effectScope 被停止 (scope.stop()) 時執行

基本使用

import { onScopeDispose } from 'vue';const scope = effectScope();
scope.run(() => {const count = ref(0);//定時器計數let intervalId = setInterval(() => {count.value++;console.log(count.value, "count");}, 1000);watchEffect(() => {console.log(count.value, "Count changed");});//在作用域停止時清理定時器onScopeDispose(() => {clearInterval(intervalId);});
});// 當調用 stop 時,作用域內定時器會被清理
scope.stop();

四、使用場景示例

場景 1:封裝可復用的組合式函數

在開發組合式函數時,可能會創建多個響應式副作用。使用 effectScope 可以確保這些副作用在組件卸載時被正確清理,或者在需要時手動停止

需求:創建一個帶自動清理功能的計時器組合函數

useTimer.js

import { effectScope, ref, watch, onScopeDispose } from "vue";// 可復用的計時器邏輯
export function useTimer(interval = 1000) {const scope = effectScope(); // 創建作用域return scope.run(() => {const count = ref(0);const isActive = ref(true);let intervalId = null;// 副作用 1:響應式計時器watch(isActive,(active) => {if (active) {intervalId = setInterval(() => count.value++, interval);console.log("開始計時");} else {clearInterval(intervalId);console.log("暫停計時");}},{ immediate: true });// 副作用 2:自動清理onScopeDispose(() => {clearInterval(intervalId);console.log("停止計時");});// 暴露給使用者的 APIreturn {count,pause: () => (isActive.value = false),//暫停resume: () => (isActive.value = true),//重新開始stop: () => scope.stop(), // 關鍵:一鍵停止所有副作用};});
}

使用:

<template><div class="container"><p>Count: {{ count }}</p><button @click="pause">暫停</button><button @click="resume">重新開始</button><button @click="stop">停止</button></div>
</template><script setup>
import {onUnmounted} from 'vue'
import { useTimer } from "./useTimer.js";
const { count, pause, resume, stop } = useTimer();
// 在組件卸載時停止所有副作用
onUnmounted(() => {stop();
});

運行結果:
請添加圖片描述

說明:

  • 一鍵清理:調用 stop() 會同時清除定時器和所有響應式依賴

  • 內存安全:避免組件卸載后定時器仍在運行的 BUG

  • 封裝性:副作用生命周期被嚴格封裝在組合函數內部


場景 2:Vue 插件/庫開發

為第三方庫提供自動清理能力以及確保插件產生的副作用不會影響主應用

示例1:開發一個地圖插件頁面卸載自動清理資源

useMapLibrary.js

// 模擬地圖庫插件
export function useMapLibrary(containerRef) {const scope = effectScope()return scope.run(() => {const map = ref(null)const markers = []watchEffect(() => {if (containerRef.value) {// 初始化地圖(偽代碼)map.value = new ThirdPartyMap(containerRef.value)// 添加示例標記markers.push(map.value.addMarker({ lat: 31.23, lng: 121.47 }))}})// 庫資源清理onScopeDispose(() => {markers.forEach(marker => marker.remove())map.value?.destroy()console.log('Map resources released')})return {map,addMarker: (pos) => markers.push(map.value.addMarker(pos)),destroy: () => scope.stop() // 暴露銷毀 API}})!
}

使用:

<template><div ref="container" ></div><button @click="addShanghaiMarker">Add Marker</button>
</template><script setup>
import { ref, onUnmounted } from 'vue'
import { useMapLibrary } from './mapLibrary'const container = ref(null)
const { addMarker, destroy } = useMapLibrary(container)// 添加額外標記
const addShanghaiMarker = () => {addMarker({ lat: 31.23, lng: 121.47 })
}// 組件卸載時銷毀地圖
onUnmounted(() => destroy())
</script>

說明:

  • 資源管理:確保銷毀地圖時同步清理所有相關資源

  • 接口簡潔:用戶只需調用 destroy() 無需了解內部實現

  • 防止泄漏:避免第三方庫造成的內存泄漏


示例2:開發一個實時通信插件,在應用卸載時自動關閉連接,避免內存泄漏。

// socket-plugin.js
import { effectScope, onScopeDispose } from 'vue'export const SocketPlugin = {install(app, options) {// 創建插件專屬作用域const socketScope = effectScope()socketScope.run(() => {// 1. 初始化 WebSocket 連接const socket = new WebSocket(options.url)let isConnected = false// 2. 監聽連接狀態socket.onopen = () => {isConnected = true//全局變量$emit需提前定義app.config.globalProperties.$emit('socket:open')}socket.onmessage = (event) => {app.config.globalProperties.$emit('socket:message', event.data)}// 3. 提供發送消息的全局方法//全局變量$socketSend需提前定義app.config.globalProperties.$socketSend = (data) => {if (isConnected) socket.send(JSON.stringify(data))}// 4. 作用域銷毀時的清理邏輯(關鍵)onScopeDispose(() => {if (socket.readyState === WebSocket.OPEN) {socket.close(1000, '應用卸載') // 正常關閉連接}console.log('WebSocket 資源已清理')})})// 5. 重寫unmount 函數達到監聽應用卸載,觸發作用域清理const originalUnmount = app.unmountapp.unmount = () => {socketScope.stop() // 手動停止作用域,觸發 onScopeDisposeoriginalUnmount.call(app) // 執行原生卸載邏輯}}
}

使用:

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { SocketPlugin } from './socket-plugin'const app = createApp(App)
app.use(SocketPlugin, { url: 'ws://localhost:3000' })
app.mount('#app')

說明:
當執行 app.unmount() (應用卸載)時,會自動觸發:
1、socketScope.stop()→ 執行 onScopeDispose 清理 WebSocket,
2、完成應用卸載

ps:注意應用的生命周期不等于組件生命周期,應用生命周期通過createApp()、app.mount()、app.unmount()等創建/捕獲


場景 3:復雜表單驗證

<script setup>
import { effectScope, reactive, computed } from 'vue'const scope = effectScope()
const form = reactive({username: '',email: '',password: '',confirmPassword: ''
})const errors = reactive({})
const isValid = computed(() => Object.keys(errors).length === 0
)scope.run(() => {// 用戶名驗證watch(() => form.username, (username) => {if (!username) {errors.username = '用戶名不能為空'} else if (username.length < 3) {errors.username = '用戶名至少3個字符'} else {delete errors.username}})// 郵箱驗證watch(() => form.email, (email) => {const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/if (!email) {errors.email = '郵箱不能為空'} else if (!emailRegex.test(email)) {errors.email = '郵箱格式不正確'} else {delete errors.email}})// 密碼一致性驗證watch([() => form.password, () => form.confirmPassword], ([password, confirmPassword]) => {if (password !== confirmPassword) {errors.password = '兩次輸入的密碼不一致'} else {delete errors.password}})
})// 組件卸載時清理所有驗證邏輯
onUnmounted(scope.stop)
</script>

表單草稿狀態暫停驗證

// 用戶點擊"保存草稿"時暫停驗證
const saveDraft=()=>{//暫停驗證scope.pause()//提交數據邏輯
}
// 用戶編輯草稿時恢復驗證
const editDraft=()=>{
//恢復驗證scope.resume()
}

場景 4:虛擬滾動列表優化

為大型列表創建虛擬滾動,僅渲染可視區域的項,并管理其副作用

VirtualList.vue


<template><divref="containerRef"class="virtual-list"style="height: 500px; overflow: auto; position: relative"><!-- 總高度占位元素 --><divref="itemsContainerRef":style="{height: `${props.items.length * props.itemHeight}px`,position: 'relative',}"><!-- 渲染可見項 --><divv-for="item in visibleItems":key="item.id":style="{position: 'absolute',top: `${item.position}px`,width: '100%',height: `${props.itemHeight}px`,boxSizing: 'border-box',}"class="virtual-item">{{ item.name }} - 索引:{{ props.items.findIndex((i) => i.id === item.id) }}</div></div></div>
</template>
<script setup>
import {ref,onMounted,onUnmounted,effectScope,onScopeDispose,nextTick,computed,
} from "vue";const props = defineProps({items: {type: Array,required: true,},itemHeight: {type: Number,default: 40,},visibleCount: {type: Number,default: 20,},bufferSize: {type: Number,default: 5,},
});const containerRef = ref(null);
const itemsContainerRef = ref(null);
const visibleStartIndex = ref(0);
const visibleEndIndex = ref(0);
// 真實可見范圍
const realVisibleStartIndex = ref(0);
const realVisibleEndIndex = ref(0);const itemScopes = new Map(); // 存儲每個項的 effectScope
let pendingFrame = null; // 用于 requestAnimationFrame 的 ID// 創建項的 effectScope
const createItemScope = (index) => {const scope = effectScope();scope.run(() => {// 為每個項創建獨立的響應式狀態const itemState = ref({ ...props.items[index], index });// 模擬項的副作用(如定時更新、動畫等)const timer = setInterval(() => {itemState.value = {...itemState.value,updatedAt: new Date().toISOString(),};}, 5000);// 清理副作用onScopeDispose(() => {console.log(index, "清理副作用");clearInterval(timer);});return itemState;});return scope;
};// 更新可見區域
const updateVisibleRange = () => {if (!containerRef.value) return;const { scrollTop, clientHeight } = containerRef.value;// 計算真實可見區域(不含緩沖區)const realStart = Math.floor(scrollTop / props.itemHeight);const realEnd = Math.min(props.items.length - 1,Math.floor((scrollTop + clientHeight) / props.itemHeight));// 更新真實可見范圍realVisibleStartIndex.value = realStart;realVisibleEndIndex.value = realEnd;// 計算帶緩沖區的可見區域const newStartIndex = Math.max(0, realStart - props.bufferSize);const newEndIndex = Math.min(props.items.length - 1,realEnd + props.bufferSize);// 僅在必要時更新if (newStartIndex !== visibleStartIndex.value ||newEndIndex !== visibleEndIndex.value) {// 清理不再可見的項的 effectScopeitemScopes.forEach((scope, index) => {if (index < newStartIndex || index > newEndIndex) {scope.stop();itemScopes.delete(index);}});// 為新可見的項創建 effectScopefor (let i = newStartIndex; i <= newEndIndex; i++) {if (!itemScopes.has(i) && props.items[i]) {const scope = createItemScope(i);itemScopes.set(i, scope);}}// 更新可見范圍visibleStartIndex.value = newStartIndex;visibleEndIndex.value = newEndIndex;}
};// 優化的滾動處理
const handleScroll = () => {// 使用 requestAnimationFrame 避免頻繁更新if (pendingFrame) {cancelAnimationFrame(pendingFrame);}pendingFrame = requestAnimationFrame(() => {updateVisibleRange();});
};// 初始化
onMounted(() => {if (!containerRef.value) return;// 初始計算可見區域updateVisibleRange();// 添加滾動監聽containerRef.value.addEventListener("scroll", handleScroll);// 監聽數據變化,更新可見區域const dataObserver = new MutationObserver(updateVisibleRange);dataObserver.observe(itemsContainerRef.value, { childList: true });
});// 清理資源
onUnmounted(() => {if (containerRef.value) {containerRef.value.removeEventListener("scroll", handleScroll);}if (pendingFrame) {cancelAnimationFrame(pendingFrame);}// 清理所有 effectScopeitemScopes.forEach((scope) => scope.stop());itemScopes.clear();
});// 計算當前可見的項
const visibleItems = computed(() => {return props.items.slice(visibleStartIndex.value, visibleEndIndex.value + 1).map((item) => ({...item,// 添加位置信息position:props.itemHeight *(props.items.findIndex((i) => i.id === item.id) || 0),}));
});// 暴露必要的屬性給父組件
defineExpose({visibleItems,visibleStartIndex,visibleEndIndex,realVisibleStartIndex,realVisibleEndIndex,
});
</script><style scoped>
.virtual-list {border: 1px solid #ccc;margin-top: 20px;width: 100%;
}.virtual-item {border-bottom: 1px solid #eee;padding: 8px;background-color: white;transition: opacity 0.1s ease;
}
</style>

頁面使用:

<!-- demo.vue -->
<template><div class="container"><h1>虛擬列表示例 ({{ totalItems }})</h1><div class="controls"><button @click="addItems" class="btn">添加 100</button><button @click="removeItems" class="btn">移除 100</button><div class="stats">可見范圍: {{range }}</div></div><VirtualListref="virtualListRef":items="items":itemHeight="itemHeight":visibleCount="visibleCount":bufferSize="bufferSize"/></div>
</template><script setup>
import { ref, computed, onMounted } from "vue";
import VirtualList from "./VirtualList.vue";// 生成大量數據
const generateItems = (count, startId = 0) => {return Array.from({ length: count }, (_, i) => ({id: startId + i,name: `項目 ${startId + i + 1}`,created: new Date().toISOString(),}));
};const items = ref(generateItems(1000));
const itemHeight = ref(40);
const visibleCount = ref(20);
const bufferSize = ref(5);
const virtualListRef = ref(null);const addItems = () => {const startId = items.value.length;const newItems = generateItems(100, startId);items.value = [...items.value, ...newItems];
};const removeItems = () => {if (items.value.length > 100) {items.value = items.value.slice(0, -100);}
};const totalItems = computed(() => items.value.length);// 初始聚焦到列表
onMounted(() => {setTimeout(() => {if (virtualListRef.value) {virtualListRef.value.$el.scrollTop = 0;}}, 100);
});// 可見范圍
const range = computed(() => {const start = virtualListRef.value?.realVisibleStartIndex || 0const end = virtualListRef.value?.realVisibleEndIndex || 0return `${start} - ${end}`
})
</script><style>
.container {max-width: 800px;margin: 0 auto;padding: 20px;font-family: Arial, sans-serif;
}.controls {display: flex;gap: 10px;margin-bottom: 20px;align-items: center;
}.btn {padding: 8px 16px;background-color: #4caf50;color: white;border: none;border-radius: 4px;cursor: pointer;
}.btn:hover {background-color: #45a049;
}.stats {margin-left: auto;font-size: 14px;color: #666;text-align: right;
}
</style>

運行結果
請添加圖片描述

場景5:測試用例管理

import { effectScope } from 'vue'//describe 是 JavaScript 測試框架(如 Jest、Mocha、Jasmine、Vitest 等)中的核心函數,用于組織和分組測試用例
describe('復雜組件測試', () => {let scopebeforeEach(() => {// 每個測試前創建新作用域scope = effectScope()})afterEach(() => {// 測試結束后清理所有副作用scope.stop()})it('應正確處理數據加載', async () => {await scope.run(async () => {// 執行包含副作用的測試代碼const { result, isLoading } = useDataFetcher()await flushPromises()expect(isLoading.value).toBe(false)expect(result.value).toEqual({ /* ... */ })})})it('應處理錯誤狀態', async () => {// ...})
})

說明:測試用例中使用effectScope能避免狀態污染、自動清理復雜副作用、支持異步、嵌套作用域管理測試等優勢


五、總結

effectScope是管理復雜副作用的終極解決方案。通過它,您可以

  • 將相關副作用組織到邏輯單元中

  • 通過單個stop()調用清理所有資源

  • 創建自包含的可復用邏輯單元

  • 確保組件卸載時完全清理

  • 簡化測試和狀態管理

在以下場景中優先考慮使用effectScope:

  • 包含3個以上副作用的組件

  • 需要管理定時器/事件監聽的可復用邏輯

  • 涉及多個響應式依賴的復雜表單

  • 需要在組件間共享的有狀態邏輯

  • 需要精確控制副作用的測試用例

請添加圖片描述

掌握effectScope將使您的Vue3應用更健壯、更易維護,特別在處理復雜場景時,它能顯著提升代碼質量和開發體驗。

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

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

相關文章

Docker 中的動態配置:docker update 命令與環境變量管理

Docker 中的動態配置&#xff1a;docker update 命令與環境變量管理 在 Docker 容器的日常管理中&#xff0c;動態調整配置以適應業務需求變化是常見的操作。docker update 命令作為 Docker 平臺的重要工具&#xff0c;為運行中的容器提供了便捷的配置調整方式&#xff0c;而環…

ELK 使用教程采集系統日志

作者&#xff1a;小凱 沉淀、分享、成長&#xff0c;讓自己和他人都能有所收獲&#xff01; 本文的宗旨在于通過易于上手實操的方式&#xff0c;教會讀者完成系統ELK日志采集的對接和使用。那你知道對于一個系統的上線考察&#xff0c;必備的幾樣東西是什么嗎&#xff1f;其實這…

小程序部分pai

wx.setClipboardData 這是微信小程序提供的 API&#xff0c;用于將數據復制到剪貼板。 Page({data: {clientInfo: {email: exampleexample.com // 假設的郵箱數據}},// 復制郵箱到剪貼板copyEmail: function() {wx.setClipboardData({data: this.data.clientInfo.email,success…

【解決方案】鴻蒙 / 礦鴻系統 Shell 無故退出問題(息屏導致)詳解

平臺環境 OpenHarmony 版本&#xff1a;4.1 release開發板&#xff1a;DAYU / RK3568調試工具&#xff1a;hdc 在使用 OpenHarmony 4.1 Release&#xff08;礦鴻系統&#xff09;進行開發時&#xff0c;遇到這樣的問題&#xff1a; &#x1f6a8; Shell 會在一段時間后自動退出…

Data Analysis TTAD=>CNN-BiGRU-MSA

TTAO 預處理、CNN-BiGRU-MSA 模型 時序數據回歸分析時序數據分析方法&#xff0c;特點&#xff1a;TTAO 預處理&#xff1a;通過三角拓撲結構增強時序特征的局部和全局關系混合模型架構&#xff1a;CNN 層提取局部特征模式BiGRU 捕獲雙向時序依賴多頭自注意力機制進行序列建模…

python-字典、集合、序列切片、字符串操作(筆記)

一、字符串常見操作&#xff08;重點&#xff09;?1.?2.字符串無法修改#錯誤示范 str1"djskds" str1[2]"3"3.?str1"abcand" # 輸出3 print(str1.index("and"))4.?str1"abcand" newStrstr1.replace("and",&quo…

【Android】EditText使用和監聽

三三想成為安卓糕手 一&#xff1a;用戶登錄校驗 1&#xff1a;EditText文本輸入框<EditTextandroid:id"id/et_user_name"android:layout_width"match_parent"android:layout_height"wrap_content"android:inputType"number"androi…

SQL 中根據當前時間動態計算日期范圍

在 SQL 中寫“動態時間”通常是指根據當前時間動態計算日期范圍&#xff0c;而不是寫死固定日期。以下是幾種常見寫法&#xff08;以 SQL Server / MySQL / PostgreSQL 為例&#xff09;&#xff1a;1. 獲取當前時間-- SQL Server SELECT GETDATE() AS now-- MySQL SELECT NOW(…

react-redux 類組件的 connect

store 目錄下 store/reducer.js import * as actionTypes from ./constantsconst initalState {counter: 100,banners: [],recommends: [] }/*** 定義reducer函數&#xff1a;純函數* param 參數一&#xff1a;store中目前保存的state* param 參數二&#xff1a;通過 dispatch…

數據分布是如何影響目標檢測精度

文章目錄一、研究背景與目標模型效果提升數據集優化二、研究問題明細各方向的關聯性與核心邏輯1. 高質量數據集的高效篩選與主動學習應用2. 基于推理結果的數據補充與增強方向優化3. 多類別場景下目標尺度與模型精度的關聯性4. 損失函數與數據增強對精度的量化影響5. 目標類型專…

高效批量轉換Java接口為MCP服務:降低重復勞動的實戰指南

高效批量轉換Java接口為MCP服務:降低重復勞動的實戰指南 在AI大模型技術飛速發展的今天,企業需要將現有Java接口快速適配為模型計算協議(MCP,Model Calculation Protocol)服務,以便與大模型生態無縫對接。然而,手動逐個轉換接口不僅耗時耗力,還容易因人為疏忽導致錯誤…

Eclipse Debug 配置指南

Eclipse Debug 配置指南 引言 Eclipse 作為一款功能強大的集成開發環境(IDE),在Java開發者中享有盛譽。在開發過程中,調試功能是必不可少的。本文將詳細介紹如何在Eclipse中配置調試環境,以便更高效地進行代碼調試。 1. 開發環境準備 在開始配置Eclipse調試環境之前,…

modelscope ProxyError: HTTPSConnectionPool(host=‘www.modelscope.cn‘, port=443)

目錄 Windows CMD&#xff1a; powershell Linux / macOS / Git Bash&#xff1a; win11 設置全局系統變量代理 modelscope ProxyError: HTTPSConnectionPool(hostwww.modelscope.cn, port443) 報錯&#xff1a; requests.exceptions.ProxyError: HTTPSConnectionPool(host…

Python學習之——序列化與反序列化

Python學習之——序列化與反序列化yaml & json & xmlyamljsonPython自帶Json庫xml一個綜合示例pickle & msgpack & marshalpicklemsgpackmarshal自定義導出py文件一個導出py文件的示例yaml & json & xml YAML & JSON &XML 如何選擇 yaml Py…

設計模式之代理模式:掌控對象訪問的優雅之道

代理模式&#xff1a;掌控對象訪問的優雅之道 引言&#xff1a;設計模式的重要性 在軟件開發中&#xff0c;設計模式是解決常見問題的可復用方案&#xff0c;它們如同建筑師的藍圖&#xff0c;為開發者提供了經過驗證的最佳實踐。在23種經典設計模式中&#xff0c;代理模式因其…

sqli-labs靶場通關筆記:第18-19關 HTTP頭部注入

第18關 User-Agent注入登錄正確的用戶名密碼&#xff0c;它會將User-Agent的信息回顯到頁面上。猜測UA頭可能存在注入點。利用bp抓包&#xff0c;在UA頭后面加一個單引號&#xff0c;發現報錯了。觀察報錯信息&#xff0c;顯示nearxx,admin)&#xff0c;推測后面應該還有兩個參…

基于按鍵開源MultiButton框架深入理解代碼框架(三)(指針的深入理解與應用)

文章目錄3、分析代碼3.3 按鍵的插入3.4 按鍵的刪除3.5 繼續分析狀態機核心理解4、寫在最后的總結5、思想感悟篇6、慈悲不渡自絕人3、分析代碼 3.3 按鍵的插入 // Button handle list headstatic Button* head_handle NULL;/*** brief Start the button work, add the handle…

ACOUSLIC-AI挑戰報告:基于低收入國家盲掃超聲數據的胎兒腹圍測量|文獻速遞-醫學影像算法文獻分享

Title題目ACOUSLIC-AI challenge report: Fetal abdominal circumferencemeasurement on blind-sweep ultrasound data from low-income countriesACOUSLIC-AI挑戰報告&#xff1a;基于低收入國家盲掃超聲數據的胎兒腹圍測量01文獻速遞介紹胎兒生長受限&#xff08;FGR&#xf…

集群聊天服務器各個類進行詳解

1.dh.h類定義概要類名&#xff1a; MySQL功能&#xff1a; 簡化MySQL的連接、查詢和更新操作&#xff0c;提供接口給上層應用使用。成員變量private:MYSQL *_conn;_conn&#xff1a;指向MYSQL結構體的指針&#xff0c;用于代表數據庫連接實例。由mysql_init()初始化&#xff0c…

電纜安全雙保險:不止防盜,更能防觸電的塔能智慧照明守護方案

城市照明、地下車庫以及園區路燈所涉及的電纜安全問題&#xff0c;向來都是運維管理方面頗為棘手的難題。在傳統的運維管理模式之下&#xff0c;電纜一旦被盜&#xff0c;那么所造成的影響可不小&#xff0c;一方面會帶來直接的經濟損失&#xff0c;另一方面還極有可能因為線路…