HTML 代码块和数据库联动

see https://ld246.com/article/1748432027805

<div>
<style>
/* 根容器 */
.container {
  display: flex;
  justify-content: space-between;
  margin: 20px;
  max-width: 830px;
}
/* 卡片样式 */
.card {
  width: 200px;
  height: 200px;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
}
.card:not(:last-child) {
  margin-right: 10px;
}
/* 内容区域 */
.content {
  text-align: center;
}
/* 数字样式 */
.number {
  font-size: 24px;
  font-weight: bold;
  color: white;
  margin-bottom: 10px;
}
/* 描述性文字样式 */
.label {
  font-size: 16px;
  color: white;
}
</style>
<div class="container">
  <div class="card" style="background: linear-gradient(45deg, rgb(116, 132, 240), rgb(109, 70, 235));">
    <div class="content day">
      <div class="number">276</div>
      <div class="label">天数</div>
    </div>
  </div>
  <div class="card" style="background: linear-gradient(45deg, rgb(255, 107, 107), rgb(255, 142, 142));">
    <div class="content note">
      <div class="number">1890</div>
      <div class="label">笔记</div>
    </div>
  </div>
  <div class="card" style="background: linear-gradient(45deg, rgb(255, 184, 108), rgb(255, 217, 61));">
    <div class="content words">
      <div class="number">1,178,927</div>
      <div class="label">字数</div>
    </div>
  </div>
  <div class="card" style="background: linear-gradient(45deg, rgb(76, 175, 80), rgb(139, 195, 74));">
    <div class="content tag">
      <div class="number">91</div>
      <div class="label">标签</div>
    </div>
  </div>
</div>
<script>
// 仅当数据库和HTML代码块在同一个文档时生效
(async () => {
    // 数据库所在的块id,注意,非数据库id
    const avBlockId = '20250529211754-v5fna55';

    // 从数据库获取数据
    // 此处查询是用的简单查询的alasql扩展
    // https://ld246.com/article/1737952682647
    const data = (await query("select * from ?", [fromAv(avBlockId), null]))[0];
    const protyleHtml = document.querySelector('protyle-html[data-content*="83338BBFCD3DEED2"]');
    if(data) {
        // 本代码块唯一标记 83338BBFCD3DEED2 <--这个注释不要删除
        const shadowRoot = protyleHtml?.shadowRoot;
        if(shadowRoot) {
            shadowRoot.querySelector('.day .number').textContent = data.天数.toLocaleString();
            shadowRoot.querySelector('.note .number').textContent = data.笔记.toLocaleString();
            shadowRoot.querySelector('.words .number').textContent = data.字数.toLocaleString();
            shadowRoot.querySelector('.tag .number').textContent = data.标签.toLocaleString();
        }
    }

    // 监听数据库变化
    // 监听av变化,当数据库块被修改时,重新获取数据
    if(protyleHtml && avBlockId && !window['__av_observe__' + avBlockId]) {
        window['__av_observe__' + avBlockId] = observeDOMChanges(document.querySelector('[data-node-id="'+avBlockId+'"]'), ()=>{
            console.log('avBlockId change');
            protyleHtml.setAttribute("data-content", protyleHtml.getAttribute("data-content"));
        }, 800, {attributes: false});
    }

    // 监听dom变化
    let observeTimer = null;
    function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
        // 默认配置
        const defaultOptions = { attributes: true, childList: true, subtree: true };
        // 合并默认配置与传入的配置
        const config = Object.assign({}, defaultOptions, options);
        // 创建一个观察器实例
        const observer = new MutationObserver((mutationsList) => {
            // 使用防抖函数确保单位时间内最多只调用一次回调
            if(observeTimer) clearTimeout(observeTimer);
            observeTimer = setTimeout(() => {
                callback(mutationsList); // 处理变化
            }, debounceTime);
        });
        // 开始观察目标节点
        observer.observe(targetNode, config);
        // 返回一个函数,以便在不需要时能够停止观察
        return () => { observer.disconnect(); };
    }
})();
</script>
</div>

注意,

  1. 这里使用了简单查询的的的 alasql 扩展,需安装相应的代码片段,详见 https://ld246.com/article/1737952682647
  2. 需要修改参数 const avBlockId = '20250529211754-v5fna55';​ 为你自己的数据库所在块 id,注意这里是块 ID,非数据库 ID
  3. 仅当数据库和 HTML 代码块在同一个文档时生效

image.png

留下你的脚步
推荐阅读