求 js 代码,只展开当前活动页签的文档树

本贴最后更新于 203 天前,其中的信息可能已经时移俗易

求 js 代码,在使用“始终定位打开的文档”功能时,只展开当前文档的文档树,自动关闭(不展开)其它无关的文档树。例如:

有笔记本 A,内有文档 A1,子文档 A2、子子文档 A3。

有笔记本 B,内有文档 B1,子文档 B2、子子文档 B3。

已将文档 A2、B2 打开,显示在上方页签栏中。

启用“始终定位打开的文档”功能。

点击 A2 页签,左侧文档树自动展开,并定位到 A-A1-A2;A3 列表不展开

点击 B2 页签,左侧文档树自动展开,定位到 B-B1-B2;同时关闭 A-A1-A2 文档树的展开状态,恢复到笔记本 A。也就是仅保留当前活动页签对应的文档树是展开状态,其它文档树分支全部关闭,包括当前活动文档的子文档树。

  • 思源笔记

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

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

    23007 引用 • 92542 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    8445 引用 • 38468 回帖 • 154 关注
1 操作
wenbocn 在 2024-06-02 13:54:35 更新了该帖
被采纳的回答
  • wilsons 1

    时隔 1 个多月,你解决了吗?相见即是有缘,看到此贴感觉有些思路,就尝试写了下,实现了这个功能。由于刚接触思源,对思源 api 还不是很了解,所以选择用 js 代码片段实现,纯原生 js 实现,方法比较笨,勉强能用。

    不足之处也请论坛里的大佬们多多批评指正!

    效果如下:

    t2.gif

    完整代码如下:

    // 等待标签页容器渲染完成后开始监听
    whenElementExist('.layout__center').then(async element => {
        // 等待笔记列表加载完毕
        await sleep(40);
        // 监听页签切换事件
        observeTabChanged(element, (tab) => {
            // 折叠所有笔记,然后定位当前笔记
            collapseAllBooksThenFocusCurrentBook(element, tab);
        });
    });
    // 折叠所有笔记,然后定位当前笔记
    async function collapseAllBooksThenFocusCurrentBook(element, tab) {
        // 等待激活文档加载完毕
        await whenElementExist(()=>{
            const content = element.querySelector('.layout-tab-container [data-id="'+tab.getAttribute("data-id")+'"]');
            return content && content.getAttribute("data-loading") === "finished";
        });
        // 折叠所有笔记
        document.querySelectorAll("ul.b3-list[data-url]").forEach(async book => {
            const bookName = tab.getAttribute("aria-label")?.split('/')[0];
            if(bookName) {
                // 如果在本笔记中则不再折叠
                const bookText = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
                if(bookText === bookName) {
                    return;
                }
            }
            // 折叠笔记
            const bookArrowBtn = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__toggle');
            if (bookArrowBtn && bookArrowBtn.firstElementChild.classList.contains("b3-list-item__arrow--open")) {
                bookArrowBtn.click();
            }
        });
        // 定位当前笔记
        document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    }
    // 监听页签切换事件
    function observeTabChanged(parentNode, callback) {
        // 创建一个回调函数来处理观察到的变化
        const observerCallback = function(mutationsList, observer) {
            // 用常规方式遍历 mutationsList 中的每一个 mutation
            for (let mutation of mutationsList) {
                // 属性被修改
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    const element = mutation.target;
                    if (element.tagName.toLowerCase() === 'li' && element.getAttribute('data-type') === 'tab-header' && element.classList.contains('item--focus')) {
                        if(typeof callback === 'function') callback(element);
                    }
                }
                // 如果有新的子节点被添加
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'li') {
                            if (node.getAttribute('data-type') === 'tab-header' && node.classList.contains('item--focus')) {
                                if(typeof callback === 'function') callback(node);
                            }
                        }
                    });
                }
            }
        };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(observerCallback);
        // 配置观察器:传递一个对象来指定观察器的行为
        const config = { attributes: true, attributeFilter: ['class'], childList: true, subtree: true };
        // 开始观察目标节点
        observer.observe(parentNode, config);
        // 返回一个函数,用于停止观察
        return function stopObserving() {
            observer.disconnect();
        };
    }
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // 等待元素渲染完成后执行
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                let element = null;
                if (typeof selector === 'function') {
                    element = selector();
                } else {
                    element = document.querySelector(selector);
                }
                if (element) {
                    resolve(element);
                } else {
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    

    使用方法:

    设置 》外观 》代码片段 》js 中新增加代码片段,然后把上面的代码粘贴过去即可。

    image.png

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • Wetoria 1 评论

    @Vanessa V 姐,看看文档树是不是可以考虑支持一下手风琴(只展开当前文档的父级路径)折叠效果。

    逐层展开是逐一发请求,用到效果的话,计算高度样式和请求返回时间有冲突就移除了。你看看是否能改进一下?
    Vanessa
  • player 1 赞同

    ToolbarBox

    这里有除了自动定位的其他代码。 自动定位就做个监听, 针对 class layout__wnd--active ,发现有 tab 的变化,就触发一次,locateDoc() 即可。

    1 回复
  • wenbocn

    本人小白,不会修改。请问能给一个直接可用的方案吗,谢谢!

    1 回复
  • wenbocn

    其实使用 Ctrl+↑(文档树折叠快捷键),再点击“定位当前打开的文档”按钮,就能完美实现想要的效果。不过会使步骤繁琐,供参考。

  • 那些代码是写在插件里面的。挪出来有点麻烦。

    你可以用番茄工具箱,打开顶部工具栏。 alt+1 快捷键就可以。切换文件后,就用 alt+1。 需要先把官方的 alt+1 去掉。

    1 回复
  • wenbocn

    大佬能有空帮忙写一个直接可用的代码或插件吗,这个帖子的 888 积分也悄悄给你,🤫

    求 css 或 js 代码,实现思源笔记在没有获取焦点时,鼠标移动到思源笔记的边栏,触发弹出文档树的功能

    1 回复
  • 感谢信赖,目前这个功能我还用不上。

    等我需要用了,我再搞。

  • wilsons 1

    时隔 1 个多月,你解决了吗?相见即是有缘,看到此贴感觉有些思路,就尝试写了下,实现了这个功能。由于刚接触思源,对思源 api 还不是很了解,所以选择用 js 代码片段实现,纯原生 js 实现,方法比较笨,勉强能用。

    不足之处也请论坛里的大佬们多多批评指正!

    效果如下:

    t2.gif

    完整代码如下:

    // 等待标签页容器渲染完成后开始监听
    whenElementExist('.layout__center').then(async element => {
        // 等待笔记列表加载完毕
        await sleep(40);
        // 监听页签切换事件
        observeTabChanged(element, (tab) => {
            // 折叠所有笔记,然后定位当前笔记
            collapseAllBooksThenFocusCurrentBook(element, tab);
        });
    });
    // 折叠所有笔记,然后定位当前笔记
    async function collapseAllBooksThenFocusCurrentBook(element, tab) {
        // 等待激活文档加载完毕
        await whenElementExist(()=>{
            const content = element.querySelector('.layout-tab-container [data-id="'+tab.getAttribute("data-id")+'"]');
            return content && content.getAttribute("data-loading") === "finished";
        });
        // 折叠所有笔记
        document.querySelectorAll("ul.b3-list[data-url]").forEach(async book => {
            const bookName = tab.getAttribute("aria-label")?.split('/')[0];
            if(bookName) {
                // 如果在本笔记中则不再折叠
                const bookText = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
                if(bookText === bookName) {
                    return;
                }
            }
            // 折叠笔记
            const bookArrowBtn = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__toggle');
            if (bookArrowBtn && bookArrowBtn.firstElementChild.classList.contains("b3-list-item__arrow--open")) {
                bookArrowBtn.click();
            }
        });
        // 定位当前笔记
        document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    }
    // 监听页签切换事件
    function observeTabChanged(parentNode, callback) {
        // 创建一个回调函数来处理观察到的变化
        const observerCallback = function(mutationsList, observer) {
            // 用常规方式遍历 mutationsList 中的每一个 mutation
            for (let mutation of mutationsList) {
                // 属性被修改
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    const element = mutation.target;
                    if (element.tagName.toLowerCase() === 'li' && element.getAttribute('data-type') === 'tab-header' && element.classList.contains('item--focus')) {
                        if(typeof callback === 'function') callback(element);
                    }
                }
                // 如果有新的子节点被添加
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'li') {
                            if (node.getAttribute('data-type') === 'tab-header' && node.classList.contains('item--focus')) {
                                if(typeof callback === 'function') callback(node);
                            }
                        }
                    });
                }
            }
        };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(observerCallback);
        // 配置观察器:传递一个对象来指定观察器的行为
        const config = { attributes: true, attributeFilter: ['class'], childList: true, subtree: true };
        // 开始观察目标节点
        observer.observe(parentNode, config);
        // 返回一个函数,用于停止观察
        return function stopObserving() {
            observer.disconnect();
        };
    }
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    // 等待元素渲染完成后执行
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                let element = null;
                if (typeof selector === 'function') {
                    element = selector();
                } else {
                    element = document.querySelector(selector);
                }
                if (element) {
                    resolve(element);
                } else {
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    

    使用方法:

    设置 》外观 》代码片段 》js 中新增加代码片段,然后把上面的代码粘贴过去即可。

    image.png

    4 回复
  • 牛!https://sypai.cc/ 也可以发一下

    1 回复
  • wenbocn

    可用,感谢!👍

  • 发了 https://sypai.cc/archives/977/

    @wenbocn 从代码中提取的这段代码,本意是想通过标签的 aria-label 属性实现,如果展开的笔记是当前点击的文档所在笔记不再折叠再展开了,这样防止出现跳动。但现在想来如果同一个笔记下,展开多个目录可能会导致同个笔记下的文档切换时不再折叠,不知道是否符合你的需求,如果不符合,建议把这段代码删除。而且这段代码在打开文档时还会出现跳动,实现并不完美。

    const bookName = tab.getAttribute("aria-label")?.split('/')[0];
            if(bookName) {
                // 如果在本笔记中则不再折叠
                const bookText = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
                if(bookText === bookName) {
                    return;
                }
            }
    

    比如,如下场景不会折叠同个笔记下的目录

    t4.gif

    2 回复
  • wenbocn

    跳动确实有点明显。请问能否结合思源本身的“设置 → 文档树 → 始终定位打开的文档”功能,减少切换页签时的跳动。实现思路,点击文档页签,使用 js 代码折叠所有文档树,然后“始终定位打开的文档”功能再起作用,不知是否可行

    1 回复
  • wenbocn

    如果 js 代码只能在“始终定位打开的文档”之后运行的话,可以在启用思源笔记“始终定位打开的文档”功能的前提下,使用 js 代码,只折叠非当前文档所在的文档树。

  • 现在就是点击文档页签,折叠所有文档树,然后定位打开的文档,使用设置的保持定位和 js 去定位效果是一样的。这里最多不折叠当前文档下的笔记目录,但仅仅这样仍然会跳动的,因为折叠过程必然会显得跳动。至于当前笔记下的其他目录是否折叠这看你需求。貌似你的需求只显示当前文档所在目录,其他统统折叠,无论是否相同笔记下。晚点我看看能否改进,但不一定能,别抱希望,免得到时候希望越大失望越大。

    论坛有大佬有好办法的也请多多指点!

    1 回复
  • wenbocn

    使用 ChatGPT 修改了代码,点击文档树,不会有跳动现象了。但点击标签页及正文后的输入焦点在文档内,能够正常编辑文档,但显示焦点却在文档树的按钮上,不知咋回事。

    // 等待元素渲染完成后执行
    function whenElementExist(selector) {
        return new Promise(resolve => {
            const checkForElement = () => {
                const element = typeof selector === 'function' ? selector() : document.querySelector(selector);
                if (element) {
                    resolve(element);
                } else {
                    requestAnimationFrame(checkForElement);
                }
            };
            checkForElement();
        });
    }
    
    // 延迟执行
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    // 折叠所有笔记,然后定位当前笔记
    async function collapseAllBooksThenFocusCurrentBook(tab) {
        const currentBookName = tab.getAttribute("aria-label")?.split('/')[0];
    
        // 等待文档加载完毕
        await whenElementExist(() => {
            const content = document.querySelector('.layout-tab-container [data-id="' + tab.getAttribute("data-id") + '"]');
            return content && content.getAttribute("data-loading") === "finished";
        });
    
        // 折叠所有笔记
        document.querySelectorAll("ul.b3-list[data-url]").forEach(book => {
            const bookName = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__text')?.innerText;
            if (bookName !== currentBookName) {
                const bookArrowBtn = book.querySelector('li[data-type="navigation-root"] span.b3-list-item__toggle');
                if (bookArrowBtn && bookArrowBtn.firstElementChild.classList.contains("b3-list-item__arrow--open")) {
                    bookArrowBtn.click();
                }
            }
        });
    
        // 定位当前笔记
        document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    }
    
    // 监听页签切换事件
    function observeTabChanged(callback) {
        const observerCallback = (mutationsList) => {
            mutationsList.forEach(mutation => {
                if ((mutation.type === 'attributes' && mutation.attributeName === 'class') ||
                    (mutation.type === 'childList' && mutation.addedNodes.length > 0)) {
                    const focusedTab = mutation.target.closest('li[data-type="tab-header"].item--focus');
                    if (focusedTab) callback(focusedTab);
                }
            });
        };
    
        const observer = new MutationObserver(observerCallback);
        observer.observe(document.querySelector('.layout__center'), { attributes: true, childList: true, subtree: true });
        return () => observer.disconnect();
    }
    
    // 主函数,等待容器渲染后开始监听
    whenElementExist('.layout__center').then(async () => {
        await sleep(40);
        observeTabChanged(collapseAllBooksThenFocusCurrentBook);
    });
    
    
    1 回复
  • wenbocn

    image.png

  • 把这个

    // 定位当前笔记
    document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
    

    改为下面这个就好了

    // 定位当前笔记
        if(document.querySelector('#dockLeft span[data-type="file"].dock__item--active')) {
            document.querySelector(".layout-tab-container .block__icons span[data-type=focus]")?.click();
        }
    

    不过,我测试下来,还是会闪动的。

  • wilsons 2

    @wenbocn 我已完美实现了不闪动的版本,并且改进了官方定位,在未打开目录树时,左侧 dock 区目录树显示隐藏按钮样式会获取焦点的 bug

    效果如下

    t6.gif

    完整代码如下

    由于链滴代码长度有限制,只能放到 jsrun 了。

    3 回复
  • EmberSky

    为什么一个月前的帖子你都能翻出来

    我不理解

    image.png

    2 回复
  • 哈哈哈,自然是搜索时遇到的

  • 对了,我也很好奇,我发现 1 个月前的帖子无法顶上来,没在首页或最新那里出现,你们是怎么看到的?

    2 回复
  • wenbocn

    完美,很好用,非常感谢!

  • JeffreyChen 1 1 评论

    在这里会显示最近有回帖的帖子:https://ld246.com/recent/reply

    原来如此
    wilsons
  • wenbocn

    刚开始切换标签页没有问题,但是切换五六个标签页后,还是存在焦点在文档树按钮的问题

    我这边点击标签页后,焦点显示是在文档树的按钮上,点击文档正文后,焦点显示才切换到文档树标签上。

    关闭软件重启后,焦点也是显示是在文档树的按钮上的

    1 回复
  • EmberSky 1 赞同

    我是不会告诉你, 我偷偷翻了你的动态

  • wenbocn 2 评论

    image.png

    我这里默认主题下是不会加粗的
    JeffreyChen
    我试了官方主题和 Asri 主题,均没有发现你说的加粗问题
    wilsons
  • image.png

    你说的是这个按钮吧,这个按钮只有把文档树隐藏时才没有焦点,其他情况都会被激活的。

    不过,这个通常没啥影响,你没说时,我都没注意到这个焦点,哈哈

    1 回复
  • wenbocn

    对,就是这个按钮。可能我这边的显示的比较明显,所以提出来了。活动标签页我自己用 css 加粗强化了,因此这两个地方的变化就明显了。

    image.png

    image.png

    1 回复
  • 你可以录屏看看,我这边并没有发现你说的问题,可能和你的样式有关。

    看我这边效果

    t7.gif

    仔细看,你会发现,当文档树隐藏时,切换标签,文档树显示隐藏按钮的焦点会闪动下,这就是切换标签时,默认的官方定位会让这个按钮聚焦,而我动态把这个聚焦给去掉了。

    1 回复
  • wenbocn

    好像是我自己的某个 css 导致的个例问题,不是该 js 代码导致的问题。

请输入回帖内容 ...

推荐标签 标签

  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖
  • Wide

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

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

    30 引用 • 218 回帖 • 635 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    30 引用 • 96 回帖
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    149 引用 • 257 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 694 关注
  • LaTeX

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

    12 引用 • 54 回帖 • 49 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 147 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 140 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    36 引用 • 35 回帖
  • 倾城之链
    23 引用 • 66 回帖 • 138 关注
  • OpenStack

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

    10 引用 • 1 关注
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 44 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 76 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 591 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    354 引用 • 1823 回帖 • 1 关注
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 223 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 486 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    53 引用 • 40 回帖 • 2 关注
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    545 引用 • 672 回帖
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 780 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 138 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 101 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 604 回帖 • 1 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖 • 1 关注