Back

Somnia 组件编写指南

Without further ado

Somnia 组件编写指南

一个常见的 shortcode ,处理 js 在 Swup.js 切换后自动加载的问题。

<div x-data="test()" x-text="some"></div>
<script>
    function test() {
        return {
            some: "test"
        }
    }
</script>
html

这段代码出现在 shortcode 后。Swup.js 下的页面,切换页面时不会自动加载其中的 js ,导致 Alpine.js 初始化失败。

简码编写简化

一切为了更方便的编写简码!

方法 1 手动移动到 x-data

将函数 return 移动到 x-data 里。如 x-data="{ some: 'test' }"

方法 2 手动移动到 custom.js

将函数移动到 assets/js/custom.js

方法 3 移动到 head 触发后初始化

在 shortcode 中使用 x-load="event (somnia:moved)" 或者 x-load="idle",或者 x-ingore 延迟 Alpine.js 初始化。然后编写代码,在 Swup.js 事件触发后,再初始化。

<div x-data="test()" x-text="some" x-load="event (somnia:moved)"></div>
<script>
    console.log("test loaded")
    function test() {
        return {
            some: "test"
        }
    } 
</script>
html

assets/js/custom.js 中的函数 Somnia.prototype.swupPageInitCustom 函数加上

    // 获取目标容器内的所有脚本元素 遍历每个脚本并将其移动到 head 中
    scriptdocument.querySelectorAll('#content-wrapper script')s.forEach(script => {
        const newScript = document.createElement('script');
        newScript.innerHTML = script.innerHTML;
        // 将脚本元素重新插入到 head 标签内
        document.head.appendChild(newScript);
    });
    document.dispatchEvent(new CustomEvent('somnia:moved', { bubbles: true }));
js

需要注意的是,这段代码比较粗糙,会导致多次加载多次触发,head 部分堆积重复。

方法 4 移动到 x-data 触发后初始化

使用 x-ingore 延迟 Alpine.js 初始化。移动相邻脚本内容到 x-data 中,替换元素触发初始化。

assets/js/custom.js 中的函数 Somnia.prototype.swupPageInitCustom 函数加上

    document.querySelectorAll('div[x-ignore]').forEach(div => {
        // 获取下一个相邻元素(即紧随其后的兄弟元素)
        const nextElement = div.nextElementSibling;
        // 如果相邻元素存在并且是脚本
        if (nextElement && nextElement.tagName.toLowerCase() === 'script') {
            // 将 innerText 设置到当前 div 的 x-data 属性上
            div.setAttribute('x-data', nextElement.innerText);
            nextElement.remove();
            div.removeAttribute('x-ignore'); // 移除 x-ignore 属性
            div.parentNode.replaceChild(div, div); // 触发 Alpine.js 重新解析 x-data
        }
    });
js

这种方法脚本保留一个 object 或者函数都可。

<div x-data="test()" x-text="some" x-ignore></div>
<script>
    function test() {
        return {
            some: "test"
        }
    }
</script>
html

方法 5 Async Alpine 异步加载

函数移动到单独的 js 文件,async-alpine 异步加载。参考 Somnia/static/js/comment.mjs

Docs