没有iFrame的情况下,如何制作JavaScript小部件?

Kan*_*roo 1 iframe widget web-component reactjs

我有一个聊天窗口小部件,我想将其嵌入其他人的网站。看起来就像对讲机和所有其他聊天弹出窗口。无论滚动到何处,我都希望使聊天弹出窗口停留在屏幕的右下角。但是,当我将聊天应用程序导入为iframe并提供给iframe时position: fixed; bottom: 0px; right: 15px;,iframe不会到达我期望的位置。

我意识到iframe对于嵌入式JS小部件而言不是最佳选择,所有最好的嵌入式应用程序都从文件存储中导入.js文件。在网上搜索了几个小时之后,我还没有找到关于如何制作那些挂接到a并呈现小部件的JS文件的解释/教程。您甚至怎么做那些纯JavaScript应用之一,它们又叫什么?(我假设不是Web组件,因为已经有很长时间的小部件了)。

抱歉,这个问题有点儿菜鸟。在我自己尝试实现之前,我从来不知道这是一回事。任何人都可以向我指出如何开始制作JS网络小部件的正确方向?谢谢!(也许ReactJS到VanillaJS转换器会超级酷)

Pau*_* T. 5

一个纯Javascript应用程序称为SPA-单页应用程序-它们对文档(页面)具有完全控制权。但是,由于您询问有关嵌入小部件的问题,所以我认为这不是问题所在(SPA的网络上有大量信息)。

我打算建议您继续使用Web组件进行此操作-今天有可用的polyfill可以在几乎所有浏览器上正常运行-但由于您提到的问题是您想知道不使用它如何完成操作,因此我在下面详细介绍我的方法

在创建纯JS小部件时,您需要确保您知道a)您无法控制全局空间,b)它需要与页面的其余部分保持良好的配合。另外,由于您没有使用Web组件(并且正在寻找纯JavaScript(无库)),因此,您还必须“手动”初始化小部件,然后将其插入页面中所需的位置-相对于一种声明性方法,其中为您的窗口小部件分配了HTML标记名称,然后将其添加到文档中,魔术就发生了:)

让我以这种方式来总结一下:

小工具工厂

这是一个简单的Javascript Widget工厂- create()返回带有您的widget的HTML元素:

const Widget = Object.create({
    create(chatId) {
        const wdg = document.createElement("div")
        wdg.classList.add("chat-box");
        wdg.innerHTML = `<h1>Chat: ${ chatId }</h1>`;
        // Load your chat data into UI
        return wdg;
    }
});
Run Code Online (Sandbox Code Playgroud)

要使用上述方法创建新的小部件(HTML元素),您将:

const myWidgetInstance = Widget.create("chat-12345");
Run Code Online (Sandbox Code Playgroud)

并将该小部件插入页面中给定位置(例如,在ID为“ chat_box”的DIV元素内部),您将:

document.getElementById("chat_box").appendChild(myWidgetInstance);
Run Code Online (Sandbox Code Playgroud)

因此,这是使用本机(Web)平台创建Widget的基础:)

创建一个可重用/可嵌入的组件

交付可重用和可嵌入的组件时的主要目标之一是确保您不依赖全局空间。因此,您的交付方式(更像您的构建过程)会将所有内容打包到JavaScript IIFD中,这也将为所有代码创建私有范围。

这些类型的单例可重用/可嵌入组件的另一个重要方面是,元素的样式需要确保它们不会“泄漏”并影响页面的其余部分(需要与其他人一起玩)。我在这里不详细介绍这个领域。(仅供参考:这也是Web组件真正派上用场的领域)

这是一个聊天组件的示例,您可以将其添加到页面中想要显示的任何位置。该组件以<script>标签的形式提供,其中包含所有代码:

<script>(function() {
    const Widget = Object.create({
        create(chatId) {
            const wdg = document.createElement("div");
            wdg.classList.add("chat-box");
            wdg.innerHTML = `<h1>Chat: ${ chatId }</h1>`;
            // Load your chat data into UI
            return wdg;
        }
    });

    const myWidgetInstance = Widget.create("chat-12345");
    const id = `chat-${ Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1) }`;
    document.write(`<div id="${ id }"></div>`);
    document.getElementById(id).appendChild(myWidgetInstance);
})();</script>
Run Code Online (Sandbox Code Playgroud)

因此,只需在所需位置放入以下脚本标记,就可以在多个地方使用它:

<body>
    <div>
        <h1>Chat 1</h1>
        <script>/* script tag show above */</script>
    </div>
    ...
    <div>
        <h1>Chat 2</h1>
        <script>/* script tag show above */</script>
    </div>
</body>
Run Code Online (Sandbox Code Playgroud)

这只是如何实现的示例方法。您将不得不添加更多内容,以支持将选项传递给每个小部件(例如,聊天ID),定义样式以及可能使运行时更高效的其他可能的改进。

另一种方法

您可以添加一次“脚本”,然后等待页面其余部分加载,然后在文档中搜索一组“已知”元素(例如,任何CSS类为的elemnet chat-box),然后在其中初始化小部件(jQuery使这种方法很流行)。

示例:请注意如何data在DOM元素中使用属性来存储更多特定于窗口小部件的数据。

<div class="chat-box" data-chatid="123"></div>

<script>(function() {
    const Widget = Object.create({
        create(chatId) {
            const wdg = document.createElement("div");
            wdg.classList.add("chat-box");
            wdg.innerHTML = `<h1>Chat: ${ chatId }</h1>`;
            // Load your chat data into UI
            return wdg;
        }
    });
    const initWhenReady = () => {
        removeEventListener("DOMContentLoaded", initWhenReady);
        Array.prototype.forEach.call(document.querySelectorAll(".chat-box"), ele => {
            const myWidgetInstance = Widget.create(ele.dataset.chatid);
            ele.appendChild(myWidgetInstance);
        });
    };
    addEventListener('DOMContentLoaded', initWhenReady);
})();</script>
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。