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.tpcf.cn/diannao/91580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;另一方面还极有可能因为线路…