目录

一、基础语法

1.1、模板 vs JSX

1.2、指令

1.2.1、v-for vs Array.map

1.2.2、v-if vs 三元运算符或者&&

1.2.3、v-bind vs 直接在JSX里写{变量}

1.2.4、v-show vs style和className

1.2.5、v-html vs dangerouslySetInnerHTML

1.3、数据绑定

1.4、数据初始化

1.5、computed(只能同步)

1.6、watch(可包含异步)

二、生命周期

2.1、周期总结

2.2、关键差异

三、组件传值

3.1、父传子

3.2、子传父

3.3、ref( 父组件访问子组件)

3.4、数据共享

3.5、跨组件通信

3.5.1、事件总线/发布订阅

3.5.2、Provide-Inject/Context

四、路由

4.1、路由传参

4.1.1、传递参数

4.1.2、接收参数

4.2、路由钩子

4.2.1、全局守卫

4.2.2、 路由独享守卫

4.2.3、组件内守卫

4.3、路由配置

一、基础语法

1.1、模板 vs JSX

  • Vue 使用基于 HTML 的模板语法,React 使用 JSX (JavaScript 的语法扩展)

1.2、指令

1.2.1、v-for vs Array.map

================vue================
<ul><li v-for="arrs in items" :key="item.id">{{ item.name }}</li>
</ul>
================react================
<ul>{arrs.map(item => (<li key="{item.id}">{item.name}</li>))}
</ul>

1.2.2、v-if vs 三元运算符或者&&

<div v-if="isVisible">显示内容</div>
<div v-else>隐藏内容</div>
=========多条件==========
{isVisible ? (<div>显示内容</div>
) : (<div>隐藏内容</div>
)}
==========单条件==========
{isVisible && <div>显示内容</div>}

1.2.3、v-bind vs 直接在JSX里写{变量}

================vue================
<img :src="imageUrl" :alt="imageAlt" />
================react================
<img src={imageUrl} alt={imageAlt} />

1.2.4、v-show vs style和className

<div v-show="isVisible">显示或隐藏</div>
<div style={{ display: isVisible ? 'block' : 'none' }}>显示或隐藏</div>
==============推荐 CSS 类方式==============
<div className={isVisible ? 'visible' : 'hidden'}>显示或隐藏</div>
.hidden { display: none; }
.visible { display: block; }

1.2.5、v-html vs dangerouslySetInnerHTML

================vue================
<div v-html="rawHtml"></div>
================react================
<div dangerouslySetInnerHTML={{ __html: rawHtml }} />

备注:

  • React 故意命名为 dangerouslySetInnerHTML 以提醒 XSS 风险。

  • 必须传入 { __html: '...' } 对象。

1.3、数据绑定

Vue双向绑定(v-model);

React单向数据流,双向绑定需要通过 value + onChange,推荐受控组件。

<input v-model="message" />
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value" />
import { useState } from 'react';
function App() {const [message, setMessage] = useState('');const handleChange = (e) => {setMessage(e.target.value);};return (<input type="text" value={message} onChange={handleChange} />);
}

1.4、数据初始化

Vue2:data函数;Vue3:ref和reactive;React:useState 或 useReducer

export default {data() {return {num: 0,message: "Hello Vue2",};},
};
const message=ref("Hello Vue3")
import { useState } from 'react';
function App() {const [num, setNum] = useState(0);const [message, setMessage] = useState("Hello React");return (<div><p>{num}</p><p>{message}</p></div>);
}

备注:

  • useState 用于定义响应式变量,返回 [value, setter]

  • 每次状态更新都会触发组件重新渲染

1.5、computed(只能同步)

Vue 的 computed 用于基于响应式数据派生出新数据,React 可以使用 useMemo 或直接在渲染时计算。注意:computed必须有一个返回值,watch不需要。

  computed: {fullName() {return `${this.firstName} ${this.lastName}`;},},
==============vue3计算属性==============
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
import { useState, useMemo } from 'react';
function App() {const [firstName, setFirstName] = useState("John");const [lastName, setLastName] = useState("Doe");// 类似 computed,依赖变化时重新计算const fullName = useMemo(() => {return `${firstName} ${lastName}`;}, [firstName, lastName]);return <p>{fullName}</p>;
}

1.6、watch(可包含异步)

  • Vue 的监听更声明式immediate/deep 直接配置)

  • Vue 3 的 watchEffect 最接近 React 的 useEffect,但依赖追踪更智能

  • React 的监听更命令式,其中默认 useEffect 会立即执行,若不需要可加依赖控制,深度监听推荐使用 use-deep-compare-effect 库,避免 JSON.stringify 性能问题。

watch: {count: {handler(newVal, oldVal) {console.log(`count changed: ${newVal}`);},immediate: true, // 立即执行一次deep: true,      // 深度监听},
},
===============vue3侦听 count 的变化===============
watch(() => count.value,(newVal, oldVal) => {console.log(`count changed: ${newVal}`);},{ immediate: true, deep: true } // 立即执行 + 深度监听
);
// watchEffect(自动立即执行)
watchEffect(() => {console.log(`count is: ${count.value}`); // 立即执行 + 自动追踪依赖
});
import { useState, useEffect } from 'react';
function App() {const [count, setCount] = useState(0);useEffect(() => {console.log("立即执行一次 + count 变化时执行");
}, [count]); // 依赖变化时触发// 仅首次渲染执行(类似 Vue 的 immediate: true)useEffect(() => {console.log("仅第一次渲染时执行");
}, []); // 空依赖数组return (<button onClick={() => setCount(count + 1)}>Increment: {count}</button>);
}
==============补充:深度监听==============
useEffect(() => {console.log("user 变化了");
}, [JSON.stringify(user)]); // 监听序列化后的对象(性能较差)// 或者使用 useDeepCompareEffect(第三方库)
import { useDeepCompareEffect } from 'use-deep-compare';
useDeepCompareEffect(() => {console.log("user 深层变化");
}, [user]);

二、生命周期

2.1、周期总结

阶段Vue 2Vue 3React类组件函数组件(Hooks)
初始化

beforeCreate/created

setup()替代constructoruseState等Hooks
挂载前

beforeMount

onXxx....getDerivedStateFromProps---
挂载完成

mounted

componentDidMountuseEffect(..., [])
更新前

beforeUpdate

getDerivedStateFromProps/

shouldComponentUpdate

---
更新完成

updated

componentDidUpdateuseEffect
卸载前

beforeDestroy

componentWillUnmountuseEffect返回的函数
卸载完成

destroyed

onUnmounted------

其中react的函数组件

1、useEffect:组合了componentDidMount、componentDidUpdate和componentWillUnmount

2、useLayoutEffect:类似useEffect,但在DOM更新后同步触发

3、useMemo/useCallback:性能优化,类似shouldComponentUpdate

2.2、关键差异

初始化阶段:
Vue在beforeCreate/created阶段完成响应式数据初始化
React类组件在constructor初始化状态,函数组件在每次渲染都可能初始化

挂载阶段:
Vue的mounted保证子组件也已挂载
React的componentDidMount不保证子组件已完成挂载

更新机制:
Vue自动追踪依赖,数据变化自动触发更新
React需要手动优化(shouldComponentUpdate/PureComponent/memo)

组合式API vs Hooks:
Vue3的setup()只在初始化时运行一次
React函数组件每次渲染都会运行所有Hooks

销毁/卸载:
Vue有明确的beforeDestroy/destroyed(2.x)或onBeforeUnmount/onUnmounted(3.x)
React只有componentWillUnmountuseEffect的清理函数

三、组件传值

3.1、父传子

===========================Vue2===========================
<!-- 父组件 -->
<Child :title="parentTitle" />
<!-- 子组件 -->
<script>
export default {props: ['title']
}
</script>
===========================Vue3===========================
<!-- 父组件 -->
<Child :title="parentTitle" />
<!-- 子组件 -->
<script setup>
const props = defineProps(['title'])
</script>
// 父组件
<Child title={parentTitle} />
// 子组件
function Child({ title }) {return <div>{title}</div>
}

3.2、子传父

===========================Vue2===========================
<!-- 子组件 -->
<button @click="$emit('update', newValue)">提交</button>
<!-- 父组件 -->
<Child @update="handleUpdate" />
===========================Vue3===========================
<!-- 子组件 -->
const emit = defineEmits(['imported'])
emit('imported', newValue)
<!-- 父组件 -->
<Child @update="handleUpdate" />
// 子组件
function Child({ onUpdate }) {return <button onClick={() => onUpdate(newValue)}>提交</button>
}
// 父组件
<Child onUpdate={handleUpdate} />

3.3、ref( 父组件访问子组件)

===========================Vue2===========================
<!-- 父组件 -->
<Child ref="childRef" />
<script>
export default {mounted() {this.$refs.childRef.childMethod()}
}
</script>
===========================Vue3===========================
<!-- 父组件 -->
<Child ref="childRef" />
<script setup>
import { ref, onMounted } from 'vue'
const childRef = ref(null)
onMounted(() => {childRef.value.childMethod()
})
</script>
// 父组件
function Parent() {const childRef = useRef(null)useEffect(() => {childRef.current.childMethod()}, [])return <Child ref={childRef} />
}
// 子组件需要使用 forwardRef
const Child = forwardRef((props, ref) => {useImperativeHandle(ref, () => ({childMethod: () => {console.log('子组件方法被调用')}}))return <div>子组件</div>
})

3.4、数据共享

===========================Vue2===========================
// store.js
export default new Vuex.Store({state: { count: 0 },mutations: {increment(state) {state.count++}}
})
// 组件中使用
this.$store.state.count
this.$store.commit('increment')
===========================Vue3===========================
// store.js
export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),actions: {increment() {this.count++}}
})
// 组件中使用
const store = useCounterStore()
store.count
store.increment()
// store.js
const counterSlice = createSlice({name: 'counter',initialState: { value: 0 },reducers: {increment(state) {state.value++}}
})
export const store = configureStore({reducer: {counter: counterSlice.reducer}
})
// 组件中使用
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
dispatch(increment())

3.5、跨组件通信

3.5.1、事件总线/发布订阅

===========================Vue2===========================
// eventBus.js
export const bus = new Vue()
// 组件A
bus.$emit('event-name', data)
// 组件B
bus.$on('event-name', handler)
===========================Vue3===========================
// mitt库
import mitt from 'mitt'
export const emitter = mitt()
// 组件A
emitter.emit('event-name', data)
// 组件B
emitter.on('event-name', handler)
// 自定义事件总线
class EventBus {constructor() {this.events = {}}// 实现on/emit/off等方法
}
export const eventBus = new EventBus()
// 组件A
eventBus.emit('event-name', data)
// 组件B
useEffect(() => {const handler = (data) => {}eventBus.on('event-name', handler)return () => eventBus.off('event-name', handler)
}, [])

3.5.2、Provide-Inject/Context

// 祖先组件
export default {provide() {return {sharedData: this.sharedData}}
}
// 后代组件
export default {inject: ['sharedData']
}
// 创建Context
const MyContext = createContext()
// 祖先组件
<MyContext.Provider value={sharedData}><Child />
</MyContext.Provider>
// 后代组件
const sharedData = useContext(MyContext)

四、路由

4.1、路由传参

4.1.1、传递参数

==========================声明式导航传参==========================
<!-- 传递params参数 -->
<router-link :to="{ name: 'user', params: { id: 123 }}">用户</router-link>
<!-- 传递query参数 -->
<router-link :to="{ path: '/user', query: { id: 123 }}">用户</router-link>
==========================编程式导航传参==========================
// params传参
this.$router.push({ name: 'user', params: { id: 123 } })
// query传参
this.$router.push({ path: '/user', query: { id: 123 } })
==========================Vue3==========================
<router-link :to="{ name: 'User', params: { id: userId }}">用户</router-link>
<router-link :to="{ path: '/user', query: { id: userId }}">用户</router-link>
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({ name: 'User', params: { id: userId } })
router.push({ path: '/user', query: { id: userId } })
==========================声明式导航传参==========================
// 传递params参数
<Link to="/user/123">用户</Link>
// 传递query参数
<Link to="/user?id=123">用户</Link>
==========================编程式导航传参==========================
// params传参
navigate('/user/123')
// query传参
navigate('/user?id=123')
// state传参(不显示在URL中)
navigate('/user', { state: { id: 123 } })

4.1.2、接收参数

// 获取params
this.$route.params.id
// 获取query
this.$route.query.id
=========================Vue3=========================
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id
const userId = route.query.id
</script>
// 获取params
const { id } = useParams()
// 获取query
const [searchParams] = useSearchParams()
const id = searchParams.get('id')
// 获取state
const { state } = useLocation()
const id = state?.id

4.2、路由钩子

4.2.1、全局守卫

// 全局前置守卫
router.beforeEach((to, from, next) => {// 登录验证逻辑if (to.meta.requiresAuth && !isAuthenticated) {next('/login')} else {next()}
})
// 全局后置钩子
router.afterEach((to, from) => {// 页面访问统计等
})
// 使用自定义Wrapper组件
function PrivateRoute({ children }) {const location = useLocation()const isAuthenticated = useAuth()if (!isAuthenticated) {return <Navigate to="/login" state={{ from: location }} replace />}return children
}
// 使用方式
<Routepath="/dashboard"element={<PrivateRoute><Dashboard /></PrivateRoute>}
/>

4.2.2、 路由独享守卫

{path: '/dashboard',component: Dashboard,beforeEnter: (to, from, next) => {if (!isAuthenticated) next('/login')else next()}
}
// 在组件内使用useEffect模拟
function Dashboard() {const navigate = useNavigate()const isAuthenticated = useAuth()useEffect(() => {if (!isAuthenticated) {navigate('/login')}}, [isAuthenticated, navigate])return <div>Dashboard</div>
}

4.2.3、组件内守卫

export default {beforeRouteEnter(to, from, next) {// 不能访问thisnext(vm => {// 通过vm访问组件实例})},beforeRouteUpdate(to, from, next) {// 当前路由改变但组件被复用时调用next()},beforeRouteLeave(to, from, next) {if (hasUnsavedChanges) {next(false) // 取消导航} else {next()}}
}
=============================Vue3=============================
// 组件内守卫
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from) => {if (hasUnsavedChanges) {return confirm('确定要离开吗?')}
})
function UserProfile() {const navigate = useNavigate()const [hasUnsavedChanges, setHasUnsavedChanges] = useState(true)// 模拟beforeRouteLeaveuseEffect(() => {const unblock = navigate((location, action) => {if (hasUnsavedChanges && action === 'POP') {return window.confirm('确定要离开吗?未保存的更改将会丢失')}return true})return () => unblock()}, [hasUnsavedChanges, navigate])return <div>User Profile</div>
}

4.3、路由配置

const routes = [{path: '/',name: 'Home',component: Home,meta: { requiresAuth: true }},{path: '/user/:id',component: User,props: true // 将params作为props传递}
]
const router = createBrowserRouter([{path: '/',element: <Home />,loader: () => fetchData(), // 数据预加载shouldRevalidate: () => false // 控制是否重新验证},{path: 'user/:id',element: <User />,errorElement: <ErrorPage /> // 错误处理}
])

这里的路由是vue2/3对比react-router-dom v6

功能Vue 2/3 (vue-router)React (react-router-dom v6)
路由传参params/query分开params/query/state多种方式
路由守卫全局/独享/组件内都有依赖组件组合和自定义Hook实现
路由配置集中式配置集中式和分散式配置
动态路由addRoute原生支持动态路由
数据预加载自行实现内置loader机制
嵌套路由children嵌套嵌套路由布局更直观

Vue2生命周期详情:Vue核心概念详解-CSDN博客

Vue2路由详情:Vue2.x(2)_vue2 import-CSDN博客

Vue2Vuex详情:Vue.js实战:深度解析Vuex状态管理与实战应用-CSDN博客

Vue3语法详情:vue3(语法应用集合)_vue3+vite+pinia-CSDN博客

React生命周期与父子通信详情:react实例与总结(一)-CSDN博客

ReactRedux详情:react的redux总结_react redux工作流程-CSDN博客

React路由详情:react路由总结_react路由插件-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89334.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89334.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/89334.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

插板式系统的“生命线“:EtherCAT分布式供电该如何实现?

在ZIO系列插板式模组系统中&#xff0c;EtherCAT分布式供电如同设备的血液循环网络&#xff0c;其供电稳定性直接决定系统可靠性。本文将从电流计算到电源扩展&#xff0c;为您讲解EtherCAT分布式供电该如何实现。ZIO系列插板式模组的电源介绍ZIO系列插板式I/O模块 是ZLG开发的…

Qwen2-VL:提升视觉语言模型对任意分辨率世界的感知能力

温馨提示&#xff1a; 本篇文章已同步至"AI专题精讲" Qwen2-VL&#xff1a;提升视觉语言模型对任意分辨率世界的感知能力 摘要 我们提出了 Qwen2-VL 系列&#xff0c;这是对先前 Qwen-VL 模型的重大升级&#xff0c;重新定义了视觉处理中传统的预设分辨率方法。Qwe…

C++类模版与友元

全局函数类内实现-直接在类内声明友元即可全局函数类外实现-需要提前让编译器知道全局函数的存在#include <iostream> using namespace std;//通过全局函数来打印Person的信息template<class T1,class T2> class Person{//全局函数&#xff0c;类内实现friend void…

Linux Java环境配置

1.进入java官网&#xff0c;点击Java archive Java Downloads | Oracle 中国https://www.oracle.com/cn/java/technologies/downloads/ 2.然后下滑选择你要安装的java版本&#xff0c;这里我选择的是java8 3.依据系统架构选择版本安装&#xff0c;x86&#xff0c;x64&#xf…

flutter app内跳转到其他安卓 app的方法

flutter 内的关键代码导包&#xff1a;url_launcher: ^6.3.1跳转逻辑&#xff1a;onPressed: () async {await launchUrl(Uri.parse(demoname://));},安卓内的关键代码<intent-filter><action android:name"android.intent.action.VIEW" /><category …

医疗资质OCR智能审核:让合规管理更高效、更精准

在医疗行业&#xff0c;资质证件的审核是确保机构合规运营的关键环节。从医疗机构执业许可证到医师资格证&#xff0c;从药品经营许可证到医疗器械注册证&#xff0c;传统人工审核方式效率低下且容易出错。现在&#xff0c;医疗资质OCR智能审核解决方案正在重塑行业标准&#x…

利用 Spring 的 `@Scheduled` 注解结合简单的状态跟踪实现空闲检测方案

一种基于定时任务和简单状态跟踪的方法: 实现思路 记录用户的最后活动时间:每当用户进行某些操作(如点击、请求等),更新其最后活动的时间戳。 使用定时任务检查用户是否空闲:设置一个后台任务,定期检查每个用户的最后活动时间,判断是否超过了设定的空闲时间阈值。 执行…

如何在 Ubuntu 上安装 Microsoft Edge 浏览器?

Microsoft Edge 是 Microsoft 在2015年开发的跨平台浏览器&#xff0c;最初是建立在他们自己的浏览器引擎和 Chakra JavaScript 引擎之上的&#xff0c;此浏览器可防止恶意网站和下载文件。 本文将帮助您在 Ubuntu 系统上安装 Microsoft Edge 浏览器。 1: 下载 Edge Browser …

16路串口光纤通信FPGA项目实现指南 - 第二部分(下)

16路串口光纤通信FPGA项目实现指南 - 第二部分&#xff08;下&#xff09; 五、核心控制逻辑实现&#xff08;接收部分&#xff09; 5.4 数据接收控制逻辑 // 接收数据寄存逻辑 reg rs422_rx_valid; // 接收数据有效信号 reg [15:0] rs422_rx_data; // 接收数据寄存器…

前后端分离项目的完整部署(Jenkins自动化部署)

人工部署方式&#xff0c;参考文章&#xff1a; 前后端分离项目的完整部署&#xff08;人工部署&#xff09;-CSDN博客 目标 在Windows操作系统上&#xff0c;使用Jenkins完成源代码的自动拉取、编译、打包、发布工作。 项目背景 前端使用vue&#xff0c;程序打包后为dist目…

Python设计模式深度解析:装饰器模式(Decorator Pattern)完全指南

Python设计模式深度解析&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09;完全指南前言什么是装饰器模式&#xff1f;装饰器模式的核心思想Python函数装饰器&#xff1a;从基础到高级基础函数装饰器高级函数装饰器实现GUI装饰器模式&#xff1a;动态界面增强Tk…

JVM--虚拟线程

首先了解一个理念&#xff1a;线程与 OS 线程 1:1 绑定在传统 Java 线程&#xff08;平台线程&#xff09;模型中&#xff1a;每个 Java 线程直接对应一个操作系统级别的线程操作系统负责调度这些线程线程的创建、管理和调度都由操作系统内核处理这种模型称为 1:1 线程模型&…

掌握系统设计的精髓:12个核心设计模式的通俗解读

在构建复杂且高可用的软件系统时&#xff0c;仅仅了解编程语言和算法是不够的。真正的挑战在于如何设计出能够应对并发、故障、扩展等各种问题的健壮架构。系统设计模式正是前辈们在无数实践中提炼出的智慧结晶&#xff0c;它们是解决常见系统问题的“最佳实践”。 本文将深入浅…

概率论与数理统计(二)

事件的概率 概率&#xff1a;可能性的大小 古典概率模型&#xff1a; 1&#xff09;有限个样本点 2&#xff09;等可能性 P(A)A中包含的基本事件数基本事件总和 P(A) \frac{A中包含的基本事件数}{基本事件总和} P(A)基本事件总和A中包含的基本事件数​ 频率与概率 nnn 次实验…

新型eSIM攻击技术可克隆用户资料并劫持手机身份

eSIM技术存在重大安全漏洞研究人员发现eSIM技术中存在一个关键漏洞&#xff0c;攻击者可利用该漏洞克隆移动用户资料并劫持手机身份。AG安全研究团队宣布&#xff0c;他们成功攻破了采用GSMA消费者证书的Kigen eUICC&#xff08;嵌入式通用集成电路卡&#xff09;安全防护&…

langchain教程2:更加高级和灵活的Prompt模板

文章目录 prompt模板 对话Prompt模板 函数大师 使用jinja2与f-string实现提示词模板格式化 组合式提示词模板 prompt模板 from langchain.prompts import PromptTemplateprompt = PromptTemplate.from_template("你是一个{name},帮我起一个具有{country}特色的{gender}名…

UE5使用Motion Warping有什么用?

在 UE5 中&#xff0c;Motion Warping 是一套用于「动态调整根运动动画」的系统插件&#xff0c;它能让带有根运动&#xff08;Root Motion&#xff09;的动画根据游戏运行时的环境自动变形&#xff08;Warp&#xff09;&#xff0c;以更精准地贴合目标位置或目标方向&#xff…

类模版的相关案例

案例实现&#xff1a;实现一个通用的数组类&#xff0c;要求如下&#xff1a;可以对内置数据类型以及自定义数据类型的数据进行存储将数组中的数据存储到堆区构造函数中可以传入数组的容量提供对应的拷贝构造函数以及operator防止浅拷贝问题提供尾插法和尾删法对数组中的数据进…

服务器端安全检测与防御技术概述

一、服务器安全风险1.不必要的访问&#xff08;如只提供HTTP服务&#xff09;--应用识别控制2.公网发起IP或端口扫描、DDOS攻击等--防火墙3.漏洞攻击&#xff08;针对服务器操作系统等&#xff09;--IPS4.根据软件版本的已知漏洞进行攻击&#xff0c;口令暴力破解、获取用户权限…

前端性能与可靠性工程系列: 渲染、缓存与关键路径优化

前端性能与可靠性工程系列: 渲染、缓存与关键路径优化 第一部分:揭秘浏览器 - 关键渲染路径 (CRP) 关键渲染路径 (Critical Rendering Path - CRP) 是指浏览器从接收到最初的 HTML、CSS 和 JavaScript 字节,到最终将它们渲染成可见像素所必须经过的一系列步骤。我们的目标,…