不适用vue react大型框架只用html等能实现局部刷新等能力吗

3 次阅读

本文最后更新于 2026年10月27日。

结论先说

完全可以,不用 Vue / React 这类大型框架,原生 HTML + JS + CSS 就能做到局部刷新、组件化、路由、状态管理这些能力。 本质上:Vue、React 底层也是操作 DOM,只是封装了虚拟DOM、响应式、调度机制。原生 JS 直接操作 DOM 就是最原始的局部刷新方案。

下面分方案从简单到进阶讲清楚各自优缺点、适合场景。

1. 最基础:手动 DOM 操作(innerHTML / appendChild / replaceChild)

原理:不刷新整个页面,只选中某个 DOM 节点,替换它内部内容。

<div id="container"></div>
<button onclick="loadData()">加载内容</button>

<script>
async function loadData() {
  const res = await fetch('/api/list');
  const data = await res.json();
  // 局部刷新,只改 container,页面不重载
  document.getElementById('container').innerHTML = `
    <ul>
      ${data.map(item => `<li>${item.name}</li>`).join('')}
    </ul>
  `;
}
</script>

✅ 优点:零依赖,最简单 ❌ 缺点:

  • innerHTML 会销毁内部所有子DOM、丢失事件绑定、输入框光标/状态
  • 数据变了要手动写代码更新对应DOM,没有自动绑定
  • 复杂页面维护灾难

小技巧:如果不想销毁DOM,不用 innerHTML,用 document.createElement、append、remove 精细增删节点。

2. 模板引擎(轻量,不是SPA框架)

比如:Handlebars、Nunjucks、Mustache,甚至自己写极简模板函数。 把模板字符串抽出来,数据传入生成 html,再局部塞到容器里。 比手写字符串拼接好一点,但依然是生成HTML字符串替换DOM,没有diff。

3. 自己实现简易虚拟DOM + Diff(就能复刻React核心思路)

核心三步:

  1. 用 JS 对象描述节点(vnode)
  2. 新旧 vnode 对比 diff
  3. 只把差异部分更新到真实 DOM,实现精细局部更新,不会整个容器重载

几百行 JS 就能跑通一个极简版,具备:

  • 增量局部更新
  • 嵌套组件 但是没有 fiber 调度、并发、HMR、生态,适合学习,大型项目自己维护成本极高。

4. 原生 Web Components(浏览器标准,非常推荐)

属于浏览器原生能力,不需要任何框架:

  • Custom Elements(自定义标签)
  • Shadow DOM(隔离样式、DOM)
  • HTML Templates(<template>)
  • <slot> 插槽
<template id="card-tpl">
  <style>p{color:red}</style>
  <p></p>
</template>
<script>
class MyCard extends HTMLElement {
  constructor() {
    super();
    const tpl = document.getElementById('card-tpl');
    this.attachShadow({mode:'open'}).append(tpl.content.cloneNode(true));
  }
  // 属性变化自动触发更新,原生响应式钩子
  static get observedAttributes() { return ['title']; }
  attributeChangedCallback(name, oldVal, newVal) {
    this.shadowRoot.querySelector('p').textContent = newVal;
  }
}
customElements.define('my-card', MyCard);
</script>

<!-- 使用 -->
<my-card title="hello"></my-card>

✅ 能力:

  • 组件化、样式隔离
  • 属性变更自动局部更新
  • 可以组合、嵌套
  • 原生标准,可和任意页面混用 ❌ 短板:
  • 没有内置状态管理、路由、全局响应式
  • 没有虚拟DOM diff,属性更新粒度由你自己控制
  • 表单双向绑定、列表渲染需要自己封装

很多轻量框架(Lit、Shoelace)就是基于 Web Components 做的封装,Lit 只有十几KB,远小于 Vue/React。

5. 原生响应式 + 发布订阅(自己做数据驱动)

用 Proxy 封装数据,数据修改时,自动执行对应的更新函数,绑定到指定DOM:

function reactive(obj, effect) {
  return new Proxy(obj, {
    set(target, key, value) {
      target[key] = value;
      effect(); // 数据变了,执行局部更新
      return true;
    }
  })
}
const state = reactive({ name: 'test' }, () => {
  document.querySelector('#name').textContent = state.name;
});

这就是 Vue2 Object.defineProperty / Vue3 Proxy 响应式的核心原理。 你可以自己写依赖收集,做到只有用到这个数据的DOM才刷新,精准局部更新。

6. 轻量替代框架(如果你不想从零造轮子,但排斥Vue/React)

这些都很小,主打局部刷新、数据驱动:

  • Lit:Google,基于Web Components,约5KB,数据驱动、自动更新
  • Preact:API和React几乎一致,3KB,有虚拟DOM diff
  • Svelte:编译期框架,运行时几乎零开销,没有虚拟DOM,编译成原生JS DOM操作
  • Alpine.js:极轻量(~7KB),在HTML上写指令,类似Vue模板,不用构建工具,直接引入脚本就能用,非常适合老页面加局部交互
<div x-data="{count:0}">
  <button @click="count++">+1</button>
  <span x-text="count"></span>
</div>
<script defer src="[https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js](https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js)"></script>

Alpine 是这类场景的热门选择:不推翻原有HTML页面,按需加局部数据驱动刷新。

7. 路由(SPA无刷新跳转)

原生 API:history.pushState / popstate 不需要框架就能实现前端路由,切换url不重载页面,只更换对应区块内容,搭配上面局部刷新。

关键对比总结

方案 局部刷新 数据驱动 组件隔离 适合场景
原生DOM innerHTML ✅ 整块替换 ❌ 手动 ❌ 简单页面、少量交互
Web Components ✅ 可控更新 ⚠️ 自己封装 ✅ Shadow DOM 可复用组件、跨框架组件
Proxy响应式 + 订阅 ✅ 精准更新 ✅ ❌ 需要自己封装 想自研极简数据驱动
Alpine.js ✅ ✅ ⚠️ 老HTML页面增强,不想上构建
Svelte/Lit/Preact ✅ diff/细粒度 ✅ ✅ 轻量SPA,不想用Vue React

什么时候不建议纯原生手写?

页面规模大:大量列表嵌套、复杂状态联动、大量表单、频繁DOM更新。 自己维护 diff、依赖收集、调度、事件、缓存,工程量会慢慢复刻一个迷你框架,后期维护成本很高。

一句话总结

局部刷新本质就是:不触发页面整体导航重载,只按需修改部分DOM。这件事是DOM API原生就支持的,和Vue/React没有绑定关系。Vue/React只是一套成熟封装方案,不是唯一方案。

如果你想要,我可以给你一份:无任何框架、纯原生JS实现的极简响应式+diff局部刷新demo(包含列表增删,只更新变化行)。