WHAT - Vue3 重要知识点梳理系列(一)

本文内容基于:https://cn.vuejs.org/

一、什么是 Vue

  • 声明式
  • 响应性
  • 组件化

二、对比其他框架:React

参考阅读:https://v2.cn.vuejs.org/v2/guide/comparison.html#React

2.1 相似之处

React 和 Vue 有许多相似之处,比如它们都:

  • 使用 Virtual DOM
  • 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件。
  • 将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。

下面的内容可能会有些过时,仅供参考

接下来将主要介绍几个重要维度的区别。

1. 运行时性能

React 和 Vue 都是非常快的,所以速度并不是在它们之中做选择的决定性因素。

那可以从两者在渲染上做的优化出发进行比较

在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手动实现 shouldComponentUpdate 方法。同时你可能会需要使用不可变的数据结构来使得你的组件更容易被优化。

下面是一个示例,演示了如何使用 PureComponent 来避免不必要的子组件重渲染:

import React, { PureComponent } from 'react';
// 子组件
class ChildComponent extends PureComponent {
  render() {
    console.log('ChildComponent rendering');
    return <div>{this.props.value}</div>;
  }
}
// 父组件
class ParentComponent extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    // 当点击按钮时,只修改 count 值
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  }
  render() {
    console.log('ParentComponent rendering');
    return (
      <div>
        <button onClick={this.handleClick}>Increment</button>
        <ChildComponent value={this.state.count} />
      </div>
    );
  }
}
export default ParentComponent;

在上面的示例中,ChildComponent 是一个纯函数组件,它继承自 PureComponent。这意味着它会自动进行浅比较来检测是否需要重新渲染。因此,即使 ParentComponent 的状态在每次更新时都会改变,只有当 value 发生实际变化时,ChildComponent 才会重新渲染。

然而,使用 PureComponent 和 shouldComponentUpdate 时,需要保证该组件的整个子树的渲染输出都是由该组件的 props 所决定的。如果不符合这个情况,那么此类优化就会导致难以察觉的渲染结果不一致。这使得 React 中的组件优化伴随着相当的心智负担。

而在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。Vue 的这个特点使得开发者不再需要考虑 react 此类主动性优化,从而能够更好地专注于应用开发本身。

2. html & css

在 React 中,一切都是 JavaScript。不仅仅是 HTML 可以用 JSX 来表达,现在的潮流也越来越多地将 CSS 也纳入到 JavaScript 中来处理。这类方案有其优点,但也存在一些不是每个开发者都能接受的取舍。

Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。

首先介绍 jsxtemplates

在 React 中,所有的组件的渲染功能都依靠 JSX。JSX 是使用 XML 语法编写 JavaScript 的一种语法糖。使用 JSX 的渲染函数有下面这些优势:

  1. 你可以使用完整的编程语言 JavaScript 功能来构建你的视图页面。比如你可以使用临时变量、JS 自带的流程控制、以及直接引用当前 JS 作用域中的值等等。
  2. 开发工具对 JSX 的支持相比于现有可用的其他 Vue 模板还是比较先进的(比如,linting、类型检查、编辑器的代码自动补全等)。

事实上 Vue 也提供了渲染函数,甚至支持 JSX。然而,Vue 官方默认推荐的还是模板。优势如下:

  1. 对于很多习惯了 HTML 的开发者来说,模板比起 JSX 读写起来更自然
  2. 基于 HTML 的模板使得将已有的应用逐步迁移到 Vue 更为容易
  3. 在 Vue 中,模板语法可以被认为是一种 DSL(领域特定语言),因为它是专门为描述用户界面而设计的语言。有些开发者认为这需要额外的学习成本。但注意,JSX 并不是没有学习成本的——它是基于 JS 之上的一套额外语法。而且 DSL 的存在使得我们可以让开发者用更少的代码做更多的事,比如 v-on 的各种修饰符,在 JSX 中实现对应的功能会需要多得多的代码。

更抽象一点来看,我们可以把组件区分为两类:一类是偏视图表现的,一类则是偏逻辑的。我们推荐在前者中使用模板,在后者中使用 JSX 或渲染函数。

两类组件的比例会根据应用类型的不同有所变化,但整体来说可以发现表现类的组件远远多于逻辑类组件。

3. 组件作用域的 css

首先,我们需要在 React 中,通常可以使用以下几种方式来管理 CSS 的作用域:

  • 普通的 css 文件

在 React 应用中,你可以像平常一样创建 .css 文件,并在组件中使用它们。但是,普通的 CSS 文件中的样式是全局生效的,可能会导致样式冲突和命名空间污染的问题。

  • CSS Modules

CSS Modules 是一种将 CSS 代码与特定组件相关联的方法。通过将 CSS 作为模块导入并自动生成唯一的类名,CSS Modules 可以避免全局作用域污染和样式冲突。在 Webpack 中,你可以使用 css-loader 配置 CSS Modules;在 Vite 中,CSS Modules 是内置支持的。

以下是一个简单的示例,演示如何在 React 应用中使用 CSS Modules,假设有一个 styles.module.css 文件:

/* styles.module.css */
.container {
  width: 100%;
  padding: 20px;
  background-color: #f0f0f0;
}
.title {
  color: #333;
  font-size: 24px;
}

然后,在 React 组件中,可以这样导入并使用 CSS Modules:

import React from 'react';
import styles from './styles.module.css';
const MyComponent = () => {
  return (
    <div className={styles.container}>
      <h1 className={styles.title}>Hello, CSS Modules!</h1>
    </div>
  );
};
export default MyComponent;

这样做的好处是,CSS 类名会自动成为局部作用域,只在当前组件范围内有效,避免了全局样式的污染和命名冲突。

  • CSS-in-JS

CSS-in-JS 是一种将 CSS 样式直接写入 JavaScript 文件中的方法,通过使用 JavaScript 的对象或函数来定义样式,并将其动态地应用到组件上。

常见的 CSS-in-JS 解决方案包括 Styled ComponentsEmotion 等。这些库允许开发者在组件级别管理样式,并提供了更灵活、更强大的样式组织和动态化能力。

以下是一个简单的使用 Styled Components 库进行 CSS-in-JS 的示例:

首先,你需要安装 Styled Components 库:

npm install styled-components

然后,在你的 React 组件中,可以这样使用 Styled Components:

import React from 'react';
import styled from 'styled-components';

// 创建一个 Styled 组件
const Button = styled.button`
  background-color: #007bff;
  color: #fff;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;

  &:hover {
    background-color: #0056b3;
  }
`;

// 在组件中使用 Styled 组件
const MyComponent = () => {
  return (
    <div>
      <h1>Styled Components Example</h1>
      <Button>Click Me</Button>
    </div>
  );
};

export default MyComponent;

在上面的示例中,我们使用 styled 函数从 Styled Components 库中创建了一个名为 Button 的组件,并定义了该组件的样式。然后,我们在 MyComponent 组件中使用了这个 Button 组件,并在 JSX 中像使用普通的 React 组件一样使用它。

React 更多用的是 CSS-in-JS,这引入了一个新的面向组件的样式范例,它和普通的 CSS 撰写过程是有区别的。

另外,虽然 React 在构建时将 CSS 提取到一个单独的样式表是支持的,但 bundle 里通常还是需要一个运行时程序来让这些样式生效。当你能够利用 JavaScript 灵活处理样式的同时,也需要权衡 bundle 的尺寸和运行时的开销。

这里 Vue 和 React 主要的区别是,Vue 设置样式的默认方法是单文件组件里类似 <style> 的标签。

单文件组件让你可以在同一个文件里完全控制 CSS,将其作为组件代码的一部分。

<style scoped>
  @media (min-width: 250px) {
    .list-container:hover {
      background: orange;
    }
  }
</style>

注意,这个可选 scoped attribute 会自动添加一个唯一的 attribute (比如 data-v-21e5b78) 为组件内 CSS 指定作用域,编译的时候 .list-container:hover 会被编译成类似 .list-container[data-v-21e5b78]:hover。如此,可实现组件作用域,避免全局样式冲突。

4. 学习曲线

React 和 Vue 就学习曲线而言,以下是一些比较:

  1. React 学习曲线

    • JSX:React 使用 JSX 语法来描述组件的结构和逻辑,这可能会对初学者造成一定的学习障碍,特别是对于那些不熟悉 JavaScript 和 HTML 的人来说。
    • 灵活性:React 提供了更多的灵活性,开发者可以更自由地选择和配置各种工具和库,但这也意味着开发者需要更多的决策和配置。
    • 状态管理:React 并没有内置的状态管理解决方案,通常需要选择并集成其他库,如 Redux、MobX 等,这可能会增加学习成本。
    • 生态系统:React 生态系统庞大而丰富,有大量的第三方库和工具可供选择,但这也意味着初学者需要花费更多时间去了解和选择适合自己的工具。
  2. Vue 学习曲线

    • 模板语法:Vue 使用模板语法来描述组件,这种语法更接近传统的 HTML 和 CSS,相对于 JSX 来说更容易理解和上手。
    • 集成性:Vue 提供了大量的内置功能,如路由、状态管理、组件化等,这些功能的集成更加简单和直接,使得初学者可以更快地上手。
    • 状态管理:Vue 内置了 Vuex 状态管理库,可以直接在 Vue 应用中使用,不需要额外学习和集成其他库。
    • 生态系统:Vue 生态系统虽然相对较小,但也很健全和成熟,有很多高质量的插件和工具可供选择,不过与 React 相比可能稍显不足。

综上所述,React 和 Vue 都有自己的学习曲线,选择哪一个取决于个人的偏好、项目需求以及团队的技术栈。

一般来说,对于有 JavaScript 和 HTML 基础的开发者来说,Vue 的学习曲线可能会更加平缓和友好一些,而对于有更多自由和灵活性要求的开发者来说,React 可能更适合。

三、在项目中引入 Vue 的方式

Vue 被设计成一个灵活的、可以渐进式集成的框架。

1. 独立 CDN 脚本

Vue 可以以一个单独 JS 文件的形式使用,无需构建步骤!

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

<div id="app">{{ message }}</div>
<script>
  const { createApp, ref } = Vue
  createApp({
    setup() {
      const message = ref('Hello vue!')
      return {
        message
      }
    }
  }).mount('#app')
</script>

上述示例使用了全局构建版本的 Vue,该版本的所有顶层 API 都以属性的形式暴露在了全局的 Vue 对象上。

这样的方式比较适合当你的后端框架已经渲染了大部分的 HTML,或者你的前端逻辑并不复杂,不需要构建步骤的场景。

Vue 也提供了另一个更适用于此类无构建步骤场景的版本 petite-vue。Petite-Vue 是一个基于 Vue 3 的微型、渐进式的 Vue.js 替代方案。它的目标是提供一个更轻量级、更简单的 Vue 实现,以满足一些简单应用场景或者更注重性能的需求。

当然,现代浏览器大多都已原生支持 ES 模块,因此我们可以像这样通过 CDN 以及原生 ES 模块使用 Vue:

<div id="app">{{ message }}</div>

<script type="module">
  import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  createApp({
    setup() {
      const message = ref('Hello Vue!')
      return {
        message
      }
    }
  }).mount('#app')
</script>

注意我们使用了 <script type="module">,且导入的 CDN URL 指向的是 Vue 的 ES 模块构建版本。

2. 作为 Web Component 嵌入

你可以用 Vue 来构建标准的 Web Component,这些 Web Component 可以嵌入到任何 HTML 页面中,无论它们是如何被渲染的。

这使得我们可以在不同的环境中重用 Vue 组件,而无需担心最终使用场景:因为生成的 Web Component 可以嵌入到旧应用、静态 HTML,甚至用其他框架构建的应用中。

要将 Vue 组件转换为 Web Component,我们可以使用 vue-custom-element 库。

下面是一个简单的示例,演示了如何将 Vue 组件转换为 Web Component:

首先,安装 vue-custom-element

npm install vue-custom-element

然后,在 Vue 组件中注册并导出 Web Component:

<template>
  <button @click="handleClick">{{ text }}</button>
</template>

<script>
import Vue from 'vue';
import vueCustomElement from 'vue-custom-element';

Vue.use(vueCustomElement);

export default Vue.customElement('my-button', {
  props: ['text'],
  methods: {
    handleClick() {
      this.$emit('click');
    }
  },
  // 渲染函数,将组件内容渲染到 shadow DOM 中
  render(h) {
    return h('button', {
      on: {
        click: this.handleClick
      }
    }, this.text);
  }
});
</script>

然后,可以像使用普通的 HTML 元素一样,在其他环境中使用我们的 Web Component:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue Web Component Example</title>
</head>
<body>
  <my-button text="Click Me"></my-button>

  <script src="https://unpkg.com/vue"></script>
  <script src="./path/to/compiled-component.js"></script>
</body>
</html>

在这个示例中,我们将 Vue 组件转换为了名为 my-button 的 Web Component,并在 HTML 页面中使用它。这样一来,我们可以将 Vue 组件嵌入到任何 HTML 页面中,而不需要担心最终使用场景。

3. 单页面应用:SPA

一些应用在前端需要具有丰富的交互性、较深的会话和复杂的状态逻辑。构建这类应用的最佳方法是使用这样一种架构:Vue 不仅控制整个页面,还负责处理抓取新数据,并在无需重新加载的前提下处理页面切换。这种类型的应用通常称为单页应用 (Single-Page application,缩写为 SPA)。

Vue 提供了核心功能库和全面的工具链支持,为现代 SPA 提供了极佳的开发体验,覆盖以下方面:

  1. 客户端路由管理
  2. 快速的构建工具
  3. ide 支持
  4. 浏览器开发工具 vue-tool
  5. Typescript 支持
  6. 测试工具支持

4. 服务端渲染:SSR

纯客户端的 SPA 在首屏加载和 SEO 方面有显著的问题,因为浏览器会收到一个巨大的 HTML 空页面,只有等到 JavaScript 加载完毕才会渲染出内容。

Vue 也提供了一系列 API,支持将一个 Vue 应用在服务端渲染成 HTML 字符串。这能让服务器直接返回渲染好的 HTML,让用户在 JavaScript 下载完毕前就看到页面内容。然后,Vue 之后会在客户端对应用进行“激活 (hydrate)”使其重获可交互性。这被称为服务端渲染 (SSR),它能够极大地改善应用在 Web 核心指标上的性能表现,如最大内容绘制 (LCP)。

对于 SPA 应用,因其本身设计存在的首屏加载问题,一般不关注 LCP

Vue 生态中有一些针对此类场景的、基于 Vue 的上层框架,比如 NuxtJS,能让你用 Vue 和 JavaScript 开发一个全栈应用。

注意 nuxtjs、nextjs,以及 nestjs 的区别

5. 静态站点生成:SSG / JAMStack

如果所需的数据是静态的,那么服务端渲染可以提前完成。这意味着我们可以将整个应用预渲染为 HTML,并将其作为静态文件部署。

这增强了站点的性能表现,也使部署变得更容易,因为我们无需根据请求动态地渲染页面。

SSG 有两种风格:单页和多页。这两种风格都能将站点预渲染为静态 HTML。

  • 单页 SSG

单页 SSG 指的是生成一个单独的 HTML 文件,通常对应着一个单独的页面。

在构建时,静态生成器会根据页面的模板和数据生成这个 HTML 文件,并将其存储在静态文件服务器上。在前端展示时,单页 SSG 在初始页面加载后将其“激活”为 SPA。

这种模式需要更多的前期 JS 加载和激活成本,只不过后续的导航也将更快,因为它只需要部分地更新页面内容,而无需重新加载整个页面。

单页 SSG 适用于那些只有少量页面的网站,例如个人博客、产品介绍页面等。它们的内容相对固定,不需要动态生成内容。

  • 多页 SSG

多页 SSG 指的是生成多个 HTML 文件,每个文件对应着一个页面。

在构建时,静态生成器会遍历整个站点的路由,并根据每个路由生成相应的 HTML 文件。在前端展示时,每次导航都会加载一个新页面。

这样的好处是它在每次加载时可以仅需最少的 JS——或者如果页面无需交互则根本不需要 JS!

多页 SSG 适用于那些包含多个页面的网站,例如企业网站、电子商务网站等。这些网站可能有不同的页面和功能,需要为每个页面生成独立的 HTML 文件。而且可能内容有动态成分存在。

注意,一些多页面 SSG 框架,如 Astro 也支持“部分激活”——它允许你通过 Vue 组件在静态 HTML 中创建交互式的“孤岛”。

总之,单页 SSG 更适合于小规模、重交互、深会话的场景,或需要在导航之间持久化元素或状态。否则,多页 SSG 将是更好的选择。

对于该场景,Vue 团队也维护了一个名为 VitePress 的静态站点生成器,Vue 官方文档就是基于它构建的!VitePress 支持两种形式的 SSG。

另外,NuxtJS 也支持 SSG。你甚至可以在同一个 Nuxt 应用中通过不同的路由提供 SSR 和 SSG。

6. Web 之外

尽管 Vue 主要是为构建 Web 应用而设计的,但它绝不仅仅局限于浏览器。你还可以:

  1. 配合 Electron 构建桌面应用
  2. 配合 Ionic Vue 构建移动端应用
  3. 使用 Quasar 或 Tauri 用同一套代码同时开发桌面端和移动端应用
  4. 使用 TresJS 构建 3D WebGL 体验
  5. 使用 Vue 的自定义渲染 API 来构建自定义渲染器,比如针对终端命令行的 vue-termui
  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值