vue3-element-admin实现同一个菜单多标签
原框架代码: 赵志江/huzhushan-vue3-element-admin
目录
TagsBar实现
实现同一个菜单多标签
device/detail/:id,不同参数时页面缓存删不掉的问题
TagsBar实现
在src/layout/components/下新建目录Tagsbar,新建index.vue
<template><div class="tags-container" :class="{ hide: !isTagsbarShow }"><el-scrollbarref="scrollContainer":vertical="false"class="scroll-container"@wheel.prevent="onScroll"><router-linkv-for="(tag, i) in tagList":key="tag.fullPath":to="tag":ref="el => setItemRef(i, el)"customv-slot="{ navigate, isExactActive }"><divclass="tags-item":class="isExactActive? 'active' : ''"@click="navigate"@click.middle="closeTag(tag)"@contextmenu.prevent="openMenu(tag, $event)"><span class="title">{{ $t(tag.title) }}</span><el-iconv-if="!isAffix(tag)"class="el-icon-close"@click.prevent.stop="closeTag(tag)"><Close /></el-icon></div></router-link></el-scrollbar></div><ulv-show="visible":style="{ left: left + 'px', top: top + 'px' }"class="contextmenu"><!-- <li @click="refreshSelectedTag(selectedTag)">{{ $t('tags.refresh') }}</li> --><li v-if="!isAffix(selectedTag)" @click="closeTag(selectedTag)">{{ $t('tags.close') }}</li><li @click="closeOtherTags">{{ $t('tags.other') }}</li><li @click="closeLeftTags">{{ $t('tags.left') }}</li><li @click="closeRightTags">{{ $t('tags.right') }}</li><li @click="closeAllTags">{{ $t('tags.all') }}</li></ul>
</template><script>
import { defineComponent, computed, getCurrentInstance } from 'vue'
import { useTags } from './hooks/useTags'
import { useContextMenu } from './hooks/useContextMenu'
import { useLayoutsettings } from '@/pinia/modules/layoutSettings'export default defineComponent({name: 'Tagsbar',mounted() {},setup() {const instance = getCurrentInstance()instance.appContext.config.globalProperties.$tagsbar = thisconst defaultSettings = useLayoutsettings()const isTagsbarShow = computed(() => defaultSettings.tagsbar.isShow)const tags = useTags()const contextMenu = useContextMenu(tags.tagList)const onScroll = e => {tags.handleScroll(e)contextMenu.closeMenu.value()}return {isTagsbarShow,onScroll,...tags,...contextMenu}},
})
</script><style lang="scss" scoped>
.tags-container {height: 32px;width: 100%;background: #fff;border-bottom: 1px solid #e0e4ef;&.hide {display: none;}.scroll-container {white-space: nowrap;overflow: hidden;::v-deep(.el-scrollbar__bar) {bottom: 0px;}}.tags-item {display: inline-block;height: 32px;line-height: 32px;box-sizing: border-box;border-left: 1px solid #e6e6e6;border-right: 1px solid #e6e6e6;color: #5c5c5c;background: #fff;padding: 0 8px;font-size: 12px;margin-left: -1px;vertical-align: bottom;cursor: pointer;&:first-of-type {margin-left: 15px;}&:last-of-type {margin-right: 15px;}&.active {color: #303133;background: #f5f5f5;}.title {display: inline-block;vertical-align: top;max-width: 200px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}.el-icon-close {color: #5c5c5c;margin-left: 8px;width: 16px;height: 16px;vertical-align: -2px;border-radius: 50%;text-align: center;transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);transform-origin: 100% 50%;&:before {transform: scale(0.8);display: inline-block;vertical-align: -2px;}&:hover {background-color: #333;color: #fff;}}}
}
.contextmenu {margin: 0;background: #fff;z-index: 3000;position: fixed;list-style-type: none;padding: 5px 0;border-radius: 4px;font-size: 12px;font-weight: 400;color: #333;box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);white-space: nowrap;li {margin: 0;padding: 8px 16px;cursor: pointer;&:hover {background: #eee;}}
}
</style>
新建hooks目录,新建useTags.js
import { storeToRefs } from 'pinia'
import { useTags as useTagsbar } from '@/pinia/modules/tags'
import { useScrollbar } from './useScrollbar'
import { watch, computed, ref, nextTick, onBeforeMount } from 'vue'
import { useRouter } from 'vue-router'export const isAffix = tag => {return !!tag.meta && !!tag.meta.affix
}export const useTags = () => {const tagStore = useTagsbar()const { tagList } = storeToRefs(tagStore)const { addTag, delTag, saveActivePosition, updateTagList } = tagStoreconst router = useRouter()const route = router.currentRouteconst routes = computed(() => router.getRoutes())const tagsItem = ref([])const setItemRef = (i, el) => {tagsItem.value[i] = el}const scrollbar = useScrollbar(tagsItem)watch(() => tagList.value.length,() => {tagsItem.value = []})const filterAffixTags = routes => {return routes.filter(route => isAffix(route))}const initTags = () => {const affixTags = filterAffixTags(routes.value)for (const tag of affixTags) {if (tag.name) {addTag(tag)}}// 不在路由中的所有标签,需要删除const noUseTags = tagList.value.filter(tag =>routes.value.every(route => route.name !== tag.name))noUseTags.forEach(tag => {delTag(tag)})}const addTagList = () => {const tag = route.valueif (!!tag.name && tag.matched[0].components.default.name === 'layout') {addTag(tag)}}const saveTagPosition = tag => {const index = tagList.value.findIndex(item => item.fullPath === tag.fullPath)saveActivePosition(Math.max(0, index))}const moveToCurrentTag = () => {nextTick(() => {for (const tag of tagsItem.value) {if (!!tag && tag.to.path === route.value.path) {scrollbar.moveToTarget(tag)if (tag.to.fullPath !== route.value.fullPath) {updateTagList(route.value)}break}}})}onBeforeMount(() => {initTags()addTagList()moveToCurrentTag()})watch(route, (newRoute, oldRoute) => {saveTagPosition(oldRoute) // 保存标签的位置addTagList()moveToCurrentTag()})return {tagList,setItemRef,isAffix,...scrollbar,}
}
useScrollbar.js
import { ref } from 'vue'export const useScrollbar = tagsItem => {const scrollContainer = ref(null)const scrollLeft = ref(0)const doScroll = val => {scrollLeft.value = valscrollContainer.value.setScrollLeft(scrollLeft.value)}const handleScroll = e => {const $wrap = scrollContainer.value.wrapRefif ($wrap.offsetWidth + scrollLeft.value > $wrap.children[0].scrollWidth) {doScroll($wrap.children[0].scrollWidth - $wrap.offsetWidth)return} else if (scrollLeft.value < 0) {doScroll(0)return}const eventDelta = e.wheelDelta || -e.deltaYdoScroll(scrollLeft.value - eventDelta / 4)}const moveToTarget = currentTag => {const $wrap = scrollContainer.value.wrapRefconst tagList = tagsItem.valuelet firstTag = nulllet lastTag = nullif (tagList.length > 0) {firstTag = tagList[0]lastTag = tagList[tagList.length - 1]}if (firstTag === currentTag) {doScroll(0)} else if (lastTag === currentTag) {doScroll($wrap.children[0].scrollWidth - $wrap.offsetWidth)} else {const el = currentTag.$el.nextElementSiblingel.offsetLeft + el.offsetWidth > $wrap.offsetWidth? doScroll(el.offsetLeft - el.offsetWidth): doScroll(0)}}return {scrollContainer,handleScroll,moveToTarget,}
}
useContextMenu.js
import { useTags } from '@/pinia/modules/tags'
import { onMounted, onBeforeUnmount, reactive, toRefs, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { isAffix } from './useTags'export const useContextMenu = tagList => {const router = useRouter()const route = useRoute()const tagsStore = useTags()const state = reactive({visible: false,top: 0,left: 0,selectedTag: {},openMenu(tag, e) {state.visible = truestate.left = e.clientXstate.top = e.clientYstate.selectedTag = tag},closeMenu() {state.visible = false},refreshSelectedTag(tag) {tagsStore.deCacheList(tag)const { fullPath } = tagnextTick(() => {router.replace({path: '/redirect' + fullPath,})})},closeTag(tag) {if (isAffix(tag)) returnconst closedTagIndex = tagList.value.findIndex(item => {return item.path === tag.path})console.log(closedTagIndex)tagsStore.delTag(tag)if (isActive(tag)) {toLastTag(closedTagIndex - 1)}},closeOtherTags() {tagsStore.delOtherTags(state.selectedTag)router.push(state.selectedTag)},closeLeftTags() {state.closeSomeTags('left')},closeRightTags() {state.closeSomeTags('right')},closeSomeTags(direction) {const index = tagList.value.findIndex(item => item.fullPath === state.selectedTag.fullPath)if ((direction === 'left' && index <= 0) ||(direction === 'right' && index >= tagList.value.length - 1)) {return}const needToClose =direction === 'left'? tagList.value.slice(0, index): tagList.value.slice(index + 1)tagsStore.delSomeTags(needToClose)router.push(state.selectedTag)},closeAllTags() {tagsStore.delAllTags()router.push('/')},})const isActive = tag => {return tag.fullPath === route.fullPath}const toLastTag = lastTagIndex => {const lastTag = tagList.value[lastTagIndex]if (lastTag) {router.push(lastTag.fullPath)} else {router.push('/')}}onMounted(() => {document.addEventListener('click', state.closeMenu)})onBeforeUnmount(() => {document.removeEventListener('click', state.closeMenu)})return toRefs(state)
}
在src/pinia/modules下新建tags.js
import { defineStore } from 'pinia'
import { getItem, setItem, removeItem } from '@/utils/storage' //getItem和setItem是封装的操作localStorage的方法
const TAGLIST = 'VEA-TAGLIST'export const useTags = defineStore('tags', {state: () => ({tagList: getItem(TAGLIST) || [],cacheList: [],activePosition: -1,}),actions: {saveActivePosition(index) {this.activePosition = index},addTag({ path, fullPath, name, meta, params, query }) {if (this.tagList.some(v => v.path === path)) return false// 添加tagListconst target = Object.assign({},{ path, fullPath, name, meta, params, query },{title: meta.title || '未命名',fullPath: fullPath || path,})if (this.activePosition === -1) {if (name === 'home') {this.tagList.unshift(target)} else {this.tagList.push(target)}} else {this.tagList.splice(this.activePosition + 1, 0, target)}// 保存到localStoragesetItem(TAGLIST, this.tagList)// 添加cacheListif (this.cacheList.includes(name)) returnif (!meta.noCache) {this.cacheList.push(name)}},deTagList(tag) {// 删除tagListthis.tagList = this.tagList.filter(v => v.path !== tag.path)// 保存到localStoragesetItem(TAGLIST, this.tagList)},deCacheList(tag) {// 删除cacheListthis.cacheList = this.cacheList.filter(v => v !== tag.name)},delTag(tag) {// 删除tagListthis.deTagList(tag)// 删除cacheListthis.deCacheList(tag)},delOtherTags(tag) {this.tagList = this.tagList.filter(v => !!v.meta.affix || v.path === tag.path)// 保存到localStoragesetItem(TAGLIST, this.tagList)this.cacheList = this.cacheList.filter(v => v === tag.name)},delSomeTags(tags) {this.tagList = this.tagList.filter(v => !!v.meta.affix || tags.every(tag => tag.path !== v.path))// 保存到localStoragesetItem(TAGLIST, this.tagList)this.cacheList = this.cacheList.filter(v =>tags.every(tag => tag.name !== v))},delAllTags() {this.tagList = this.tagList.filter(v => !!v.meta.affix)// 保存到localStorageremoveItem(TAGLIST)this.cacheList = []},updateTagList(tag) {const index = this.tagList.findIndex(v => v.path === tag.path)if (index > -1) {this.tagList[index] = Object.assign({}, this.tagList[index], tag)// 保存到localStoragesetItem(TAGLIST, this.tagList)}},clearAllTags() {this.cacheList = []this.tagList = []// 保存到localStorageremoveItem(TAGLIST)},},
})
src/layout/components/Content下新建index.vue,keep-alive组件会根据Component的name来跟include进行匹配,来缓存页面,同样的页面重新进入时不会触发onMounted,只会触发onActivated。
<template><router-view v-slot="{ Component }"><keep-alive :include="cacheList.join(',')"><component :is="Component" :key="key" /></keep-alive></router-view>
</template>
<script>
import { storeToRefs } from 'pinia'
import { computed, defineComponent } from 'vue'
import { useRoute } from 'vue-router'
import { useTags } from '@/pinia/modules/tags'export default defineComponent({setup() {const route = useRoute()const { cacheList } = storeToRefs(useTags())const key = computed(() => route.fullPath)return {cacheList,key,}},
})
</script>
实现同一个菜单多标签
框架通过vue-router来实现页面跳转和菜单展示,下面介绍对一个菜单,如果实现参数不同,显示多个tag。
按如下定义menu
{path: 'detail/:id',name: 'device_detail',component: () => import('@/views/device/detail.vue'),meta: { title: '设备详情', icon: 'el-icon-s-platform' },hidden: true,}
device/detail.vue中动态修改Component的name:
onMounted(() => {ctx.deviceId = parseInt(ctx.$route.params.id)ctx.$options.name = 'device_detail' + ctx.deviceId
})
onActivated(() => {ctx.$options.name = 'device_detail' + ctx.deviceId
})
修改src/pinia/modules/tags.js,修改地方:tag.name 改为 this.getFinalName(tag),即根据参数不同name也不同,name放入cacheList,用于唯一标识一个Component。
import { defineStore } from 'pinia'
import { getItem, setItem, removeItem } from '@/utils/storage' //getItem和setItem是封装的操作localStorage的方法
const TAGLIST = 'VEA-TAGLIST'export const useTags = defineStore('tags', {state: () => ({tagList: getItem(TAGLIST) || [],cacheList: [],activePosition: -1,}),actions: {saveActivePosition(index) {this.activePosition = index},addTag({ path, fullPath, name, meta, params, query }) {if (this.tagList.some(v => v.path === path)) return falsevar title = meta.titleif (name == 'device_detail') {title = title + ' ' + query.name}// 添加tagListconst target = Object.assign({},{ path, fullPath, name, meta, params, query },{title: title || '未命名',fullPath: fullPath || path,})if (this.activePosition === -1) {if (name === 'home') {this.tagList.unshift(target)} else {this.tagList.push(target)}} else {this.tagList.splice(this.activePosition + 1, 0, target)}// 保存到localStoragesetItem(TAGLIST, this.tagList)// 添加cacheListconst finalName = this.getFinalName(target)if (this.cacheList.includes(finalName)) returnif (!meta.noCache) {this.cacheList.push(finalName)}},getFinalName(tag) {if (tag.name == 'device_detail') {return tag.name + tag.params.id}return tag.name},deTagList(tag) {// 删除tagListthis.tagList = this.tagList.filter(v => v.path !== tag.path)// 保存到localStoragesetItem(TAGLIST, this.tagList)},deCacheList(tag) {const name = this.getFinalName(tag)// 删除cacheListthis.cacheList = this.cacheList.filter(v => v !== name)},delTag(tag) {// 删除tagListthis.deTagList(tag)// 删除cacheListthis.deCacheList(tag)},delOtherTags(tag) {this.tagList = this.tagList.filter(v => !!v.meta.affix || v.path === tag.path)// 保存到localStoragesetItem(TAGLIST, this.tagList)const name = this.getFinalName(tag)this.cacheList = this.cacheList.filter(v => v === name)},delSomeTags(tags) {this.tagList = this.tagList.filter(v => !!v.meta.affix || tags.every(tag => tag.path !== v.path))// 保存到localStoragesetItem(TAGLIST, this.tagList)this.cacheList = this.cacheList.filter(v =>tags.every(tag => tag.name !== v))},delAllTags() {this.tagList = this.tagList.filter(v => !!v.meta.affix)// 保存到localStorageremoveItem(TAGLIST)this.cacheList = []},updateTagList(tag) {const index = this.tagList.findIndex(v => v.path === tag.path)if (index > -1) {this.tagList[index] = Object.assign({}, this.tagList[index], tag)// 保存到localStoragesetItem(TAGLIST, this.tagList)}},clearAllTags() {this.cacheList = []this.tagList = []// 保存到localStorageremoveItem(TAGLIST)},},
})
device/detail/:id,不同参数时页面缓存删不掉的问题
现象如下:进入/device/detail/1,再打开/device/detail/2,点击其他标签,删掉/device/detail/2标签,再打开/device/detail/2,此时发现只触发了onActivated方法,没有触发onMounted方法,页面没有重新渲染,keepalive这里的缓存机制不清楚,但是可以知道框架误以为/device/detail/2还在缓存中,直接把缓存中的页面拿过来显示了。
解决方法
对于这种动态菜单的情况,Compnent的key属性增加自增的标识,每次打开标识加1。
修改src/pinia/modules/tags.js,增加detailIndex,在addTag时增加detailIndex的修改
import { defineStore } from 'pinia'
import { getItem, setItem, removeItem } from '@/utils/storage' //getItem和setItem是封装的操作localStorage的方法
const TAGLIST = 'VEA-TAGLIST'export const useTags = defineStore('tags', {state: () => ({tagList: getItem(TAGLIST) || [],cacheList: [],activePosition: -1,detailIndex: {}}),actions: {saveActivePosition(index) {this.activePosition = index},addTag({ path, fullPath, name, meta, params, query }) {if (this.tagList.some(v => v.path === path)) return falsevar title = meta.titleif (name == 'device_detail') {title = title + ' ' + query.name}// 添加tagListconst target = Object.assign({},{ path, fullPath, name, meta, params, query },{title: title || '未命名',fullPath: fullPath || path,})if (this.activePosition === -1) {if (name === 'home') {this.tagList.unshift(target)} else {this.tagList.push(target)}} else {this.tagList.splice(this.activePosition + 1, 0, target)}// 保存到localStoragesetItem(TAGLIST, this.tagList)// 添加cacheListconst finalName = this.getFinalName(target)if (this.cacheList.includes(finalName)) returnif (!meta.noCache) {if (finalName.startsWith('device_detail')) {if (!this.detailIndex[target.path]) {this.detailIndex[target.path] = 1} else {this.detailIndex[target.path]++}} else {this.detailIndex[target.path] = ''}this.cacheList.push(finalName)}},
修改src/layout/components/Content/index.vue中的key未route.path + detailIndex.value[route.path]
<template><router-view v-slot="{ Component }"><keep-alive :include="cacheList.join(',')"><component :is="Component" :key="key" /></keep-alive></router-view>
</template>
<script>
import { storeToRefs } from 'pinia'
import { computed, defineComponent } from 'vue'
import { useRoute } from 'vue-router'
import { useTags } from '@/pinia/modules/tags'export default defineComponent({setup() {const route = useRoute()const { cacheList, detailIndex } = storeToRefs(useTags())const key = computed(() => route.path + detailIndex[route.path])return {cacheList,key,}},
})
</script>
相关文章:
vue3-element-admin实现同一个菜单多标签
原框架代码: 赵志江/huzhushan-vue3-element-admin 目录 TagsBar实现 实现同一个菜单多标签 device/detail/:id,不同参数时页面缓存删不掉的问题 TagsBar实现 在src/layout/components/下新建目录Tagsbar,新建index.vue <template><div c…...
第三十六节 Java 网络编程
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。 java.net包中J2SE的API包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注…...

DRF的认证、权限、限流、序列化、反序列化
DRF的认证、权限、限流、序列化、反序列化 一、认证1、直接用,用户授权2、认证组件源码 二、权限1. 直接使用,用户权限2.权限组件源码 三、序列化1. 序列化1.1 自定义Serailizer类序列化1.2 在视图APIView中使用1.3 自定义ModelSerializer类序列化1.4 不…...
解决:Cannot read properties of undefined (reading ‘validate‘)问题
问题:Element UI使用表单校验功能控制台出现Cannot read properties of undefined (reading validate)报错 解决:在 <el-form :model"form" :rules"rules">添加 ref"form",form为自定义的表单名称 <…...
关于IP地址发展历程的详细探讨
IP地址的发展历程是一段不断演进、适应网络技术发展的历史。自互联网诞生以来,IP地址作为网络设备的唯一标识,扮演了至关重要的角色。以下是对IP地址发展历程的详细探讨。 在互联网的初期,主机数量相对较少,IP地址主要用于区分不…...
【LeetCode热题100】【二叉树】将有序数组转换为二叉搜索树
题目链接:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode) 取中间的数作为根节点,左边的数递归转换,右边的数递归转换 class Solution { public:TreeNode *sortedArrayToBST(vector<int> &nums) {retur…...
文心一言和GPT-4全面比较
自大型语言模型出现以来,人工智能在自然语言处理方面取得了显著进步。文心一言和GPT-4是当前最先进的两款语言模型,在业内广受关注。两者都具有强大的能力,但各有特点和优势。本文将从多个方面对这两个模型进行全面比较,以帮助读者…...
Mac的终端配置
Mac的终端配置 参考教程包管理工具 - Homebrew出现的问题用虚拟环境解决方案:直接将解释器的路径放过去错误方法:用find查找到虚拟环境安装的路径,其链接的是brew安装的python路径 编辑器没有报错,但是运行过程中仍然找不到pandas…...

制作一个RISC-V的操作系统十-Trap和Exception(流 mtvec mepc mcause mtval mstatus trap完整流程)
文章目录 流mtvecmepcmcausemtvalmstatustrap 初始化trap的top half(硬件完成)trap的bottom half(软件完成)从trap返回代码实现 流 控制流:程序控制的执行流 trap分为中断和异常 mtvec base:存储trap入…...

【爬虫开发】爬虫从0到1全知识md笔记第4篇:Selenium课程概要,selenium的介绍【附代码文档】
爬虫开发从0到1全知识教程完整教程(附代码资料)主要内容讲述:爬虫课程概要,爬虫基础爬虫概述,,http协议复习。requests模块,requests模块1. requests模块介绍,2. response响应对象,3. requests模块发送请求,4. request…...

对一个时间序列中的每个元素按照指定精度向上取整
【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 对一个时间序列中的每个元素 按照指定精度向上取整 例如:对小时处理, 则9:01处理为10:00 Series.dt.ceil() 选择题 以下代码的输出结果中正确的是? import pandas as…...

51单片机+TN901非接触式红外测温设计论文与源码PCB等资料
1、摘要 温度测量技术应用十分广泛,而且在现代设备故障检测领域中也是一项非常重要的技术。但在某些应用领域中,要求测量温度用的传感器不能与被测物体相接触,这就需要一种非接触的测温方式来满足上述测温需求。本论文正是应上述实际需求而设…...
AI创业项目:AI旅游规划定制师
在当前的旅游市场中,个性化旅游规划成为越来越多旅行者的需求。然而,现行的定制旅行服务主要依赖于人工定制师,这一模式面临着信息不透明、价格弹性大等挑战。定制师在客户与服务供应商之间掌握着信息差,依靠这一优势获得收益&…...
win 安装 Stable Diffusion
注:本人使用的是 RTX2060 - 6G版 特别提醒:安装一定要 CUDA 和 PyTorch 版本能配套用,不然会有生成保存问题(我是这样的),装完用 python -m xformers.info 这个看对应的版本 建议:有些命令安装在venv 虚拟机中做&…...

STM32F407+FreeRTOS+LWIP UDP组播
开发环境介绍: MCU:STM32F407ZET6 网卡:LAN8720A LWIP版本:V1.1.0 FreeRTOS 版本:V10.2.1 LAN8720A硬件原理图: 硬件连接说明: MII_RX_CLK/RMII_REF_CLK ------>PA1 …...

(源码+部署+讲解)基于Spring Boot + Vue的车位租赁系统设计与实现
前言 💗博主介绍:✌专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 2024年Java精品实战案例《100套》 🍅文末获取源码联系🍅 🌟…...

Lecture 2~4 About Filter
文章目录 空间域上的滤波器- 线性滤波器盒状滤波器Box Filter锐化Sharpening相关运算 vs. 卷积运算 Correlation vs. Convolution - 非线性滤波器高斯滤波器Gaussian filter - 实际问题- 纹理texture 频域上的滤波器 滤波的应用- 模板匹配- 图像金字塔 空间域上的滤波器 图像…...
【LINUX】Linux 命令大全:系统管理与网络操作指南
开始之前 Linux命令行,也称为终端,是Linux最强大的特性之一。通过命令行,用户可以执行几乎所有的任务,比如文件操作、程序安装、系统监控和网络配置等。了解这些基本命令,将帮助你更好地掌握Linux系统。 文件和目录操…...
Day50 动态规划 part11
Day50 动态规划 part11 123.买卖股票的最佳时机III 我的思路: 这道题考虑了交易次数 j(最大次数为2),以及某天 i 应该买or卖股票(两种状态) 用三维数组表示 dp[i][j][0] – 第i天结束时,交易j…...

Docker 搭建私有镜像仓库
一、镜像仓库简介 Docker的镜像仓库是一个用于存储和管理Docker镜像的中央位置。镜像仓库的主要作用是提供一个集中的地方,让用户可以上传、下载、删除和共享Docker镜像。镜像仓库又可以分为公共镜像仓库和私有仓库镜像仓库: 公共镜像仓库 Docker Hub 是…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...