🌐 拒绝框架绑定!原生 JS 实现「自动宫格布局」,Vue/React/Angular/纯 HTML 通吃
在前端技术栈日益分裂的今天,我们是否还需要为每个框架单独写一套布局逻辑?
- Vue 项目写个 Directive?
- React 项目写个 Hook + Component?
- Angular 项目写个 Directive?
- 老项目或静态页面还得手写 CSS Media Query?
NO! 🙅♂️
今天介绍一个完全独立、零框架依赖的轻量级布局引擎:lg-grid (来自 lg.web)。
它不依赖 Vue、React 或 Angular 的运行时,直接基于 原生 JavaScript 和 HTML 属性指令 驱动。无论你的项目是最新的 Next.js、Nuxt,还是传统的 jQuery 页面,甚至是一个简单的 .html 文件,都能即插即用。
✨ 核心亮点:为什么选择“原生指令”?
1. 🚀 真正的框架无关 (Framework Agnostic)
底层纯原生 JS 实现,通过解析 HTML 自定义属性(如 lg-grid="310")自动初始化。
- Vue/React/Angular: 直接当普通 HTML 用,无额外包装器,性能无损。
- 静态页面: 引入 JS/CSS 即可生效,无需构建步骤。
- 微前端: 在不同子应用间共享,无冲突。
2. 📐 智能自动计算
只需告诉它“我想要每个格子最小多宽”(例如 310px),它会自动:
- 监听容器宽度变化。
- 实时计算最佳列数。
- 动态注入 CSS 变量控制布局。
- 多区域联动:同一父容器下的多个
.lg-grid自动对齐列宽。
3. ⚡️ 极致轻量
- 0 框架依赖:包体积极小,无 Virtual DOM 开销。
- 按需加载:不污染全局命名空间,只操作指定的 DOM 节点。
💻 全场景使用指南
第一步:引入资源
无论什么项目,只需引入 JS 和 CSS:
import 'lg.web/index.css';
import { grid } from 'lg.web';
grid.install()
💡 注意:这里没有
app.use(),没有<GridProvider>,只有纯粹的grid.install()。
场景 A:原生 HTML / 传统 jQuery 项目
直接在 HTML 标签上使用属性,无需任何框架语法。这是最基础的用法,适合老项目改造或静态页面。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lg.web@1.0.1/dist/grid/index.css">
<style>
/* 自定义网格项样式 */
.grid-item {
border: 1px solid #764ba2;
line-height: 32px;
text-align: center;
}
</style>
<script type="module">
import { grid } from 'https://esm.sh/lg.web@1.0.1/dist/grid/index.js';
grid.install();
window.onload = () => {
document.querySelectorAll('[lg-grid]').forEach(grid => {
grid.addEventListener('lg-grid-change', (event) => {
console.log(event.detail);
});
});
};
</script>
<h2 class="group-title">不分组展示 (lg-grid="200")</h2>
<div lg-grid="200" class="lg-grid">
<div class="grid-item">Item 1</div>
<div class="grid-item">Item 2</div>
<div class="grid-item">Item 3</div>
<div class="grid-item">Item 4</div>
<div class="grid-item">Item 5</div>
<div class="grid-item">Item 6</div>
</div>
<h2 class="group-title">分组展示 (lg-grid="500")</h2>
<div lg-grid="500" onlg-grid-change="console.log(this);">
<h3 class="sub-group-title first">第一组</h3>
<div class="lg-grid">
<div class="grid-item">Item 1</div>
<div class="grid-item">Item 2</div>
<div class="grid-item">Item 3</div>
<div class="grid-item">Item 4</div>
</div>
<h3 class="sub-group-title">第二组</h3>
<div class="lg-grid">
<div class="grid-item">Item A</div>
<div class="grid-item">Item B</div>
<div class="grid-item">Item C</div>
<div class="grid-item">Item D</div>
<div class="grid-item">Item E</div>
<div class="grid-item">Item F</div>
</div>
</div>
场景 B:Vue 3 / Nuxt 项目
在 Vue 中,它被视为普通的 HTML 属性。Vue 的模板编译器会原样保留 lg-grid 属性,运行时由 lg.web 的 JS 接管。
<template>
<div lg-grid="310" @lg-grid-change="onColumnChange">
<div class="lg-grid">
<div v-for="i in 7" :key="i" class="card">
Item {{ i }}
</div>
</div>
<div class="lg-grid">
<div class="card">A</div>
<div class="card">B</div>
</div>
</div>
</template>
<script setup>
// 假设已在 main.js 全局安装,若需按需加载可在此处引入
// import { grid } from 'lg.web';
// grid.install()
const onColumnChange = (event) => {
// 直接获取原生事件详情
const { cols } = event.detail;
console.log(`🌟 Vue 捕获:当前 ${cols} 列`);
};
</script>
<style scoped>
.card {
background: #f0f9ff;
border: 1px solid #bae6fd;
padding: 20px;
border-radius: 8px;
}
</style>
场景 C:React / Next.js 项目
React JSX 完全支持自定义 HTML 属性。由于 lg-grid-change 是原生 DOM 事件而非 React 合成事件,推荐使用 useEffect + ref 进行监听,以获得最佳兼容性。
import { useEffect, useRef } from 'react';
import 'lg.web/index.css';
// import { grid } from 'lg.web'; // 建议在入口文件 (main.jsx) 执行一次 grid.install()
export default function GridPage() {
const containerRef = useRef(null);
useEffect(() => {
const node = containerRef.current;
if (!node) return;
// 绑定原生事件监听器
const handleGridChange = (e) => {
console.log(`⚛️ React 捕获:列数变为 ${e.detail.columns}`);
// 在这里更新 state 或触发其他逻辑
};
node.addEventListener('lg-grid-change', handleGridChange);
// 清理监听器
return () => {
node.removeEventListener('lg-grid-change', handleGridChange);
};
}, []);
return (
<div ref={containerRef} lg-grid="310">
<div className="lg-grid">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="card">
{i}
</div>
))}
</div>
<div className="lg-grid">
<div className="card">A</div>
<div className="card">B</div>
</div>
</div>
);
}
🏆 总结对比
| 特性 | UI 库组件 (Element/AntD) | 框架专用指令 (Vue/React Hooks) | lg.web (原生指令) |
|---|---|---|---|
| 框架依赖 | 🔴 强依赖 (绑定特定框架运行时) | 🔴 强依赖 (仅限某单一框架) | 🟢 无依赖 (Pure JS, 零运行时开销) |
| 适用场景 | 该框架生态内的项目 | 该框架生态内的项目 | 🌍 全场景 (Vue/React/Angular/jQuery/静态页) |
| 迁移成本 | 🔴 极高 (换框架需完全重写组件) | 🔴 极高 (换框架需完全重写逻辑) | 🟢 零成本 (HTML 属性保留,JS 通用,代码无需改动) |
| 包体积 | 🔴 大 (通常几十 KB 起步) | 🟡 中 (含框架特定逻辑) | 🟢 极小 (<5KB, 纯功能代码) |
| 事件机制 | 框架封装的合成事件 | 框架封装的合成事件 | ⚡ 原生 DOM 事件 (所有框架通用) |
| 多框架混用 | ❌ 困难 (易产生命名空间冲突) | ❌ 不可能 (无法跨框架复用) | ✅ 完美支持 (微前端/iframe/混合开发首选) |
| 动态内容 | 需手动调用 refresh 方法 | 需依赖响应式数据触发 | ✅ 自动观察 (自动发现新节点) |
| 生命周期 | 耦合框架生命周期 | 耦合框架生命周期 | 🔄 独立运行 (不依赖任何框架挂载过程) |
🚀 结语
lg.web 不仅仅是一个宫格组件,它是一种“回归原生”的开发理念。
在这个框架层出不穷、技术栈频繁更迭的时代,最原生的方案往往是最长久、最通用的方案。
- ❌ 你不需要担心 Vue 4 会不会破坏你的自定义指令。
- ❌ 你不需要担心 React Server Components (RSC) 是否支持你的 Client Hook。
- ❌ 你不需要为 Angular 的大版本升级而重构布局逻辑。
- ❌ 你不需要在 微前端 架构中为不同子应用引入多套布局库。
无论你的下一个项目是用 SolidJS、Qwik、Svelte、Lit,还是仅仅是一个简单的 .html 静态文件,lg-grid 都能无缝衔接,无需任何适配成本。
让布局回归简单,让代码回归标准。 一次编写,随处运行 (Write Once, Run Anywhere)。
👉 立即在你的项目中尝试吧!体验真正的框架无关开发。
-
推荐一个前后端脚手架 lg-soar:助力开发者腾飞的利器
-
微信公众号
-