思源笔记可移动的导航大纲:js 代码片段

导航目录大体功能:(使用方法:把代码放进 js 代码片段,粘贴完注意第 8 条)

  1. 随着笔记标签页的切换,导航内容也能相应切换
  2. 目录字体大小可调
  3. 可折叠起来
  4. 导航目录过长,可滚动
  5. 鼠标点击目录,可以导航到正文相应位置
  6. 鼠标悬停在目录上,可弹出浮窗
  7. 鼠标单击块,浮动大纲中对应的标题内容颜色会改变。再次点击会找上一级标题
  8. image.png

看下图,应该能明白。更新时间 20250227,修复了一些 bug

screenshots.gif

// ========== 工具函数 ========== // 使用原生DOMParser解析HTML并提取纯文本内容 const parseHtmlToText = (html) => { return html.replace(/<[^>]+>/g, '').replace(/&nbsp/g, ' '); // 注意,使用时要在&nbsp后面加一个分号; }; // 通用高亮函数,返回是否匹配成功 function highlightOutlineElements(outlineContent, nodeId, textContent) { const outlineElements = outlineContent.querySelectorAll("[data-href]"); let isMatched = false; // 用于标记是否找到匹配项 outlineElements.forEach((element) => { const href = element.getAttribute('data-href'); const hrefId = href.split('/').pop(); const isMatch = nodeId ? hrefId === nodeId : element.textContent.trim() === textContent; // 只在必要时修改样式 if (isMatch && element.style.backgroundColor !== 'green') { element.style.backgroundColor = 'green'; // 高亮背景颜色 isMatched = true; // 标记匹配成功 } else if (!isMatch && element.style.backgroundColor === 'green') { element.style.backgroundColor = ''; // 恢复默认背景颜色 } }); return isMatched; // 返回是否匹配成功 } // ========== 数据获取函数 ========== // 获取文档信息,包括 rootID async function getRootID({ id }) { const response = await fetch(`/api/block/getDocInfo`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id }), }); const data = await response.json(); return data.data.rootID; // 直接返回 rootID } // 获取文档大纲的函数 const getDocOutline = async (docId) => { try { const response = await fetch(`/api/outline/getDocOutline`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: docId }), }); if (!response.ok) { throw new Error(`网络请求失败:${response.status}`); } const data = await response.json(); if (data.code === 0) { return data.data; } else { console.error('获取文档目录结构失败:', data.msg); return null; } } catch (error) { console.error('获取文档目录结构失败:', error.message); return null; } }; // ========== 大纲处理函数 ========== // 收集大纲标题的函数 const collectTitles = (data) => { let titles = []; for (let item of data) { let text = (item.name || item.content).trim(); // 解析HTML为纯文本 const parsedText = parseHtmlToText(text); titles.push({ text, parsedText, id: item.id, depth: item.depth, needParse: text !== parsedText, }); // 递归处理子标题 if (item.count > 0) { titles = titles.concat(collectTitles(item.blocks ?? item.children)); } } return titles; }; // 生成大纲内容的函数 const generateOutline = async (nodeId, outlineContent) => { console.log("开始生成大纲,节点 ID:", nodeId); // 调试日志 try { if (!nodeId) { outlineContent.innerHTML = "<li>未找到有效节点,请点击文档内容。</li>"; return; } // 检查是否需要重新生成大纲 const currentOutlineNodeId = outlineContent.getAttribute('data-current-node-id'); if (currentOutlineNodeId === nodeId) { console.log("大纲已存在,无需重新生成"); // 调试日志 return; } const docOutline = await getDocOutline(nodeId); // 获取文档大纲 if (!docOutline) { outlineContent.innerHTML = "<li>无法获取文档目录结构。</li>"; return; } const titles = collectTitles(docOutline); // 收集大纲标题 const fragment = document.createDocumentFragment(); // 创建文档片段 // 遍历标题并生成列表项 titles.forEach(title => { const listItem = document.createElement("li"); const link = document.createElement("span"); link.setAttribute("data-type", "a"); link.setAttribute("data-href", `siyuan://blocks/${title.id}`); // 使用 textContent 设置内容,避免HTML被解析 link.textContent = title.parsedText; // 设置链接样式 Object.assign(link.style, { color: "#000", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", display: "inline-block", maxWidth: "100%", }); // 添加链接点击事件 link.addEventListener("mousedown", (e) => { if (e.button === 0) { e.preventDefault(); const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(link); selection.removeAllRanges(); selection.addRange(range); } }); link.addEventListener('click', function (event) { event.preventDefault(); const href = this.getAttribute("data-href"); window.open(href, '_blank'); }); // 设置列表项的缩进 listItem.style.paddingLeft = `${title.depth * 15}px`; listItem.appendChild(link); fragment.appendChild(listItem); }); // 清空并更新大纲内容 outlineContent.innerHTML = ""; outlineContent.appendChild(fragment); // 更新当前大纲的节点 ID outlineContent.setAttribute('data-current-node-id', nodeId); console.log("大纲生成完成"); // 调试日志 } catch (error) { outlineContent.innerHTML = `<li>生成大纲失败:${error.message}</li>`; } }; // ========== 页面交互函数 ========== // 修改函数:根据 rootId 查找并返回所有兄弟元素的 title 文本数组 function getLastSiblingTitle(rootId) { const allBreadcrumbItems = document.querySelectorAll('.protyle-breadcrumb__item'); for (const item of allBreadcrumbItems) { if (item.getAttribute('data-node-id') === rootId && item.classList.contains('protyle-breadcrumb__item--active')) { const parent = item.parentElement; const siblings = Array.from(parent.children).filter(sibling => sibling !== item); const titles = []; siblings.forEach(sibling => { const titleElement = sibling.querySelector('.protyle-breadcrumb__text'); if (titleElement && titleElement.getAttribute('title')) { titles.push(titleElement.getAttribute('title')); } }); return titles; // 返回包含所有兄弟节点标题的数组 } } return []; // 如果未找到符合条件的元素,返回空数组 } // 处理 NodeHeading 类型 function handleNodeHeading(outlineContent, nodeId) { console.log("处理 NodeHeading 类型,节点 ID:", nodeId); // 调试日志 highlightOutlineElements(outlineContent, nodeId, null); } // 处理非 NodeHeading 类型 function handleNonNodeHeading(outlineContent, textContentArray) { console.log("处理非 NodeHeading 类型,兄弟节点标题数组:", textContentArray); // 调试日志 if (Array.isArray(textContentArray) && textContentArray.length > 0) { // 倒序遍历数组,依次尝试匹配 for (let i = textContentArray.length - 1; i >= 0; i--) { const currentLine = textContentArray[i]; if (highlightOutlineElements(outlineContent, null, currentLine)) { return; // 匹配成功后退出循环 } } } } // 全局点击事件处理函数 const handleClick = async (e, outlineContent) => { console.log("点击事件触发,目标元素:", e.target); // 调试日志 let target = e.target; while (target && target !== document && !target.hasAttribute('data-node-id')) { target = target.parentNode; } if (target && target.hasAttribute('data-node-id')) { const nodeId = target.getAttribute('data-node-id'); try { // 获取 rootID const rootID = await getRootID({ id: nodeId }); if (rootID) { console.log("开始生成大纲,节点 ID:", nodeId); // 调试日志 await generateOutline(nodeId, outlineContent); if (target.getAttribute('data-type') === 'NodeHeading') { handleNodeHeading(outlineContent, nodeId); } else { const siblingTitles = getLastSiblingTitle(rootID); if (siblingTitles.length > 0) { handleNonNodeHeading(outlineContent, siblingTitles); } } } } catch (error) { console.error('获取 rootID 失败:', error.message); } } else { outlineContent.innerHTML = "<li>未找到有效节点,请点击文档内容。</li>"; } }; // ========== UI 创建函数 ========== // 创建大纲面板的函数 const createOutlinePanel = () => { const outlinePanel = document.createElement("div"); Object.assign(outlinePanel.style, { position: "fixed", top: "100px", left: "1000px", width: "200px", height: "30px", background: "#f1f1f1", border: "1px solid #ccc", borderRadius: "5px", padding: "0", boxShadow: "0 0 10px rgba(0, 0, 0, 0.1)", zIndex: "1000", overflow: "hidden", }); const topButtonsContainer = createTopButtonsContainer(); outlinePanel.appendChild(topButtonsContainer); const outlineTitle = document.createElement("h3"); outlineTitle.textContent = "大纲"; Object.assign(outlineTitle.style, { margin: "0 0 10px", }); outlinePanel.appendChild(outlineTitle); const outlineContent = document.createElement("ul"); outlineContent.id = "outline-list"; Object.assign(outlineContent.style, { listStyle: "none", padding: "0", margin: "0", fontSize: "14px", marginTop: "20px", overflowY: "auto", maxHeight: "340px", }); outlineContent.setAttribute("draggable", "false"); outlineContent.addEventListener("dragstart", (e) => e.preventDefault()); outlinePanel.appendChild(outlineContent); const toggleButtonInstance = topButtonsContainer.querySelector('button:nth-child(2)'); toggleButtonInstance.textContent = "展开"; let isExpanded = false; toggleButtonInstance.addEventListener("click", () => { isExpanded = !isExpanded; outlinePanel.style.height = isExpanded ? "400px" : `${topButtonsContainer.offsetHeight}px`; toggleButtonInstance.textContent = isExpanded ? "折叠" : "展开"; }); enableDragging(outlinePanel, topButtonsContainer); return { outlinePanel, outlineContent }; }; // 创建顶部按钮容器的函数 const createTopButtonsContainer = () => { const topButtonsContainer = document.createElement("div"); Object.assign(topButtonsContainer.style, { position: "absolute", top: "0", left: "0", right: "0", height: "20px", backgroundColor: "#f1f1f1", display: "flex", justifyContent: "space-between", alignItems: "center", padding: "5px", }); const showOutlineButton = document.createElement("button"); showOutlineButton.textContent = "思源大纲"; Object.assign(showOutlineButton.style, { padding: "5px", background: "#007bff", color: "#fff", border: "none", borderRadius: "5px", cursor: "pointer", }); const toggleButtonElement = document.createElement("button"); toggleButtonElement.textContent = "展开"; Object.assign(toggleButtonElement.style, { padding: "5px", background: "#ccc", border: "none", borderRadius: "5px", cursor: "pointer", }); topButtonsContainer.appendChild(showOutlineButton); topButtonsContainer.appendChild(toggleButtonElement); return topButtonsContainer; }; // 创建字体大小调整按钮的函数 const createFontButtonsContainer = (outlineContent) => { const fontButtonsContainer = document.createElement("div"); Object.assign(fontButtonsContainer.style, { display: "flex", gap: "5px", }); const decreaseFontSizeButton = document.createElement("button"); decreaseFontSizeButton.textContent = "-"; Object.assign(decreaseFontSizeButton.style, { width: "20px", height: "20px", fontSize: "16px", border: "none", background: "#ccc", borderRadius: "50%", }); decreaseFontSizeButton.addEventListener("click", () => { const currentSize = parseFloat(outlineContent.style.fontSize); outlineContent.style.fontSize = `${Math.max(currentSize - 1, 10)}px`; }); const increaseFontSizeButton = document.createElement("button"); increaseFontSizeButton.textContent = "+"; Object.assign(increaseFontSizeButton.style, { width: "20px", height: "20px", fontSize: "16px", border: "none", background: "#ccc", borderRadius: "50%", }); increaseFontSizeButton.addEventListener("click", () => { const currentSize = parseFloat(outlineContent.style.fontSize); outlineContent.style.fontSize = `${Math.min(currentSize + 1, 24)}px`; }); fontButtonsContainer.appendChild(decreaseFontSizeButton); fontButtonsContainer.appendChild(increaseFontSizeButton); return fontButtonsContainer; }; // 实现面板拖动功能的函数 const enableDragging = (outlinePanel, topButtonsContainer) => { let isDragging = false; let offsetX, offsetY; topButtonsContainer.style.cursor = "move"; topButtonsContainer.addEventListener("mousedown", (e) => { if (isDragging) return; isDragging = true; offsetX = e.clientX - Number(outlinePanel.style.left.replace('px', '')); offsetY = e.clientY - Number(outlinePanel.style.top.replace('px', '')); const onMouseMove = (e) => { if (!isDragging) return; let newX = e.clientX - offsetX; let newY = e.clientY - offsetY; const minX = 20; const minY = 20; const maxX = window.innerWidth - outlinePanel.offsetWidth - 20; const maxY = window.innerHeight - outlinePanel.offsetHeight - 20; newX = Math.max(minX, Math.min(newX, maxX)); newY = Math.max(minY, Math.min(newY, maxY)); outlinePanel.style.left = `${newX}px`; outlinePanel.style.top = `${newY}px`; }; const onMouseUp = () => { isDragging = false; document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); }; document.addEventListener("mousemove", onMouseMove); document.addEventListener("mouseup", onMouseUp); }); }; // ========== 主函数 ========== const main = () => { const { outlinePanel, outlineContent } = createOutlinePanel(); document.body.appendChild(outlinePanel); const fontButtonsContainer = createFontButtonsContainer(outlineContent); const topButtonsContainer = outlinePanel.querySelector('div'); topButtonsContainer.appendChild(fontButtonsContainer); document.addEventListener('click', (e) => handleClick(e, outlineContent)); }; main();
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    24541 引用 • 100487 回帖
2 操作
cxg318 在 2025-02-27 01:25:05 更新了该帖
cxg318 在 2025-02-24 00:11:08 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • Floria233

    这个很棒啊,感谢大大。就我的理解,这个设计是不是和 ob 的 floating index(好像是这个)插件相似?就是可以使大纲悬浮起来——就动图与说明看起来,似乎是这个样子?

    (我就说嘛,ob 能做到的东西,思源大差不差也都能做到类似的,就是这边开发者人手缺乏罢了,扼腕……)

    这个我所能想到的第一个优点就是节省面板位置,因为插件那么多,而软件本体除了编辑器之外的其他部分又那么小,可谓寸土寸金,参考我的话,左边是自带文档树 + 书签两个部件,右边是二级文档树这个部件,这三个是长期固定,常用的浮动面板是 knote 和小记,偶尔需要查看大纲,就得按快捷键切换了(因为不是每个文档都有大纲,需要用的时候才会固定,不用的时候就不希望它占用位置)

    因为文档跳转频繁,文档树与其浮动还是贴边吧,而浮动的大纲面板可以按照需要跳出来,最能辅助正文查看又能灵活调取(不至于总是放在某个地方),唯有它浮动起来是最合适的 😁

    我的体验是,它是一个有则最好,无则稍憾(思源本体可以凑合)而绝非鸡肋的功能设计,ob,flowus(notion 不知道)还有有道云(印象不知道)这种都有特别给出这个设计啊,所以它绝对是有必要的

    目前我所想到的优化方向,1 设计上,应该是这个面板先跟主题风格和谐一致,除此之外,2 这个 UI 的信息界面,大大要不要参考动图右边那个大纲插件设计?给每个大标题旁边都用数字标注其下小标题的数量之类的?

    另,有道云的悬浮大纲,在不用时会变成一道道长短不一的横线,这个看起来很简洁,但可以的话,请大大千万别做成这样,因为我用过几次,每次都需要鼠标浮过去它才会显现,不够直观还增加了操作步骤。

    也不希望完全参照 ob 的那个插件——只能在一个固定位置悬浮(这个当大纲标题太长时,偶尔会和正文重合起来),就是动图中这种自由拖动我感觉挺好的 👍(不过它是只能在编辑区拖动?还是可以在整个界面拖动呢?后者感觉更好一点)

    其实这个面板,只要存在了就是它最大的意义,其他都是锦上添花(来自小白的看法)

    1 回复
  • cxg318
    作者

    思源本体内任意位置拖动的

  • 感觉挺好的工具,有很多场景会需要。

  • zzshang

    鸡肋

  • Floria233

    用不用取决于使用者,开不开发取决于开发者。

    使用者对开发者所做的某个非强制不影响使用体验的功能缺乏感知,就是楼下这种了。

    很多开发者做某个东西,最开始都是基于自己的某些目的,有的是练手,有的是自用,有的是为爱发电,大大感觉有必要就做吧,真正在需要者的使用场景里,还是相当实用滴。

    有句糙话是,我可以不用,你不能没有(捂脸),大概就是这种情况。关键是看大大的动图,已经做到一定可用性了,做好了之后一定会有人需要的。👍

    1 回复
  • cxg318 2 评论
    作者

    再修修,如果大家有一些好的点子,就加上去,到时候成形了,代码放出来

    1 回复
    大大,这些点子感觉可以参考 AI,之前用 joplin 时总觉得文档树很难用,为此还特意去论坛反馈,使用 AI 帮助整理说辞时,AI 给出了更多我都没想到的优化设计方案(乍一看确实也很合理),到了那份上,感觉不是满足使用者需求,而是在考验开发者水平了 😂
    Floria233
    我搜索了一下,给个示例,并非冒犯,只为给大大你参考,要是看不惯 AI 可以忽视。我个人是觉得它里面所给出的某些方向似乎特别难。
    Floria233
  • Floria233

    针对笔记软件中悬浮目录功能的优化方向,可以从以下多个维度进行深入改进,提升用户体验和效率:

    这个是 AI 所写,个人感想使用【】


    一、交互体验优化

    1. 动态折叠与智能展开

      • 层级感知折叠:根据用户当前阅读位置(如标题层级),自动折叠非相关层级目录(如仅展示当前章节的 2-3 级标题)。【这个看动图好像可以做到】
      • 手势交互:支持双指捏合展开/折叠目录层级,长按目录项直接拖拽调整文档结构。【这个涉及到的知识是不是有点难???二级文档树到现在都没法自由拖动排序,可能就是这个原因】
      • 焦点跟随:滚动正文时,悬浮目录自动高亮并居中显示当前章节,同时折叠非相邻章节。【这个感觉比较好用】
    2. 快捷操作集成

      • 右键菜单增强:在目录项右键添加「跳转到子标题」「复制标题链接」「快速拆分/合并章节」等高频操作。【这个在我看来,似乎有点繁琐,不过如果加上好像也挺好用,但这应当是个很大的工作量】
      • 拖拽多选:支持框选或 Shift 多选目录项,批量调整章节顺序或层级(类似文件管理器逻辑)。【这个背后原理不太懂,也许很难???它这个和文档树有点类似,选了目录就直接调动整个文档界面的内容,这个真的有必要吗???这种使用频率似乎不够高……】

    二、视觉与信息呈现优化

    1. 三维视觉反馈

      • 深度指示:通过阴影、缩进层级和颜色渐变区分标题层级(如一级标题深色加粗,次级标题逐渐淡化)。【UI 方面的,这个感觉不错】
      • 阅读进度可视化:在目录项右侧添加细进度条,显示该章节的阅读完成比例(通过文字密度分析估算)。【思源可以联动到这份上吗?估计也不容易】
    2. 动态内容预览

      • Hover 卡片:鼠标悬停目录项时,弹出缩略图或关键句预览,避免频繁跳转。【感觉复杂,悬浮需求有必要吗?如果可以开发出来可能会好用,但可能会影响思源性能,造成卡顿,这是我的揣测】
      • 关联标签:自动标记含图片、表格、代码块的章节,通过图标直观展示内容类型。【同上】

    三、功能增强

    1. 智能目录管理

      • 自动语义重组:通过 NLP 识别内容主题,建议合并/拆分章节(如检测到连续多个短段落讨论同一主题时提示合并)。【复杂】
      • 版本对比:记录目录结构历史版本,支持与早期版本对比并恢复。【这个感觉很没必要,然而这个真是 AI 才能提出来,一般使用者想不到这个】
    2. 跨文档联动

      • 多文档目录聚合:在协同场景下,悬浮目录可同时显示多个关联文档的目录(如项目文档 + 会议纪要),支持跨文档跳转。【这个是啥?有点不懂】
      • 书签同步:将目录项与文档内自定义书签绑定,实现混合导航。【无法想象,从来没有见过哪个目录导航能做到这份上,但不明觉厉】

    四、场景化适配

    1. 创作模式优化

      • 大纲模式融合:进入写作模式时,悬浮目录自动切换为可编辑大纲,支持直接修改标题文本或升降级。【这个感觉不错,不过话说回来,感觉工作量不小】
      • 思维导图联动:点击目录项右侧图标,一键生成以当前章节为中心的局部思维导图。【同上】
    2. 移动端专属设计

      • 摇杆式导航:在窄屏下将目录转换为底部半屏摇杆,滑动控制滚动速度,点击快速定位。【不懂】
      • 语音导航:支持语音指令如「跳转到第三节」「展开所有二级标题」。【感觉这个是真鸡肋】

    五、性能与底层优化

    1. 实时响应机制【这个是给开发者的建议,不说了】

      • 增量加载:超长文档中仅渲染可视区域目录项,滚动时动态加载(类似虚拟列表技术)。
      • 差异更新:通过 Diff 算法仅更新变动的目录节点,避免整体重绘导致的卡顿。
    2. 智能预判

      • 滚动惯性预测:根据滚动速度预加载即将到达的目录节点,确保流畅的高亮切换。

    六、用户自定义体系

    1. 个性化规则引擎
      • 条件过滤:设置「自动隐藏所有空章节」「仅显示含 TODO 标签的节点」等自定义过滤规则。
      • 样式模板库:提供不同场景的目录主题(如学术论文模式、会议记录模式),支持导出分享。

    示例方案:智能写作助手模式

    • 场景:用户撰写技术文档时,悬浮目录右侧常驻 AI 面板:【这个是接入了 AI 的目录,和现在大大做的目录,不是一回事啊,同理,感觉这个不容易做到】
      1. 自动检测「缺少结论段」并红色警示
      2. 推荐插入「代码示例」「流程图」等模块按钮
      3. 实时显示章节字数统计与建议优化点(如「当前段落术语密度过高」)

    通过以上优化,悬浮目录可从被动导航工具升级为主动创作助手,同时兼顾效率型用户的深度需求和新手用户的易用性。建议采用 A/B 测试逐步推进,优先落地高 ROI 功能(如目录搜索、拖拽调整),再迭代智能功能。【这个应该是给开发者的建议,ROI 这种术语都出来了,哈哈哈】

    1 回复
  • att88 2 评论

    我个人可太需要这个了好嘛!之前论坛找了好几次是否有悬浮大纲悬浮文档树,结果都是没有。思源大纲虽说可以四处移动,但是高宽还是受到主页面限制,有时候大纲没几行内容还占了一大片,老按快捷键开关也很麻烦。就很希望能像 ps 那样工具面板都能页面外悬浮,能专注页面本身不被视觉中心外的东西干扰。感谢作者!希望尽快上架

    文档树原来就是可以悬浮的,但悬浮大纲这个是真没有
    Floria233
    请问文档树怎么悬浮?
    att88
  • cxg318 1 评论
    作者

    扔给我这么多,直接整不会了。😂
    ai 确实能帮忙很多,代码基本是 ai 写的,但要修一些小细节,对于我这等代码小白来说,还是很难的。
    可能一个小问题,扔给 kimi,豆包,deepseek,他们几十次都没法给一个满意的结果,
    最后,还得手动进代码查找修改。
    这里也有很大可能是喂给他们的关键词不够准确。
    思源是一个让人折腾停不下来的软件,但要学的东西实在太多了******

    1 操作
    cxg318 在 2025-02-23 00:39:03 更新了该回帖
    不要吓到了,可以做的就去做,不可以做的就去学或者就不做,躺平也没关系,AI 给的方案感觉是作为商业产品开发,方方面面都考虑到了,但 20% 的功能可以满足使用者 80% 的需求,28 定理无处不在,剩下顶多精益求精。😄
    Floria233
  • LitBearPibs

    大佬赶紧上架吧,插件市场怎么搜到,指个路子啊

  • cxg318
    作者

    7.双击段落里的块(包括段落标题),大纲对应的颜色改变

    screenshots.gif

  • cxg318
    作者

    js 代码片段放出,有需要的拿去用,也欢迎修改的更好。
    肯定有一些 bug,先暂时用着吧。😋

    1 回复
  • att88

    js 代码用了好像没起作用?上面 docker 栏中也没找到相应图标,是不是我哪里使用姿势不对

    1 回复
  • cxg318
    作者

    代码片段有一个是 css,一个是 js,不要填错了

    1 回复
  • att88

    确实填的是 js。代码中有一段 // 解码HTML实体的函数 我这边报错,应该是大大代码块粘贴的时候 html 直接给解析了。改回去后我现在运行正常。感谢!!

    image.png

    1 回复
  • cxg318
    作者

    确实,粘贴时自动被系统解析了。只能粘贴完代码,手动改一下了。因为这是发贴的系统自动改的。

  • NieJianYing via macOS

    丸辣,手机伺服用不了,会从网页跳到桌面程序

  • cxg318
    作者

    更新 20250227

请输入回帖内容 ...

推荐标签 标签

  • gRpc
    11 引用 • 9 回帖 • 89 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 1 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 441 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    12 引用 • 54 回帖 • 19 关注
  • 导航

    各种网址链接、内容导航。

    43 引用 • 177 回帖 • 2 关注
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    6 引用 • 140 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1741 回帖 • 2 关注
  • OpenCV
    15 引用 • 36 回帖 • 2 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    182 引用 • 1005 回帖 • 1 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 463 关注
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 617 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 816 回帖 • 1 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 6 关注
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 720 关注
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    584 引用 • 3537 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 378 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 3 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖
  • 电影

    这是一个不能说的秘密。

    122 引用 • 608 回帖
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 491 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 168 关注
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 93 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 1 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 292 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    126 引用 • 848 回帖