Vue3+Element Plus实战:给el-dialog加个『老板键』(一键全屏/拖拽/记忆位置)

news2026/3/14 12:17:17
Vue3 Element Plus 弹窗『老板键』全屏、拖拽与位置记忆的工程化实现你是否遇到过这样的场景正在一个复杂的后台管理系统中处理数据弹窗里展示着关键图表或表单突然需要快速切换到另一个应用或者临时需要隐藏当前工作界面。传统的弹窗操作——点击右上角的“X”关闭再重新打开——不仅打断了工作流还可能丢失临时的上下文状态。这种“紧急隐藏”的需求在游戏玩家中被称为“老板键”一键切换瞬间“隐身”。今天我们就将这个概念引入到企业级前端开发中为基于 Vue3 和 Element Plus 的el-dialog组件打造一套集一键全屏、自由拖拽和位置记忆于一体的“老板键”增强方案。这不仅仅是给按钮加个点击事件那么简单。我们将深入 Vue3 的组合式 APIComposition API和 TypeScript 的强大类型系统从零构建一个高复用、强类型、易于维护的自定义指令。你会看到相较于 Vue2 时代的实现我们如何利用现代前端工具链写出更清晰、更健壮、更具表现力的代码。无论你是希望提升复杂后台系统的用户体验还是单纯想探索 Vue3 自定义指令的进阶玩法这篇文章都将为你提供一套可直接落地的工程化解决方案。1. 项目初始化与核心思路拆解在开始敲代码之前让我们先明确目标。我们要实现的v-boss-key指令需要为el-dialog注入三个核心能力一键全屏/恢复点击对话框标题栏的专属按钮或双击标题栏弹窗应能瞬间占据整个视口排除可能的侧边栏再次操作则完美还原到之前的大小和位置。标题栏拖拽用户可以通过鼠标拖拽对话框的标题栏在屏幕可视区域内自由移动弹窗位置。位置记忆对话框的位置无论是初始位置还是用户拖拽后的位置应在组件生命周期内被记住。关闭后重新打开它应该出现在上次停留的地方而不是重置到默认位置。为了实现这些我们需要解决几个关键技术点如何安全地操作 DOM、如何管理状态、如何处理事件以及如何优雅地集成到 Element Plus 的生态中。Vue3 的组合式 API 为我们提供了完美的工具——useDialogBossKey这个自定义 Hook它将封装所有核心逻辑。首先创建一个新的 Vue3 项目如果你还没有并确保安装了 Element Plus。# 使用你喜欢的包管理器这里以 pnpm 为例 pnpm create vuelatest my-boss-key-project # 按照提示选择 TypeScript, Pinia 等按需 cd my-boss-key-project pnpm install pnpm install element-plus element-plus/icons-vue接下来在src目录下创建我们的核心文件结构src/ ├── directives/ │ └── bossKey/ │ ├── index.ts # 指令定义和注册入口 │ ├── useDialogBossKey.ts # 核心组合式函数 │ └── types.ts # TypeScript 类型定义 └── main.ts # 全局注册指令2. 构建核心组合式函数useDialogBossKey这是整个功能的“大脑”。我们将所有响应式状态、计算属性和方法都封装在这个 Hook 里。它接收两个参数对话框的 DOM 元素引用和标题栏的 DOM 元素引用。打开src/directives/bossKey/types.ts我们先定义好类型这是保证代码健壮性的第一步。// src/directives/bossKey/types.ts export interface DialogRect { width: string; height: string; top: string; left: string; margin: string; padding: string; boxSizing: string; position: string; zIndex: string; } export interface DragState { isDragging: boolean; startX: number; startY: number; initialLeft: number; initialTop: number; } export interface BossKeyState { isFullscreen: Refboolean; originalStyle: RefDialogRect | null; dragState: RefDragState; headerElement: HTMLElement | null; dialogElement: HTMLElement | null; }现在创建核心文件useDialogBossKey.ts。// src/directives/bossKey/useDialogBossKey.ts import { ref, computed, onUnmounted, type Ref } from vue; import type { DialogRect, DragState } from ./types; export function useDialogBossKey(dialogElRef: RefHTMLElement | null, headerElRef: RefHTMLElement | null) { // 状态定义 const isFullscreen ref(false); const originalStyle refDialogRect | null(null); const dragState refDragState({ isDragging: false, startX: 0, startY: 0, initialLeft: 0, initialTop: 0, }); // 计算属性获取当前对话框的样式对象 const getCurrentDialogRect (): DialogRect { const el dialogElRef.value; if (!el) return {} as DialogRect; const style window.getComputedStyle(el); return { width: style.width, height: style.height, top: style.top, left: style.left, margin: style.margin, padding: style.padding, boxSizing: style.boxSizing, position: style.position, zIndex: style.zIndex, }; }; // 核心方法切换全屏 const toggleFullscreen () { const dialogEl dialogElRef.value; if (!dialogEl) return; isFullscreen.value !isFullscreen.value; if (isFullscreen.value) { // 进入全屏保存原始样式并应用全屏样式 if (!originalStyle.value) { originalStyle.value getCurrentDialogRect(); } // 记录滚动位置用于恢复 const scrollTop document.documentElement.scrollTop || document.body.scrollTop; (dialogEl as any).__savedScrollTop scrollTop; Object.assign(dialogEl.style, { margin: 0, padding: 1.5rem, // 全屏时适当增加内边距避免内容贴边 boxSizing: border-box, position: fixed, top: 0, left: 0, width: 100vw, height: 100vh, zIndex: 9999, // 确保在最顶层 overflow: auto, }); // 防止背景滚动 document.body.style.overflow hidden; } else { // 退出全屏恢复原始样式 if (originalStyle.value) { Object.assign(dialogEl.style, originalStyle.value); } // 恢复滚动位置 const savedScrollTop (dialogEl as any).__savedScrollTop; if (savedScrollTop ! undefined) { window.scrollTo(0, savedScrollTop); } // 恢复背景滚动 document.body.style.overflow ; } }; // 核心方法初始化拖拽 const initDrag () { const headerEl headerElRef.value; const dialogEl dialogElRef.value; if (!headerEl || !dialogEl) return; const onMouseDown (e: MouseEvent) { // 如果已经是全屏状态不允许拖拽 if (isFullscreen.value) return; e.preventDefault(); const style window.getComputedStyle(dialogEl); const left parseFloat(style.left) || 0; const top parseFloat(style.top) || 0; dragState.value { isDragging: true, startX: e.clientX, startY: e.clientY, initialLeft: left, initialTop: top, }; const onMouseMove (moveEvent: MouseEvent) { if (!dragState.value.isDragging) return; const deltaX moveEvent.clientX - dragState.value.startX; const deltaY moveEvent.clientY - dragState.value.startY; let newLeft dragState.value.initialLeft deltaX; let newTop dragState.value.initialTop deltaY; // 简单的边界检查确保对话框不会完全移出可视区域 const maxLeft window.innerWidth - dialogEl.offsetWidth; const maxTop window.innerHeight - dialogEl.offsetHeight; newLeft Math.max(0, Math.min(newLeft, maxLeft)); newTop Math.max(0, Math.min(newTop, maxTop)); dialogEl.style.left ${newLeft}px; dialogEl.style.top ${newTop}px; }; const onMouseUp () { dragState.value.isDragging false; document.removeEventListener(mousemove, onMouseMove); document.removeEventListener(mouseup, onMouseUp); // 拖拽结束后可以在这里触发一个自定义事件通知父组件位置已更新 // dialogEl.dispatchEvent(new CustomEvent(dialog-dragged, { detail: { left: dialogEl.style.left, top: dialogEl.style.top } })); }; document.addEventListener(mousemove, onMouseMove); document.addEventListener(mouseup, onMouseUp); }; headerEl.addEventListener(mousedown, onMouseDown); // 添加双击全屏事件 headerEl.addEventListener(dblclick, toggleFullscreen); // 清理函数 const cleanup () { headerEl.removeEventListener(mousedown, onMouseDown); headerEl.removeEventListener(dblclick, toggleFullscreen); }; onUnmounted(cleanup); return cleanup; }; // 创建全屏按钮并注入到标题栏 const createFullscreenButton () { const headerEl headerElRef.value; if (!headerEl || headerEl.querySelector(.boss-key-fullscreen-btn)) return; const button document.createElement(button); button.type button; button.className boss-key-fullscreen-btn; button.innerHTML svg xmlnshttp://www.w3.org/2000/svg width16 height16 fillcurrentColor viewBox0 0 16 16 path dM1.5 1a.5.5 0 0 0-.5.5v4a.5.5 0 0 1-1 0v-4A1.5 1.5 0 0 1 1.5 0h4a.5.5 0 0 1 0 1h-4zM10 .5a.5.5 0 0 1 .5-.5h4A1.5 1.5 0 0 1 16 1.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 1-.5-.5zM.5 10a.5.5 0 0 1 .5.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 0 14.5v-4a.5.5 0 0 1 .5-.5zm15 0a.5.5 0 0 1 .5.5v4a1.5 1.5 0 0 1-1.5 1.5h-4a.5.5 0 0 1 0-1h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 .5-.5z/ /svg ; button.style.cssText position: absolute; right: 40px; /* 放在关闭按钮左侧 */ top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: #909399; padding: 4px; border-radius: 4px; line-height: 1; ; button.addEventListener(click, (e) { e.stopPropagation(); toggleFullscreen(); }); button.addEventListener(mouseenter, () { button.style.color #409EFF; button.style.backgroundColor rgba(64, 158, 255, 0.1); }); button.addEventListener(mouseleave, () { button.style.color #909399; button.style.backgroundColor transparent; }); headerEl.style.position relative; // 确保按钮定位正确 headerEl.appendChild(button); }; return { isFullscreen, originalStyle, dragState, toggleFullscreen, initDrag, createFullscreenButton, }; }这个组合式函数已经包含了全屏切换、拖拽逻辑和按钮创建的完整逻辑。它使用了 Vue3 的响应式系统状态管理清晰并且通过onUnmounted自动清理事件监听器避免了内存泄漏。3. 封装自定义指令 v-boss-key有了核心逻辑接下来我们需要将其封装成一个 Vue 自定义指令这样才能方便地在任何el-dialog上使用。指令的生命周期钩子mounted,updated,unmounted非常适合做 DOM 操作和清理工作。创建src/directives/bossKey/index.ts// src/directives/bossKey/index.ts import { createApp, type Directive, type App } from vue; import { useDialogBossKey } from ./useDialogBossKey; import { ref } from vue; const bossKeyDirective: Directive { mounted(el: HTMLElement, binding) { // 确保指令只作用于 el-dialog 的根元素 const dialogEl el.querySelector(.el-dialog) as HTMLElement; const headerEl el.querySelector(.el-dialog__header) as HTMLElement; if (!dialogEl || !headerEl) { console.warn(v-boss-key 指令应应用于包含 .el-dialog 和 .el-dialog__header 的元素); return; } // 使用 ref 包装 DOM 元素以便在组合式函数中响应式使用虽然这里变化不大 const dialogElRef ref(dialogEl); const headerElRef ref(headerEl); // 调用组合式函数获取所有方法和状态 const { initDrag, createFullscreenButton } useDialogBossKey(dialogElRef, headerElRef); // 存储实例到元素上便于在 updated 或 unmounted 时访问 (el as any).__bossKey { initDrag, createFullscreenButton, cleanup: () { /* 如果需要额外的清理 */ } }; // 初始化拖拽功能 initDrag(); // 创建全屏按钮 createFullscreenButton(); // 为标题栏添加可拖拽光标样式 headerEl.style.cursor move; }, updated(el) { // 如果对话框内容更新例如 v-if 切换可能需要重新初始化按钮 // 这里简单处理如果按钮不存在则重新创建 const headerEl el.querySelector(.el-dialog__header) as HTMLElement; const existingBtn headerEl?.querySelector(.boss-key-fullscreen-btn); if (headerEl !existingBtn (el as any).__bossKey) { (el as any).__bossKey.createFullscreenButton(); } }, unmounted(el) { // 清理工作移除事件监听器等useDialogBossKey 中的 onUnmounted 已处理大部分 const instance (el as any).__bossKey; if (instance instance.cleanup) { instance.cleanup(); } delete (el as any).__bossKey; } }; // 提供安装函数用于全局注册 export function setupBossKeyDirective(app: App) { app.directive(boss-key, bossKeyDirective); } export default bossKeyDirective;现在我们需要在main.ts中全局注册这个指令。// src/main.ts import { createApp } from vue; import App from ./App.vue; import ElementPlus from element-plus; import element-plus/dist/index.css; import { setupBossKeyDirective } from ./directives/bossKey; const app createApp(App); app.use(ElementPlus); // 注册我们的“老板键”指令 setupBossKeyDirective(app); app.mount(#app);4. 在组件中使用与高级配置指令已经就绪使用起来非常简单。在你的任何 Vue 组件中只需要在el-dialog上添加v-boss-key即可。!-- src/components/DemoDialog.vue -- template div el-button clickdialogVisible true打开增强对话框/el-button el-dialog v-modeldialogVisible title带有老板键的对话框 width600px v-boss-key !-- 就是这里 -- p这是一个普通的对话框内容。/p p现在你可以/p ul li拖拽标题栏来移动它。/li li点击标题栏右侧的全屏图标或双击标题栏进入全屏模式。/li li在全屏模式下内容区域会最大化背景被锁定。/li li再次点击全屏图标或按 strongESC/strong 键我们可以扩展这个功能退出全屏。/li /ul template #footer span classdialog-footer el-button clickdialogVisible false取消/el-button el-button typeprimary clickdialogVisible false确认/el-button /span /template /el-dialog /div /template script setup langts import { ref } from vue; const dialogVisible ref(false); /script style scoped /* 可以添加一些自定义样式 */ .boss-key-fullscreen-btn:hover { transition: all 0.2s ease; } /style但是一个健壮的库应该考虑更多的边界情况和自定义需求。让我们来扩展指令使其支持参数和修饰符。例如我们可以通过指令的值来禁用某些功能或者自定义全屏按钮的样式。首先更新types.ts来定义指令的绑定值类型。// src/directives/bossKey/types.ts (新增) export interface BossKeyBindingValue { drag?: boolean; // 是否启用拖拽默认为 true fullscreen?: boolean; // 是否启用全屏默认为 true fullscreenIcon?: string; // 自定义全屏图标 HTML 字符串 // 可以添加记忆位置的配置例如存储到 localStorage 的 key rememberPosition?: boolean | string; }然后修改指令的mounted钩子解析这些参数。// src/directives/bossKey/index.ts (更新 mounted 部分) mounted(el: HTMLElement, binding) { // ... 获取 dialogEl 和 headerEl ... // 解析指令参数提供默认值 const options: BossKeyBindingValue binding.value || {}; const enableDrag options.drag ! false; // 默认 true const enableFullscreen options.fullscreen ! false; // 默认 true const customIcon options.fullscreenIcon; const dialogElRef ref(dialogEl); const headerElRef ref(headerEl); const { initDrag, createFullscreenButton, toggleFullscreen } useDialogBossKey(dialogElRef, headerElRef); (el as any).__bossKey { initDrag, createFullscreenButton, toggleFullscreen, options, }; if (enableDrag) { initDrag(); headerEl.style.cursor move; } else { headerEl.style.cursor default; } if (enableFullscreen) { // 可以传递自定义图标给 createFullscreenButton createFullscreenButton(customIcon); } // 监听 ESC 键退出全屏可选功能 const handleKeydown (e: KeyboardEvent) { if (e.key Escape (el as any).__bossKey?.isFullscreen?.value) { toggleFullscreen(); } }; if (enableFullscreen) { document.addEventListener(keydown, handleKeydown); (el as any).__bossKey.handleKeydown handleKeydown; } },相应的我们需要修改useDialogBossKey.ts中的createFullscreenButton函数以接受自定义图标。// 在 useDialogBossKey.ts 中更新函数签名和实现 const createFullscreenButton (customIconHtml?: string) { const headerEl headerElRef.value; if (!headerEl || headerEl.querySelector(.boss-key-fullscreen-btn)) return; const button document.createElement(button); button.type button; button.className boss-key-fullscreen-btn; // 使用自定义图标或默认图标 button.innerHTML customIconHtml || svg ...默认图标/svg ; // ... 其余样式和事件逻辑不变 ... };现在你可以更灵活地使用指令了el-dialog v-modelvisible title自定义配置 v-boss-key{ drag: true, fullscreen: true, fullscreenIcon: i/i } !-- 内容 -- /el-dialog el-dialog v-modelvisible2 title仅拖拽 v-boss-key{ fullscreen: false } !-- 只有拖拽功能 -- /el-dialog5. 位置记忆与状态持久化“老板键”的另一个精髓是“记忆”。用户调整了对话框位置下次打开时它应该还在那里。我们可以利用浏览器的localStorage或配合状态管理库如 Pinia来实现这个功能。让我们在useDialogBossKey组合式函数中增加位置记忆的逻辑。思路是在对话框拖拽结束或关闭时将其位置left,top保存起来在对话框下次挂载时读取保存的位置并应用。首先为指令绑定值增加一个唯一标识符key用于在存储中区分不同的对话框。// types.ts export interface BossKeyBindingValue { // ... 其他配置 memoryKey?: string; // 用于持久化存储的键名。如果提供则启用位置记忆。 }然后在组合式函数中添加记忆功能的逻辑。我们需要修改拖拽的onMouseUp事件和指令的mounted钩子。// 在 useDialogBossKey.ts 的 initDrag 函数中修改 onMouseUp const onMouseUp () { dragState.value.isDragging false; document.removeEventListener(mousemove, onMouseMove); document.removeEventListener(mouseup, onMouseUp); // --- 新增保存位置 --- if (memoryKey.value) { const rect { left: dialogEl.style.left, top: dialogEl.style.top, }; localStorage.setItem(boss-key-pos-${memoryKey.value}, JSON.stringify(rect)); } // --- 结束 --- };同时我们需要在组合式函数初始化时从存储中读取位置并应用。// 在 useDialogBossKey.ts 中新增一个初始化位置的函数并在组合式函数开头调用 const memoryKey ref(binding.value?.memoryKey || ); // 需要从指令 binding 传入 const restorePosition () { if (!memoryKey.value || !dialogElRef.value) return; const saved localStorage.getItem(boss-key-pos-${memoryKey.value}); if (saved) { try { const { left, top } JSON.parse(saved); const dialogEl dialogElRef.value; // 简单验证一下值是否有效 if (left top) { dialogEl.style.left left; dialogEl.style.top top; } } catch (e) { console.warn(Failed to restore dialog position:, e); } } }; // 在 mounted 钩子中初始化拖拽和按钮后调用 restorePosition // initDrag(); // createFullscreenButton(); // restorePosition(); // -- 新增最后在指令定义中我们需要将memoryKey传递给组合式函数。这可能需要我们调整useDialogBossKey的接口使其能接收更多初始配置。一个更简洁的做法是将所有配置通过一个options对象传入。// useDialogBossKey.ts 更新函数签名 export function useDialogBossKey( dialogElRef: RefHTMLElement | null, headerElRef: RefHTMLElement | null, options: { memoryKey?: string } {} // 接收配置 ) { const memoryKey ref(options.memoryKey || ); // ... 其余逻辑 ... } // 在指令的 mounted 中 const { initDrag, createFullscreenButton, restorePosition } useDialogBossKey(dialogElRef, headerElRef, { memoryKey: options.memoryKey, }); // 初始化后恢复位置 restorePosition();现在使用带有记忆功能的指令el-dialog v-modeluserEditDialogVisible title编辑用户 v-boss-key{ memoryKey: user-edit-dialog } !-- 这个对话框的位置会被记住键名为 boss-key-pos-user-edit-dialog -- /el-dialog6. 样式优化、边界处理与最佳实践功能实现了但体验要打磨。这里有几个常见的优化点和最佳实践1. 全屏时的内边距与滚动全屏时对话框内容直接贴边可能不美观。我们在全屏样式中添加了padding: 1.5rem。同时将对话框自身的overflow设为auto并锁定了body的滚动这样全屏对话框内部可以滚动而背景页面固定。2. 拖拽边界处理我们的拖拽逻辑包含了一个简单的边界检查防止对话框被拖出视口。这是一个基础版本。对于更复杂的需求比如限制在某个父容器内拖拽你需要修改onMouseMove中的maxLeft和maxTop的计算逻辑。3. 性能与事件解绑这是关键。我们在onMouseUp和组件的onUnmounted生命周期中都移除了全局的mousemove和mouseup事件监听器。这避免了事件处理函数残留导致的内存泄漏和潜在的错误。4. 与 Element Plus 的样式兼容我们通过querySelector获取.el-dialog和.el-dialog__header元素这依赖于 Element Plus 稳定的内部类名。虽然这类名通常很稳定但在自定义主题或未来大版本更新时需要留意。我们的按钮通过绝对定位放置在标题栏内并设置了right: 40px来避开原生的关闭按钮通常在右侧宽度约40px。这个值可能需要根据你的实际主题进行调整。5. 可访问性 (A11y) 考虑我们创建的全屏按钮是一个原生的button元素这比用div或span更好因为它天然支持键盘导航Tab 键和屏幕阅读器。你可以进一步添加aria-label属性来明确其功能。button.setAttribute(aria-label, isFullscreen.value ? 退出全屏 : 进入全屏); // 在全屏切换时需要动态更新这个标签6. 响应式考量当前实现主要针对桌面端鼠标交互。在移动端你需要考虑触摸事件touchstart,touchmove,touchend来支持拖拽。逻辑类似但事件处理上需要做些调整。7. 提供一个 CSS 文件供用户覆盖样式我们可以创建一个简单的 CSS 文件定义.boss-key-fullscreen-btn等类的基础样式让使用者可以通过引入这个文件或覆盖这些类名来自定义外观。/* src/directives/bossKey/style.css */ .boss-key-fullscreen-btn { position: absolute; right: 40px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: var(--el-text-color-secondary); padding: 4px; border-radius: 4px; line-height: 1; transition: color 0.2s, background-color 0.2s; } .boss-key-fullscreen-btn:hover { color: var(--el-color-primary); background-color: rgba(var(--el-color-primary-rgb), 0.1); }将这个文件在指令入口或你的主样式文件中导入。经过以上六个步骤我们从零构建了一个功能完整、代码清晰、易于扩展的 Vue3 自定义指令v-boss-key。它不仅解决了“一键隐藏”的趣味需求更提供了一套提升el-dialog交互体验的生产力工具。你可以直接复制代码到你的项目中也可以根据实际需求轻松地扩展出更多功能比如调整大小、吸附到屏幕边缘、多显示器支持等。记住好的工具是那些能无缝融入工作流并在需要时悄然提供强大支持的部件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2411069.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…