在创建网站应用时,遇到需要将组件移动到其他网站的任务很常见。通常这些组件是一些通用的按钮、底部导航、顶部导航等元素。
部件例如,我们可以拿按钮组件作为一个例子,我们将它在组件间传递。它看起来会是这样的。
<button class="button">点我</button>
<style>
.button {
background-color: #4caf50;
color: white;
border: none;
padding: 12px 24px;
text-align: center;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.button:hover {
background-color: #45a049;
}
.button:active {
transform: scale(0.95);
}
</style>
切换到全屏模式,退出全屏模式
网站上的结果会是这样:
现在,让我们拿两个站点来做例子,你需要让这两个站点共用同一个组件。假设这两个站点是 example1 和 example2。它们可以托管在不同的地方。一个站点可以从 GitHub 部署,另一个可以从本地服务器部署。
现在,主要的问题出现了:该怎么分?
几种分享的方法我来简单说说常用的几种方法,从最简单到最实用的。
这两种方法大致如下。
1. 输出到文件并通过脚本连接方式
这种方法假设有一个函数可以返回HTML代码。而且,这个函数可以通过一个远程文件调用。这个文件放在哪儿都没关系,你只需要在那里引用它。
创建按钮的JavaScript文件
// buttonModule.js
(function (global) {
// 定义一个 createButton 函数
function createButton() {
// 创建一个 <style> 元素并添加样式
const style = document.createElement('style');
style.textContent = `
.button {
background-color: #4caf50;
color: white;
border: none;
padding: 12px 24px;
text-align: center;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.button:hover { /*鼠标悬停时的样式*/
background-color: #45a049;
}
.button:active { /*鼠标点击时的样式*/
transform: scale(0.95);
}
`;
// 创建按钮元素
const button = document.createElement('button');
button.className = 'button';
button.textContent = '点击我';
// 返回包含样式和按钮的对象
return { style, button };
}
// 将 createButton 函数暴露到全局作用域
global.buttonModule = {
createButton,
};
})(window);
全屏模式, 退出全屏
例子1/root/index.html
例子2/root/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>按钮模块</title>
<script src="https://.../buttonModule.js"></script>
</head>
<body>
<div id="wrapper"></div>
<script>
// 使用按钮模块:
const { style, button } = buttonModule.createButton();
const wrapper = document.getElementById("wrapper");
wrapper.append(style); // 将样式附加到文档
wrapper.append(button); // 将按钮添加到页面
</script>
</body>
</html>
全屏,退出全屏
在这里,我们通过一个与我们两个站点都不相连的站点来连接模块。它也可能是同一个GitHub。
特点(优点):
- 使用标准的 HTML
<script>
标签即可轻松实现,无需额外设置。 - 不需要现代工具或配置,如 Webpack 或 Vite。
- 适合小型单页面应用或快速实验使用。
- 极简的配置,加快开发过程。
- 可无缝集成到已经依赖全局变量的现有项目中。
不足之处:
- 如果有大量的组件,就会有上千个脚本,这使得这种方法只适合单一使用场景。
- 向全局作用域添加变量或对象,增加了命名冲突的可能性。
- 当使用多个脚本时,很难避免冲突。
- 使得项目更难扩展或重构,从而增加复杂性。
- 脚本依赖于正确的加载顺序,这需要手动管理。
- 维护起来比较困难,也不符合当前的最佳实践。
2. 利用第三方库并将组件移到API中
为此方法,我们将使用类似于 HMPL 的模块。它能帮助您用简单的基于对象的模板连接服务器组件。首先,让我们将组件连接到服务器上。创建一个单独的 HTML
文件,并通过一个 API 请求来提供它。如下是 .html
文件的内容:
button.html
<button class="button">点击按钮</button>
<style>
.button {
background-color: #4caf50;
color: white;
border: none;
padding: 12px 24px;
text-align: center;
text-decoration: none;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.button:hover {
background-color: #45a049;
}
.button:active {
transform: scale(0.95);
}
</style>
全屏显示 退出全屏
之后,我们需要将这个文件转移到服务器上。后端用Node.js。我们将用express.js作为创建API的流行框架。首先,我们会设置一个路由来接收我们的组件。
buttonController.js
const express = require("express");
const expressRouter = express.Router();
const path = require("path");
const 按钮控制器 = (req, res) => {
res.sendFile(path.join(__dirname, "../button.html"));
};
expressRouter.use("/getButton", 按钮控制器);
全屏,退出全屏
app.js(应用主文件)
const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const cors = require("cors");
const PORT = 8000;
const app = express();
const routes = require("./routes/buttonController");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors({ origin: true, credentials: true }));
app.set(express.static(path.join(__dirname, "src")));
app.use("/api", routes);
app.listen(PORT);
全屏模式:进入全屏 退出全屏
之后,我们将会有一个途径可以轻松取出这个组件。在网站上我们可以连接HMPL。它可以通过几种方式连接,我们来看看主要的几种方式:
通过脚本:
<script src="https://unpkg.com/json5/dist/index.js"></script> <!-- 引入json5的库 -->
<script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script> <!-- 引入hmpl-js的库 -->
全屏 退出全屏
通过进口
import hmpl from "hmpl-js";
全屏模式 退出全屏
我们使用方法一,因为index.html在我们的网站上默认是首页。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>按钮组件</title>
</head>
<body>
<script src="https://unpkg.com/json5/dist/index.js"></script>
<script src="https://unpkg.com/hmpl-js/dist/hmpl.min.js"></script>
<script>
// 编译模板函数
const templateFn = hmpl.compile(
`<div id="wrapper">{{ src: "https://.../api/getButton" }}</div>`
);
// 获取模板函数返回的按钮包裹元素
const btnWrapper = templateFn().response;
// 将按钮包裹元素添加到文档主体中
document.body.append(btnWrapper);
</script>
</body>
</html>
全屏模式 退出全屏
在这里,我们差不多像第一种方法一样操作,但关键是现在你可以放心地重复使用这个组件。比如你可以这样操作:
// `btnWrapper1` 和 `btnWrapper2` 是从模板函数中获取的响应。
const btnWrapper1 = templateFn().response;
const btnWrapper2 = templateFn().response;
切换到全屏模式,退出全屏
此外,该模块还提供了许多其他功能,例如指示器(指标)、错误处理功能等。由于该模块基于 fetch,您可以有效自定义请求,并实现更多功能。
特点(优点):
- 重用组件
- 适合从小型应用到包含数千个组件的大型应用
- 特别针对这种以服务器为中心,在客户端显示组件的方法,提供了大量的功能
- 使用方式非常灵活
不足之处:
- 连接两个脚本
- 创建额外API
这种方法实际上是在客户端实现了类似SSR的思想,但缺少了爬虫能够访问的关键元素。不过,这种方法确实很酷,可以简化解决问题的过程。
结尾视情况而定,你可以选择第一种方法或第二种方法。在第一种方法中,你完全掌控整个过程,但如果你需要处理多个组件,这种方法就不太适合,因为你得不断导入文件,这并不是很好。
谢谢大家的阅读,希望这篇文章对你们有帮助!