[js][css] 分享一个类语雀代码块折叠 JS

image.png

image.png

PixPin20250312155832.gif

.code-block { position: relative; margin: 1.5rem 0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; overflow: hidden; z-index: 1; background-color: #f5f5f5; padding: 1rem; border: 2px solid transparent; } @keyframes neon-border { 0% { border-color: #ff0080; box-shadow: 0 0 5px #ff0080; } 25% { border-color: #00ffff; box-shadow: 0 0 5px #00ffff; } 50% { border-color: #00ff00; box-shadow: 0 0 5px #00ff00; } 75% { border-color: #ffff00; box-shadow: 0 0 5px #ffff00; } 100% { border-color: #ff0080; box-shadow: 0 0 5px #ff0080; } } .code-block:hover:not([data-fullscreen="true"]) { animation: neon-border 5s infinite; transform: translateY(-3px) scale(1.02); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); z-index: 10; } .code-block pre { margin: 0; padding: 0; } .code-block-header .code-block-title { font-weight: 500; } .theme-dark .code-block { background-color: #1e1e1e; color: #d4d4d4; } .code-block .protyle-action { opacity: 0; transition: opacity 0.3s ease; } .code-block:hover .protyle-action { opacity: 1; } .code-block[data-fullscreen="true"] { border: none; animation: none; transform: none !important; box-shadow: none; border-radius: 0; margin: 0; padding: 0; } .code-block[data-fullscreen="true"] .hljs { height: calc(100vh - 45px); padding: 1rem; box-sizing: border-box; } .code-block[data-fullscreen="true"] .code-block-header { padding: 8px 15px; background-color: rgba(0, 0, 0, 0.1); border-bottom: 1px solid rgba(127, 127, 127, 0.3); } .code-block[data-fullscreen="true"] .code-block-header { border-left: 4px solid #ff0080; transition: border-color 0.5s ease; } .code-block[data-fullscreen="true"] .code-block-header:hover { border-left-color: #00ffff; } .code-fullscreen-button { opacity: 0.6; transition: transform 0.3s ease, opacity 0.3s ease; } .code-fullscreen-button:hover { opacity: 1; transform: rotate(90deg); } .code-block.animate .hljs { transition: max-height 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .code-arrow { transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @media (max-width: 768px) { .code-block:hover:not([data-fullscreen="true"]) { transform: translateY(-2px) scale(1.01); } .code-fullscreen-button { right: 20px; } }
(() => { const config = { defaultTitle: "Code", arrowExpandedHTML: '<svg class="code-arrow" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M8.59 16.59L13.17 12L8.59 7.41L10 6L16 12L10 18L8.59 16.59Z"></path></svg>', arrowCollapsedHTML: '<svg class="code-arrow" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M8.59 16.59L13.17 12L8.59 7.41L10 6L16 12L10 18L8.59 16.59Z"></path></svg>', fullscreenHTML: '<svg class="code-fullscreen" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></svg>', exitFullscreenHTML: '<svg class="code-fullscreen" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></svg>', headerMinWidth: 100, collapseAnimation: true, animationDuration: 300, }; function addStyles() { const styles = ` .code-block-header { display: flex; align-items: center; padding: 4px 8px; cursor: pointer; background-color: var(--b3-code-block-bg); color: var(--b3-protyle-inline-code-color); border-bottom: 1px solid rgba(127, 127, 127, 0.2); font-size: 13px; font-family: var(--b3-font-family-code); position: relative; } .code-block-title { margin-left: 8px; flex-grow: 1; line-height: 1.5; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .code-arrow { width: 35px; height: 35px; margin-left: 20px; transition: transform 0.2s ease; } .code-fullscreen-button { position: absolute; right: 50px; width: 35px; height: 35px; display: flex; align-items: center; justify-content: center; cursor: pointer; opacity: 0.7; transition: all 0.3s ease; } .code-fullscreen-button:hover { opacity: 1; transform: scale(1.1); } .code-fullscreen { width: 24px; height: 24px; } .code-block-title:empty:before { content: "${config.defaultTitle}"; opacity: 0.6; } .code-block[data-collapsed="true"] .code-block-header .code-arrow { transform: rotate(0deg); } .code-block[data-collapsed="false"] .code-block-header .code-arrow { transform: rotate(90deg); } .code-block[data-collapsed="true"] .code-block-header { border-bottom: none; opacity: 0.8; } .code-block-title:focus { outline: none; border-bottom: 1px dotted var(--b3-protyle-inline-code-color); } .code-block[data-collapsed="true"] .hljs { display: none; } .code-block[data-fullscreen="true"] { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999; background-color: var(--b3-code-block-bg); display: flex; flex-direction: column; overflow: hidden; } .code-block[data-fullscreen="true"] .hljs { flex-grow: 1; overflow: auto; max-height: none !important; display: block !important; height: auto !important; opacity: 1 !important; } .code-block[data-fullscreen="true"] .code-block-header { position: sticky; top: 0; z-index: 1; } `; const styleEl = document.createElement('style'); styleEl.innerHTML = styles; document.head.appendChild(styleEl); } function createCodeBlockHeader(codeBlock) { if (codeBlock.querySelector('.code-block-header')) { return; } const header = document.createElement('div'); header.className = 'code-block-header protyle-custom'; header.innerHTML = config.arrowExpandedHTML; const title = document.createElement('div'); title.className = 'code-block-title'; title.contentEditable = 'true'; title.spellcheck = false; const language = getCodeBlockLanguage(codeBlock); if (language) { title.textContent = language; } header.appendChild(title); const fullscreenButton = document.createElement('div'); fullscreenButton.className = 'code-fullscreen-button'; fullscreenButton.innerHTML = config.fullscreenHTML; fullscreenButton.title = "全屏显示代码"; header.appendChild(fullscreenButton); header.addEventListener('click', (e) => { if ((e.target === title && document.activeElement === title) || fullscreenButton.contains(e.target)) { return; } toggleCodeBlock(codeBlock); }); title.addEventListener('click', (e) => { e.stopPropagation(); }); title.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); title.blur(); } }); fullscreenButton.addEventListener('click', (e) => { e.stopPropagation(); toggleFullscreen(codeBlock, fullscreenButton); }); codeBlock.insertBefore(header, codeBlock.firstChild); codeBlock.setAttribute('data-collapsed', 'false'); codeBlock.setAttribute('data-fullscreen', 'false'); } function toggleFullscreen(codeBlock, button) { const isFullscreen = codeBlock.getAttribute('data-fullscreen') === 'true'; const hljs = codeBlock.querySelector('.hljs'); if (isFullscreen) { codeBlock.setAttribute('data-fullscreen', 'false'); button.innerHTML = config.fullscreenHTML; button.title = "全屏显示代码"; if (codeBlock._wasCollapsedBeforeFullscreen) { if (hljs) { hljs.style.display = ''; hljs.style.maxHeight = ''; hljs.style.height = ''; hljs.style.opacity = ''; hljs.style.overflow = ''; delete hljs.dataset.animating; } setTimeout(() => { codeBlock.setAttribute('data-collapsed', 'true'); if (hljs) { hljs.style.display = 'none'; } delete codeBlock._wasCollapsedBeforeFullscreen; }, 50); } if (window._scrollPositionBeforeFullscreen !== undefined) { window.scrollTo(0, window._scrollPositionBeforeFullscreen); delete window._scrollPositionBeforeFullscreen; } } else { window._scrollPositionBeforeFullscreen = window.scrollY; if (codeBlock.getAttribute('data-collapsed') === 'true') { codeBlock._wasCollapsedBeforeFullscreen = true; codeBlock.setAttribute('data-collapsed', 'false'); if (hljs) { hljs.style.display = 'block'; hljs.style.maxHeight = 'none'; hljs.style.height = 'auto'; hljs.style.opacity = '1'; hljs.style.overflow = 'auto'; if (hljs.dataset.animating === 'true') { delete hljs.dataset.animating; } } } codeBlock.setAttribute('data-fullscreen', 'true'); button.innerHTML = config.exitFullscreenHTML; button.title = "退出全屏"; setTimeout(() => { if (hljs) { hljs.scrollTop = 0; } }, 0); } } function getCodeBlockLanguage(codeBlock) { const hljsElement = codeBlock.querySelector('.hljs'); if (!hljsElement) return null; const classes = hljsElement.className.split(' '); for (const cls of classes) { if (cls !== 'hljs' && cls.length > 0) { return cls; } } return null; } function toggleCodeBlock(codeBlock) { if (codeBlock.getAttribute('data-fullscreen') === 'true') { return; } const isCollapsed = codeBlock.getAttribute('data-collapsed') === 'true'; const hljs = codeBlock.querySelector('.hljs'); if (!hljs) return; if (hljs.dataset.animating === 'true') { return; } hljs.dataset.animating = 'true'; hljs.style.transition = 'none'; codeBlock.classList.remove('animate'); if (isCollapsed) { hljs.style.display = 'block'; hljs.style.height = '0px'; hljs.style.overflow = 'hidden'; hljs.style.opacity = '0'; const targetHeight = hljs.scrollHeight; const heightAnimation = hljs.animate([ { height: '0px', opacity: 0 }, { height: targetHeight + 'px', opacity: 1 } ], { duration: 250, easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', fill: 'forwards' }); heightAnimation.onfinish = () => { hljs.style.height = ''; hljs.style.overflow = ''; hljs.style.opacity = ''; hljs.style.transition = ''; delete hljs.dataset.animating; }; } else { const startHeight = hljs.offsetHeight; hljs.style.height = startHeight + 'px'; hljs.style.overflow = 'hidden'; const opacityAnimation = hljs.animate([ { opacity: 1 }, { opacity: 0 } ], { duration: 120, easing: 'ease-out', fill: 'forwards' }); setTimeout(() => { const heightAnimation = hljs.animate([ { height: startHeight + 'px' }, { height: '0px' } ], { duration: 180, easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', fill: 'forwards' }); heightAnimation.onfinish = () => { hljs.style.display = 'none'; hljs.style.height = ''; hljs.style.opacity = ''; hljs.style.overflow = ''; hljs.style.transition = ''; delete hljs.dataset.animating; }; }, 70); } codeBlock.setAttribute('data-collapsed', !isCollapsed); } function processCodeBlocks(element) { const codeBlocks = element.querySelectorAll('.code-block:not([data-processed="true"])'); codeBlocks.forEach(codeBlock => { createCodeBlockHeader(codeBlock); codeBlock.setAttribute('data-processed', 'true'); }); } function observeCodeBlockAddition(container) { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.classList && node.classList.contains('code-block')) { createCodeBlockHeader(node); node.setAttribute('data-processed', 'true'); } if (node.querySelectorAll) { processCodeBlocks(node); } } }); } }); }); observer.observe(container, { childList: true, subtree: true }); return observer; } function setupKeyboardHandlers() { document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { const fullscreenCodeBlock = document.querySelector('.code-block[data-fullscreen="true"]'); if (fullscreenCodeBlock) { const fullscreenButton = fullscreenCodeBlock.querySelector('.code-fullscreen-button'); if (fullscreenButton) { toggleFullscreen(fullscreenCodeBlock, fullscreenButton); e.preventDefault(); } } } }); } function waitForElement(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(() => { if (document.querySelector(selector)) { observer.disconnect(); resolve(document.querySelector(selector)); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } function isMobile() { return !!document.getElementById("sidebar"); } async function init() { addStyles(); setupKeyboardHandlers(); const container = await waitForElement(isMobile() ? '.protyle-content' : '.layout__center'); processCodeBlocks(container); observeProtyleAddition(container, protyles => { protyles.forEach(protyle => { if (!protyle.classList.contains('protyle')) { protyle = protyle.closest('.protyle'); } if (protyle) { processCodeBlocks(protyle); observeCodeBlockAddition(protyle); } }); }); } function observeProtyleAddition(container, callback) { const observer = new MutationObserver(mutations => { const protyles = []; mutations.forEach(mutation => { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.classList && (node.classList.contains('protyle') || node.classList.contains('protyle-content'))) { protyles.push(node); } } }); } }); if (protyles.length > 0) { callback(protyles); } }); observer.observe(container, { childList: true, subtree: true }); return observer; } init(); })();
  • 思源笔记

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

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

    25753 引用 • 106573 回帖
  • 代码片段

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

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

    174 引用 • 1212 回帖 • 2 关注
4 操作
Luuxcyzz 在 2025-03-12 16:02:38 更新了该帖
Luuxcyzz 在 2025-03-12 15:48:47 更新了该帖
JeffreyChen 在 2025-03-12 12:08:18 更新了该帖
JeffreyChen 在 2025-03-12 12:07:46 更新了该帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 34 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 551 关注
  • Hibernate

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

    39 引用 • 103 回帖 • 726 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    730 引用 • 1281 回帖 • 1 关注
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 634 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    499 引用 • 1395 回帖 • 244 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • Excel
    31 引用 • 28 回帖 • 2 关注
  • Access
    1 引用 • 3 回帖 • 2 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 634 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 221 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖
  • 印象笔记
    3 引用 • 16 回帖 • 1 关注
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖
  • jsDelivr

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

    5 引用 • 31 回帖 • 107 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 369 关注
  • 叶归
    9 引用 • 41 回帖 • 20 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 29 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 150 回帖
  • gRpc
    11 引用 • 9 回帖 • 94 关注
  • 安全

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

    199 引用 • 818 回帖
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 代码片段

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

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

    174 引用 • 1212 回帖 • 2 关注
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 182 关注