Vue3 学习笔记 —— 重新了解 Vue3 新特性

目录

一. 使用 Vite 搭建环境

1. Vite 的优势

2. Vite 安装和使用

2.1 初始化项目

2.2 Vite 命令行(package.json)

3. Vite 项目目录

二. 重新学习 Vue3 新特性

1. 实现双向数据绑定

1.1 Vue2 基于 Object.defineProperty() 实现

1.2 Vue3 基于 Proxy 实现

2. 优化 Vdom

2.1 什么是虚拟 DOM

2.2 为什么使用虚拟 DOM

2.3 介绍 Diff 算法

2.4 Vue3 中如何优化 Vdom

3. 补丁标记(patch flag)

3.1 什么是补丁标记(patch flag)

3.2 补丁标记如何优化静态树

3.3 新增的补丁标记(patch flag)

4. Fragment

4.1 支持多个根节点

4.2 支持 render JSX 写法

5. Tree Shaking

5.1 Vue2 中如何处理多余的代码

5.2 Vue3 中如何处理多余的代码

6. Composition API

7. SFC 语法规范


本文是基于 B站up主 小满zs Vue3专栏视频 进行的学习和补充,他在 CSDN 是有账号的,讲的很清楚,非常值得学习🎉

小满zs的博客_CSDN博客-Vue3,typeScript,前端领域博主小满zs擅长Vue3,typeScript,前端,等方面的知识,小满zs关注前端框架,node.js,vue.js,小程序,javascript领域.https://blog.csdn.net/qq1195566313?type=blog


一. 使用 Vite 搭建环境

1. Vite 的优势

开始 {#getting-started} | Vite中文网下一代前端开发与构建工具https://vitejs.cn/guide/

1.1 冷服务(原生 ESM、原生 ESM 动态导入)

JavaScript modules: dynamic import() | Can I use... Support tables for HTML5, CSS3, etchttps://caniuse.com/es6-module-dynamic-import默认 的构建目标浏览器是能 在 script 标签上支持原生 ESM 和 原生 ESM 动态导入

传统浏览器可以通过官方插件 @vitejs/plugin-legacy 支持 —— 查看 构建生产版本 章节获取更多细节

1.2 HMR(模块热更新,速度超快)

Vite 提供了一套原生 ESM 的 HMR API。 具有 HMR 功能的框架可以利用该 API 提供即时、准确的更新,而无需重新加载页面或清除应用程序状态。Vite 内置了 HMR 到 Vue 单文件组件(SFC) 和 React Fast Refresh 中。也通过 @prefresh/vite 对 Preact 实现了官方集成

注意,你不需要手动设置这些 —— 当你通过 create-vite 创建应用程序时,所选模板已经为你预先配置了这些

1.3 Rollup 打包

rollup.jshttps://rollupjs.org/guide/en/Vite 使用 Rollup 打包代码,Vite 支持大部分 Rollup 插件,Vite 中的 Rollup 是预配置的,可输出用于生产环境的高度优化过的静态资源

2. Vite 安装和使用

2.1 初始化项目

可以通过附加的命令行选项,直接指定项目名称和想要使用的模板

模板可替换为:vanilla,vanilla-ts,vue,vue-ts,react,react-ts,preact,preact-ts,lit,lit-ts,svelte,svelte-ts

# npm 6.x
npm init vite@latest my-vue-app --template vue

# npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app -- --template vue

2.2 Vite 命令行(package.json)

  • 可以指定额外的命令行选项,如 --port 或 --https
  • 运行 npx vite --help 获得完整的命令行选项列表
{
  "scripts": {
    "dev": "vite", // 启动开发服务器,别名:`vite dev`,`vite serve`
    "build": "vite build", // 为生产环境构建产物
    "preview": "vite preview" // 本地预览生产构建产物
  }
}

3. Vite 项目目录

3.1 public vs assets

public 下面的内容不会 被编译,可以存放静态资源

assets 存放了可编译的 静态资源

3.2 index.html

Vite 的入口文件是 html 文件,也就是 index.html

Webpack,Rollup 的入口文件都是是 js 文件,也就是 enrty input

Vite 刚开始不会编译 index.html 中的 js 文件,当你用到某些 js 文件时(比如 script src="xxxxx.js"),Vite 才会才会解析这些文件

3.3 vite config ts

Vite 的配置文件

二. 重新学习 Vue3 新特性

1. 实现双向数据绑定

1.1 Vue2 基于 Object.defineProperty() 实现

Object.defineProperty() - JavaScript | MDNObject.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

1.2 Vue3 基于 Proxy 实现

proxy 与 Object.defineProperty(obj, prop, desc) 方式相比的优势:

  • 丢掉麻烦的备份数据
  • 省去for in 循环
  • 可以监听数组变化
  • 代码更简化
  • 可以监听动态新增的属性
  • 可以监听删除的属性
  • 可以监听数组的索引和 length 属性
let proxyObj = new Proxy(obj, {
  get: function (target, prop) {
    return prop in target ? target[prop] : 0;
  },
  set: function (target, prop, value) {
    target[prop] = 888;
  },
});

 

2. 优化 Vdom

2.1 什么是虚拟 DOM

虚拟 DOM,就是通过 JavaScript 生成一个 AST 节点树

Vue Template Explorerhttps://vue-next-template-explorer.netlify.app/#eyJzcmMiOiI8ZGl2PkhlbGxvIFdvcmxkITwvZGl2PiIsIm9wdGlvbnMiOnt9fQ==可以通过上面的网站,自动生成 AST 节点树(还能输入 vue 语法,看到静态标记哦)

2.2 为什么使用虚拟 DOM

let div = document.createElement('div')
let str = ''
for (const key in div) {
  str += key + '、'
}
console.log(str)

上面的代码打印出了一个 div 的全部属性,打印结果:

​ 

综上所述,直接操作 DOM 非常浪费性能,要尽可能少的操作DOM

可以用 JavaScript 的计算性能,来换取操作 DOM 所消耗的性能(操作 JavaScript 是非常快的)

2.3 介绍 Diff 算法

<template>
  <div>
    <div v-for="(item) in TestArr" :key="item">{{ item }}</div>
  </div>
</template>

<script setup lang="ts">
  const TestArr: string[] = ['A', 'B', 'C', 'D']
  TestArr.splice(2, 0, 'SSS')
</script>
import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, createElementVNode as _createElementVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("template", null, [
    _createElementVNode("div", null, [
      (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.TestArr, (item) => {
        return (_openBlock(), _createElementBlock("div", { key: item }, _toDisplayString(item), 1 /* TEXT */))
      }), 128 /* KEYED_FRAGMENT */))
    ])
  ]))
}
小满zs的个人空间_哔哩哔哩_Bilibili小满zs,Vue3;小满zs的主页、动态、视频、专栏、频道、收藏、订阅等。哔哩哔哩Bilibili,你感兴趣的视频都在B站。https://space.bilibili.com/99210573?spm_id_from=333.1007.0.0

2.4 Vue3 中如何优化 Vdom

GitHub - vuejs/core: 🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web. - GitHub - vuejs/core: 🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.https://github.com/vuejs/core

Vue2 中,每次更新diff,都是全量对比

Vue3 中,只对比带有补丁标记的,进而减少 非动态内容的 对比消耗,补丁标记见下一节

3. 补丁标记(patch flag)

3.1 什么是补丁标记(patch flag)

编译前:

<div>Hello Vue3!</div>
<div>Hello Vue3!</div>
<div>Hello Vue3!</div>
<div>Hello Vue3!</div>
<div>{{ msg }}</div>
<div>Hello Vue3!</div>
<div>Hello Vue3! </div>

Vue3 编译后的 Vdom:

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(_Fragment, null, [
    _createElementVNode("div", null, "Hello Vue3!"),
    _createElementVNode("div", null, "Hello Vue3!"),
    _createElementVNode("div", null, "Hello Vue3!"),
    _createElementVNode("div", null, "Hello Vue3!"),
    _createElementVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createElementVNode("div", null, "Hello Vue3!"),
    _createElementVNode("div", null, "Hello Vue3! ")
  ], 64 /* STABLE_FRAGMENT */))
}

创建动态DOM元素时,Vdom 不仅模拟了DOM元素的基本信息,还新增了一个标记:1 /* TEXT */

黄色框内的就是 补丁标记 patch flag

3.2 补丁标记如何优化静态树

虽然 JavaScript 做 Vdom 的对比非常的快,但是还有提升空间

当 Diff 算法运行到 _createElementBlock() 方法时,会忽略所有的静态节点,只对有标记的动态节点进行对比,即使在多层的嵌套下依然有效

因此,在针对大组件的时候,patch flag 大大提高了 Vue3 的 Vdom 的性能

3.3 新增的补丁标记(patch flag)

TEXT = 1 // 动态文本节点
CLASS=1<<1,1 // 2 // 动态 class
STYLE=1<<2, // 4 // 动态 style
PROPS=1<<3, // 8 // 动态属性,但不包含类名和样式
FULLPR0PS=1<<4, // 16 // 具有动态key属性,当key改变时,需要进行完整的 diff 比较
HYDRATE_ EVENTS = 1 << 5, // 32 // 带有监听事件的节点
STABLE FRAGMENT = 1 << 6, // 64 // 一个不会改变子节点顺序的fragment
KEYED_ FRAGMENT = 1 << 7, // 128 // 带有key属性的 fragment 或部分子字节有 key
UNKEYED FRAGMENT = 1<< 8, // 256 // 子节点没有key 的fragment
NEED PATCH = 1 << 9, // 512 // 一个节点只会进行非 props 比较
DYNAMIC_SLOTS = 1 << 10 // 1024 // 动态slot
HOISTED = -1 // 静态节点
BALL = -2

4. Fragment

4.1 支持多个根节点

<template>
  <div>23333</div>
  <div>23333</div>
  <div>23333</div>
</template>

4.2 支持 render JSX 写法

类似于 React

  render() {
    return (
      <>
        { this.visable
          ? (<div>{ this.obj.name }</div>)
          : (<div>{ this.obj.age }</div>)
        }
        <input v-model={ this.val }></input>
        { [1, 2, 3].map(
          (v) => { return <div>{ v } === </div> }
        )}
      </>
    );
  },

新增了 Suspense  和  多 v-model 用法

5. Tree Shaking

5.1 Vue2 中如何处理多余的代码

Vue2 中,无论是否使用 vue 的某些功能(比如 watch),最终都会被打包到生产代码中

原因:Vue 实例在项目中是单例的,捆绑程序无法检测到该对象的哪些属性被用到

5.2 Vue3 中如何处理多余的代码

Vue3 引入Tree Shaking,将全局 API 进行分块,如果不使用 vue 的某些功能(比如 watch),这些功能就不会进行打包

举个栗子:只用到了 watch,则只导入 watch(import {watch} from 'vue'),其他没用到的内容(比如 computed)就不会打包,进而减少体积

Tree Shaking 作用:在保持代码运行结果不变的前提下,去除无用代码

6. Composition API

setup 函数式编程(也叫 Vue Hook)

例如:ref  reactive watch computed toRefs toRaws 

7. SFC 语法规范

*.vue 文件由三种类型的顶层语法块所组成:<template>、<script>、<style>

7.1 <template>

每个 *.vue 文件最多可同时包含一个 <template> 块

<template> 中的内容会被提取出来,并传递给 @vue/compiler-dom,预编译为 JavaScript 的渲染函数,附属到导出的组件上,作为其 render 选项

7.2 <script>

每个 *.vue 文件最多可同时包含一个 <script> 块 (不包括 <script setup>)

该脚本将作为 ES Module 来执行,其默认导出的内容应该是 Vue 组件选项对象

关于Vue 组件选项对象,有两种可能:

  • 一个普通的对象
  • defineComponent() 的返回值

全局 API | Vue.jsVue.js - The 渐进式 JavaScript 框架https://v3.cn.vuejs.org/api/global-api.html#definecomponent

/**
 * 具有组件选项的对象
 */
import { defineComponent } from 'vue'

const MyComponent = defineComponent({
  data() {
    return { count: 1 }
  },
  methods: {
    increment() {
      this.count++
    }
  }
})

/**
 * 或者是一个 setup 函数,函数名称将作为组件名称来使用 
 */
import { defineComponent, ref } from 'vue'

const HelloWorld = defineComponent(function HelloWorld() {
  const count = ref(0)
  return { count }
})

 

7.3 <script setup>

每个 *.vue 文件最多可同时包含一个 <script setup> 块 (不包括常规的 <script>)

该脚本会被预处理,作为组件的 setup() 函数使用,也就是说它会在每个组件实例中执行

<script setup> 的顶层绑定会自动暴露给模板

单文件组件 <script setup> | Vue.js

7.4 <style>

每个 *.vue 文件可以包含多个 <style> 块(和前面不一样哦)

<style> 标签可以通过 scoped 或 module attribute,将样式封装在当前组件内

多个不同封装模式的 <style> 标签,可以在同一个组件中出现

单文件组件样式特性 | Vue.jsVue.js - The 渐进式 JavaScript 框架https://v3.cn.vuejs.org/api/sfc-style.html#style-scoped

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值