效果图

实际代码


<template><div class="mermaid-container" style="z-index: 99999" ref="wrapperRef"><!-- 控制栏 --><div class="control-bar"><div class="control-bar-flex control-bar-tab-wrap"><div :class="['control-bar-tab-item', showCode ? '' : 'control-bar-tab-item-active']" @click="toggleCode">图表</div><div :class="['control-bar-tab-item', showCode ? 'control-bar-tab-item-active' : '']" @click="toggleCode">代码</div></div><div class="control-bar-flex"><div v-if="showCode"><div class="control-bar-dropdown" style="margin-right: 8px" @click="onCopy"><icon-park type="copy" size="16" theme="outline" fill="rgba(82,82,82)" style="margin-right: 4px"></icon-park><span>复制</span></div></div><template v-else><el-tooltip class="box-item" effect="dark" content="缩小" placement="top"><icon-park type="zoom-out" size="16" theme="outline" fill="rgba(82,82,82)" @click="zoomOut" style="margin-right: 16px; cursor: pointer"></icon-park></el-tooltip><el-tooltip class="box-item" effect="dark" content="放大" placement="top"><icon-park type="zoom-in" size="16" theme="outline" fill="rgba(82,82,82)" @click="zoomIn" style="margin-right: 16px; cursor: pointer"></icon-park></el-tooltip><div class="control-bar-line"></div><div class="control-bar-dropdown" @click="editHandle" style="margin-right: 4px"><icon-park type="edit" size="16" theme="outline" fill="rgba(82,82,82)" style="margin-right: 4px"></icon-park><span>编辑</span></div></template><el-dropdown trigger="click"><div class="control-bar-dropdown"><icon-park type="download" size="16" theme="outline" fill="rgba(82,82,82)" style="margin-right: 4px"></icon-park><span>下载</span></div><template #dropdown><el-dropdown-menu><el-dropdown-item @click="downloadSVG">下载 SVG</el-dropdown-item><el-dropdown-item @click="downloadPNG">下载 PNG</el-dropdown-item><el-dropdown-item @click="downloadCode">下载代码</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></div><!-- 代码/图表切换 --><pre class="mermaid-code" v-if="showCode"><code class="hljs code-block-body">{{ code }}</code></pre><div v-else id="graphContainer" class="mermaid-chart" @mousedown="startDrag" @mouseup="stopDrag" @mouseleave="stopDrag" @mousemove="dragFlowchart"><div id="custom-output" class="mermaid-chart-container" ref="mermaidContainer" :style="{ transform: `translate3d(0, ${offsetY}px, 0) scale(${scale})`, maxWidth: `${maxWidth}px` }"><!-- {{ code }} --></div></div><div id="diagram" class="mermaid-container" style="float: left; width: 1px; height: 1px; overflow: hidden"><svg xmlns="http://www.w3.org/2000/svg" id="abc" width="200" height="200"><g transform="translate(50,50)"></g></svg></div><el-dialog v-model="showEditDialog" title="编辑" width="98%" @close="closeEditDialog" modal-class="drawioFrame-dialog" :close-on-click-modal="false"><iframe ref="drawioFrame" :src="iframeSrc" style="width: calc(100% - 4px); height: calc(100% - 4px); border: 0"></iframe><template #footer><!-- <el-button @click="showEditDialog = false">关闭编辑器</el-button> --></template></el-dialog></div>
</template><script setup lang="ts" name="MermaidDiagram">
import { ref, onMounted, nextTick, watch, inject } from 'vue'
import hljs from 'highlight.js'const props = defineProps({code: {type: String,required: true},dialogVisible: {type: Boolean,default: false}
})const onceMessage = inject('$onceMessage')
const showCode = ref(false)
const scale = ref(1)
const mermaidContainer = ref(null)
const maxWidth = ref(0)
const wrapperRef = ref(null)
const svgHeight = ref(0)
const svgWidth = ref(0)
const isDragging = ref(false)
const offsetY = ref(0) // 纵向偏移量
const startY = ref(0) // 鼠标按下时的初始Y坐标
const showEditDialog = ref(false)
const drawioFrame = ref(null)
const iframeSrc = ref('https://embed.diagrams.net/?embed=1&ui=atlas&spin=1&proto=json')
const baseXml = ref(``)
const isDrawioReady = ref(false)// 合并初始化监听(优化逻辑)
const initMessageHandler = () => {// 确保每次对话框打开时重新监听window.addEventListener('message', handleDrawioMessage)
}// 初始化Mermaid
onMounted(() => {refreshMermaid()initMermaid()calculateMaxWidth()window.addEventListener('resize', calculateMaxWidth)initMessageHandler()
})const calculateMaxWidth = () => {if (wrapperRef.value) {maxWidth.value = wrapperRef.value.clientWidth}
}// 监听显示状态变化
watch(() => showCode.value,newVal => {if (newVal) {nextTick(() => {// 具体高亮方式选其一// 方式1:全局重新高亮hljs.highlightAll()// 方式2:定向高亮(推荐)const codeBlocks = document.querySelectorAll('.mermaid-code code')codeBlocks.forEach(block => {hljs.highlightElement(block)})})}}
)// 监听显示状态变化
// watch(
//     () => [props.code,props.dialogVisible],
//     newVal => {
//         if (newVal[0] && newVal[1]) {
//             refreshMermaid()
//             initMermaid()
//         }
//     }
// )const initMermaid = () => {mermaid.initialize({startOnLoad: false,theme: 'default',flowchart: {useMaxWidth: false,htmlLabels: true,curve: 'basis'},securityLevel: 'loose' // 允许SVG操作})renderDiagram()
}const renderDiagram = async () => {await nextTick()if (mermaidContainer.value) {try {// 使用 mermaid.init 生成流程图,并传入回调函数// mermaid.init(undefined, mermaidContainer.value, () => {//     // 在回调函数中获取高度//     const svgElement = mermaidContainer.value.querySelector('svg')//     if (svgElement) {//         // 获取 viewBox 高度,这是 Mermaid 渲染后的实际高度//         const viewBox = svgElement.viewBox?.baseVal//         const height = viewBox?.height || svgElement.getBoundingClientRect().height//         const width = viewBox?.width || svgElement.getBoundingClientRect().width//         console.log('Mermaid渲染后高度:', height)//         console.log('Mermaid渲染后width:', width)//         svgHeight.value = height//         svgWidth.value = width//         // 计算缩放比例//         if (height > 546) {//             const targetScale = 546 / height//             scale.value = Math.min(targetScale, 1)//             console.log(`自动缩放: 原始高度${height}px, 缩放比例${targetScale.toFixed(2)}`)//         } else {//             scale.value = 1//         }//     }// })const input = props.codeconst outputId = 'mermaid-' + Math.random().toString(36).substr(2, 9)// 使用render方法渲染图表mermaid.render(outputId, input).then(result => {mermaidContainer.value.innerHTML = result.svgsetTimeout(() => {// 在回调函数中获取高度const svgElement = mermaidContainer.value.querySelector('svg')if (svgElement) {// 获取 viewBox 高度,这是 Mermaid 渲染后的实际高度const viewBox = svgElement.viewBox?.baseValconst height = viewBox?.height || svgElement.getBoundingClientRect().heightconst width = viewBox?.width || svgElement.getBoundingClientRect().widthconsole.log('Mermaid渲染后高度:', height)console.log('Mermaid渲染后width:', width)svgHeight.value = heightsvgWidth.value = width//     // 计算缩放比例if (height > 546) {const targetScale = 546 / heightscale.value = Math.min(targetScale, 1)console.log(`自动缩放: 原始高度${height}px, 缩放比例${targetScale.toFixed(2)}`)} else {scale.value = 1}}}, 0)}).catch(error => {console.error('渲染错误:', error)mermaidContainer.value.innerHTML = '<div style="color: red; padding: 10px; background-color: #ffe6e6;">渲染错误: ' + error.message + '</div>'})} catch (err) {console.error('Mermaid渲染错误:', err)}}
}// 控制方法
const toggleCode = () => {showCode.value = !showCode.valuesetTimeout(() => {if (!showCode.value) {refreshMermaid()initMermaid()}}, 0)
}const refreshMermaid = () => {scale.value = 1isDragging.value = falseoffsetY.value = 0startY.value = 0showCode.value = false
}const draw = async (diag: any) => {let conf5 = mermaid.getConfig2()if (diag.db.getData) {const data4Layout = diag.db.getData()const direction = diag.db.getDirection()data4Layout.type = diag.typedata4Layout.layoutAlgorithm = 'dagre'data4Layout.direction = directiondata4Layout.nodeSpacing = conf5?.nodeSpacing || 50data4Layout.rankSpacing = conf5?.rankSpacing || 50data4Layout.markers = ['point', 'circle', 'cross']data4Layout.diagramId = 'id-111'return data4Layout}return null
}const svgToImage = (svgString: any, format = 'png') => {return new Promise((resolve, reject) => {try {// 创建SVG图像const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' })const svgUrl = URL.createObjectURL(svgBlob)// 加载图像const img = new Image()img.onload = function () {try {// 创建canvasconst canvas = document.createElement('canvas')const ctx = canvas.getContext('2d')canvas.width = img.widthcanvas.height = img.heightctx.drawImage(img, 0, 0)const imageData = canvas.toDataURL(`image/${format}`, 0.9)URL.revokeObjectURL(svgUrl)resolve({data: imageData,width: img.width,height: img.height})} catch (err) {reject(`转换canvas时出错: ${err.message}`)}}img.onerror = function () {URL.revokeObjectURL(svgUrl)reject('SVG加载失败')}img.src = svgUrl} catch (err) {reject(`SVG解析错误: ${err.message}`)}})
}const svgToBase64 = (svgContent: any) => {// 处理Unicode字符const bytes = new TextEncoder().encode(svgContent)const binString = Array.from(bytes, byte => String.fromCharCode(byte)).join('')const base64 = btoa(binString)return `shape=image;noLabel=1;verticalAlign=top;imageAspect=1;image=data:image/svg+xml,${base64}`
}const createDrawIoXml = (imageData: any, width: any, height: any, text: any) => {const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {const r = (Math.random() * 16) | 0const v = c === 'x' ? r : (r & 0x3) | 0x8return v.toString(16)})// 创建draw.io XML文件内容let xml = ''xml += '<mxGraphModel dx="0" dy="0" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="' + width + '" pageHeight="' + height + '">\n'xml += '  <root>\n'xml += '    <mxCell id="0" />\n'xml += '    <mxCell id="1" parent="0" />\n'xml += '    <UserObject label="" mermaidData="' + text + '" id="' + uuid + '">\n'xml += '      <mxCell style="' + imageData + ';" vertex="1" parent="1">\n'xml += '         <mxGeometry x="0" y="0" width="' + width + '" height="' + height + '" as="geometry" />\n'xml += '      </mxCell>\n'xml += '    </UserObject>\n'xml += '  </root>\n'xml += '</mxGraphModel>\n'return xml
}const start = async () => {let mermaidText = props.codeconst diagram = await mermaid.mermaidAPI.getDiagramFromText(mermaidText)// console.log('完整的解析结果:', diagram)let data4Layout = await draw(diagram)if (data4Layout) {console.log('完整的解析结果:', data4Layout)console.log(mermaid.select_default2('#diagram'))const ss = mermaid.select_default2('#abc')let ddd = await mermaid.render3(data4Layout, ss)const drawio = mxMermaidToDrawio(ddd, data4Layout.type, {})// console.log('===========drawio', drawio)return drawio} else {console.log('没有解析到数据')const result = await mermaid.render('diagram2', mermaidText)const imageResult = await svgToImage(result.svg)const data = svgToBase64(result.svg)console.log(imageResult)let d = { data: mermaidText }const jsonString = JSON.stringify(d)const escapedJson = jsonString.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')console.log(escapedJson)const drawioXml = createDrawIoXml(data, svgWidth.value, svgHeight.value, escapedJson)console.log('=========drawioXml', drawioXml)return drawioXml}
}const editHandle = async () => {baseXml.value = await start()showEditDialog.value = trueawait nextTick()
}// 2. 监听 draw.io 的初始化完成事件
const handleDrawioMessage = event => {if (event.data === '{"event":"init"}') {isDrawioReady.value = truetryLoadDiagram()}
}// 3. 只有 iframe 和 draw.io 都就绪时,才发送 XML
const tryLoadDiagram = () => {if (isDrawioReady.value) {loadDiagram()}
}// 调整对话框关闭事件处理
const closeEditDialog = () => {showEditDialog.value = falseisDrawioReady.value = false // 重置状态initMessageHandler() // 重新绑定监听以便下次使用
}const loadDiagram = () => {const frame = drawioFrame.valueif (frame) {frame.contentWindow.postMessage(JSON.stringify({action: 'load',xml: baseXml.value}),'*')}
}const zoomIn = () => {// scale.value = Math.min(scale.value + 0.1, 2)const newScale = scale.value + 0.1const scaledWidth = (mermaidContainer.value?.scrollWidth || 0) * newScale// 只有当缩放后宽度小于容器宽度时才允许放大if (scaledWidth <= maxWidth.value) {scale.value = newScale} else {// 自动调整到最大允许比例scale.value = maxWidth.value / (mermaidContainer.value?.scrollWidth || maxWidth.value)}
}const zoomOut = () => {scale.value = Math.max(scale.value - 0.1, 0.5)
}const downloadSVG = () => {const svg = mermaidContainer.value?.querySelector('svg')if (!svg) returnconst serializer = new XMLSerializer()const source = serializer.serializeToString(svg)const svgBlob = new Blob([source], { type: 'image/svg+xml' })downloadFile(svgBlob, 'diagram.svg')
}const downloadPNG = async () => {const svg = mermaidContainer.value?.querySelector('svg')if (!svg) returnconst canvas = document.createElement('canvas')const ctx = canvas.getContext('2d')const data = new XMLSerializer().serializeToString(svg)const img = new Image()img.onload = () => {canvas.width = svgWidth.valuecanvas.height = svgHeight.valuectx.drawImage(img, 0, 0)canvas.toBlob(blob => {downloadFile(blob, 'diagram.png')}, 'image/png')}img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(data)))
}const downloadCode = async () => {// 创建 Blob 对象const blob = new Blob([props.code], { type: 'text/plain' })downloadFile(blob, 'diagram.mermaid')
}const downloadFile = (blob, filename) => {const link = document.createElement('a')link.href = URL.createObjectURL(blob)link.download = filenamedocument.body.appendChild(link)link.click()document.body.removeChild(link)
}const onCopy = () => {const textarea = document.createElement('textarea') // 直接构建textareatextarea.value = `${props.code}` // 设置内容document.body.appendChild(textarea) // 添加临时实例textarea.select() // 选择实例内容document.execCommand('Copy') // 执行复制document.body.removeChild(textarea) // 删除临时实例onceMessage.success('复制成功')
}// 开始拖动
const startDrag = e => {isDragging.value = truestartY.value = e.clientYdocument.body.style.cursor = 'grab' // 五指抓取手势document.body.style.userSelect = 'none' // 禁用文本选择
}// 停止拖动
const stopDrag = () => {if (!isDragging.value) returnisDragging.value = falsedocument.body.style.cursor = '' // 恢复默认光标document.body.style.userSelect = '' // 恢复文本选择
}// 拖动中计算位置
const dragFlowchart = e => {if (!isDragging.value) returnconst deltaY = e.clientY - startY.valueoffsetY.value += deltaYstartY.value = e.clientY // 更新当前鼠标位置// 根据缩放比例动态计算最大偏移量const containerHeight = 546 // 容器固定高度const scaledHeight = svgHeight.value * scale.value // 缩放后的实际高度const maxOffset = Math.max(0, scaledHeight - containerHeight) // 计算最大可偏移量// 限制拖动边界offsetY.value = Math.max(-maxOffset, Math.min(maxOffset, offsetY.value))
}
</script><style lang="scss">
.drawioFrame-dialog {max-height: calc(100vh) !important;.ep-dialog {padding: 4px;height: calc(96vh) !important;}.ep-dialog__header {margin-bottom: 2px;}.ep-dialog__headerbtn {top: -4px;}.ep-dialog__body {padding: 0 !important;margin: 0 !important;max-height: 100% !important;height: calc(96vh - 24px - 8px) !important;}.ep-dialog__footer {display: none;}
}
</style>
<style lang="scss" scoped>
.mermaid-container {// border: 1px solid #eee;border-radius: 12px;// padding: 10px;// margin: 20px 0;background-color: #fafafa;color: #494949;.control-bar {display: flex;border-radius: 12px 12px 0 0;justify-content: space-between;display: flex;padding: 6px 14px 6px 6px;background-color: #f5f5f5;.control-bar-flex {display: flex;justify-content: center;align-items: center;color: rgba(82, 82, 82);}.control-bar-tab-wrap {background-color: rgba(0, 0, 0, 0.03);border-radius: 8px;}.control-bar-tab-item {height: 26px;font-size: 12px;white-space: nowrap;cursor: pointer;border-radius: 8px;flex: 1;justify-content: center;align-items: center;padding: 0 14px;font-weight: 400;display: flex;position: relative;}.control-bar-tab-item-active {display: flex;background-color: #fff;font-weight: 600;box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.02), 0 6px 10px 0 rgba(0, 0, 0, 0.04);}.control-bar-line {width: 1px;height: 14px;margin-right: 12px;background-color: rgba(187, 187, 187, 1);}.control-bar-dropdown {cursor: pointer;display: flex;align-items: center;cursor: pointer;padding: 0px 4px;height: 28px;font-size: 12px;color: rgba(82, 82, 82);border-radius: 12px;&:hover {background-color: rgba(0, 0, 0, 0.04);}}}
}.mermaid-chart {overflow: auto;background-color: #fafafa;border-radius: 0 0 12px 12px;overflow: hidden;max-height: 546px;display: flex;justify-content: center;align-items: center;user-select: none; // 禁用文本选择will-change: transform; // 提示浏览器优化渲染.mermaid-chart-container {will-change: transform; // 提示浏览器优化渲染user-select: none; // 禁用文本选择}/* 鼠标按下时切换为激活手势 */.mermaid-flowchart:active {cursor: grabbing;}
}.mermaid-chart > div {display: flex;justify-content: center;align-items: center;width: 100%;height: 100%;
}.mermaid-code {background-color: #fafafa;padding: calc(9.144px) calc(13.716px) calc(9.144px) calc(13.716px);white-space: pre-wrap;overflow: auto;text-align: left;border-radius: 0 0 12px 12px;font-size: 12px;
}.icon {font-style: normal;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tcp/quic 的滑动窗口

一、滑动窗口 rwnd&#xff1a; 接收端窗口&#xff0c;接收方在每次发送ACK确认报文时&#xff0c;会包含一个 rwnd (Receive Window Size) 字段&#xff0c;指明自己当前剩余的接收缓冲区大小&#xff08;即可用窗口&#xff09;&#xff0c;这里是否是socket的接收缓冲区&am…

JVM监控及诊断工具-命令行篇

18.1. 概述 性能诊断是软件工程师在日常工作中需要经常面对和解决的问题&#xff0c;在用户体验至上的今天&#xff0c;解决好应用的性能问题能带来非常大的收益。 Java 作为最流行的编程语言之一&#xff0c;其应用性能诊断一直受到业界广泛关注。可能造成 Java 应用出现性能…

Jenkins 版本升级与插件问题深度复盘:从 2.443 到 2.504.3 及功能恢复全解析

前言&#xff1a;问题溯源与升级必要性 在 Jenkins 持续集成体系中&#xff0c;插件生态是其强大功能的核心驱动力。然而&#xff0c;某次例行维护中&#xff0c;团队对 Jenkins 2.443 环境的插件进行批量升级后&#xff0c;意外触发连锁反应 &#xff1a; SSH Server 插件功能…

Ribbon实战

一、前置知识 1.1 负载均衡定义 负载均衡指的是将网络请求通过不同的算法分配到不同的服务器上的技术&#xff0c;从而提升系统的性能。 1.2 负载均衡工具 负载均衡工具可以分分为客户端负载均衡工具和服务端负载均衡工具&#xff0c;它们的区别如下。 表1-1 负载均衡工具…

cs285学习笔记(一):课程总览

根据 Fall 2023 学期的官方课程日程&#xff0c;这里是 CS 285 全课程的 Lecture 大纲及内容摘要&#xff0c;详细对应周次和主题&#xff0c;方便你快速定位每节课要点、相关作业与视频资源 &#x1f3af; 官方课程地址 YouTobe 视频地址 blibli视频(带中文字幕) &#x…

OkHttp SSE 完整总结(最终版)

1. SSE 基础概念 什么是 SSE&#xff1f; SSE&#xff08;Server-Sent Events&#xff09;是一种 Web 标准&#xff0c;允许服务器向客户端推送实时数据。 核心特点 单向通信&#xff1a;服务器 → 客户端 基于 HTTP 协议&#xff1a;使用 GET 请求 长连接&#xff1a;连…

聚宽sql数据库传递

自建数据库从聚宽到Q-MT自动化交易实战 从接触聚宽以来一直都是手动跟单&#xff0c;在网上看到许多大佬的自动交易文章&#xff0c;心里也不禁十分痒痒。百说不如一练&#xff0c;千讲不如实干。经过一番努力&#xff0c;终于成功实盘了&#xff0c;效果还可以&#xff0c;几…

es里为什么node和shard不是一对一的关系

提问&#xff1a; 既然多个shard会被分配到同一个node上&#xff0c;那么为什么不把多个shard合并成一个然后存在当前node上呢&#xff0c;简而言之也就是让node和shard形成一对一的关系呢 &#xff1f;非常好的问题&#xff0c;这正是理解Elasticsearch分片&#xff08;shard…

浅谈npm,cnpm,pnpm,npx,nvm,yarn之间的区别

首先做一个基本的分类 名称描述npm,cnpm,yarn,pnpm都是Javascript包管理器nvm是Node.js版本控制器npx命令行工具 I.npm,cnpm,yarn,pnpm npm (Node Package Manager) npm是Node.js默认的包管理器&#xff0c;随Node.js的安装会一起安装。使用npm可以安装&#xff0c;发布&…

滑动窗口-76.最小覆盖子串-力扣(LeetCode)

一、题目解析1.不符合要求则返回空串("")2.子串中重复字符的数量要不少于t中该字符的数量二、算法原理解法1&#xff1a;暴力枚举哈希表这里的暴力枚举也可以优化&#xff0c;即在包含t中元素处枚举&#xff0c;如在A、B和C处开始枚举&#xff0c;减少不必要的枚举 解…

从零构建搜索引擎 build demo search engine from scratch

从零构建搜索引擎 build demo search engine from scratch 我们每天都会使用搜索引擎&#xff1a;打开google等搜索引擎&#xff0c;输入关键词&#xff0c;检索出结果&#xff0c;这是一次搜索&#xff1b;当打开历史记录旁边的&#x1f50d;按钮&#xff0c;输入关键词&#…

pytorch小记(二十九):深入解析 PyTorch 中的 `torch.clip`(及其别名 `torch.clamp`)

pytorch小记&#xff08;二十九&#xff09;&#xff1a;深入解析 PyTorch 中的 torch.clip&#xff08;及其别名 torch.clamp&#xff09;深入解析 PyTorch 中的 torch.clip&#xff08;及其别名 torch.clamp&#xff09;一、函数签名二、简单示例三、广播支持四、与 Autograd…

快速分页wpf

/*没有在xaml设置上下文window.context是因为 命名空间一直对应不上 所以在xaml.cs 里面绑定*/ <Window x:Class"DataGrid.views.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft…

如何彻底禁用 Chrome 自动更新

如何彻底禁用 Chrome 自动更新 随着谷歌将 Chrome 浏览器版本升级至 138&#xff0c;它即将彻底抛弃对 Manifest V2 扩展的支持。许多用户希望将浏览器版本锁定在 138&#xff0c;以继续使用 uBlock Origin、Tampermonkey 等常用扩展。 本文总结了四种有效方法&#xff0c;帮助…

流批一体的“奥卡姆剃刀”:Apache Cloudberry 增量物化视图应用解析

引言&#xff1a;流批一体&#xff0c;理想与现实的鸿沟 在数据驱动的今天&#xff0c;“实时”二字仿佛拥有魔力&#xff0c;驱使着无数企业投身于流批一体架构的建设浪潮中。我们渴望实时洞察业务变化&#xff0c;实时响应用户需求。以 Apache Flink 为代表的流处理引擎&…

C# 入门教程(三):详解字段、属性、索引器及各类参数与扩展方法

文章目录一、字段、属性、索引器、常量1.字段2.属性2.1 什么是属性2.2 属性的声明2.3 属性与字段的关系3 索引器4. 常量二、传值 输出 引用 数组 具名 可选参数&#xff0c;扩展方法2.1 传值参数2.1.1 值类型 传参2.1.2 引用类型 传参2.2 引用参数2.2.1 引用参数-值类型 传参2.…

《美术教育研究》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a;问&#xff1a;《美术教育研究》是不是核心期刊&#xff1f;答&#xff1a;不是&#xff0c;是知网收录的第一批认定学术期刊。问&#xff1a;《美术教育研究》级别&#xff1f;答&#xff1a;省级。主管单位&#xff1a; 安徽出版集团有限责任公司 主办…

每日算法刷题Day47:7.13:leetcode 复习完滑动窗口一章,用时2h30min

思考: 遇到子数组/子字符串可以考虑能不能用滑动窗口&#xff0c; 定长:逆向思维,答案不定 最大长度/最小长度:一般求长度 越长越合法/越短越合法/恰好:一般求数量 主要思考窗口条件成立&#xff0c; 判断条件是符合窗口条件(最小长度/越长越合法还是不符合(最大长度/越短越合法…

电流驱动和电压驱动的区别

理解电流驱动和电压驱动的区别对电路设计至关重要&#xff0c;尤其在高速、高抗噪要求的场景&#xff08;如LVDS&#xff09;。以下是两者的核心对比&#xff1a;一、电压驱动 (Voltage Drive) 核心原理&#xff1a; 驱动器输出一个受控的电压&#xff08;与负载阻抗无关&#…

宿舍电费查询——以ZUA为例

宿舍电费查询——以ZUA为例0. 安装抓包环境手机端桌面端1. 登录1.1 开启抓包后进入缴费页面&#xff1a;1.2 分析请求1.3 编写登录代码2. 获取楼栋及房间ID2.1 获取楼栋ID2.2 编写获取楼栋ID代码2.3 获取房间ID2.4 编写获取房间ID代码3. 获取剩余电费&#xff1a;3.1 选择房间号…