红宝书第四十一讲:关于Vue3的入门解读和与Vue2的区别

资料取自《JavaScript高级程序设计(第5版)》
查看总目录:红宝书学习大纲


1. 什么是Vue3?

Vue3是一个用于构建用户界面的渐进式框架。它和Vue2类似,但进行了很多改进,比如更快的速度、更小的体积和更灵活的代码组织方式。

2. 如何安装Vue3?

你可以通过以下命令安装Vue3:

npm install vue@next

或者使用CDN:

<script src="https://unpkg.com/vue@next"></script>

3. 创建一个简单的Vue3应用

下面是一个简单的Vue3应用示例:

<div id="app">
  <h1>{{ message }}</h1>
  <button @click="changeMessage">点击我</button>
</div>
<script>
import { createApp, ref } from 'vue';

createApp({
  setup() {
    const message = ref('Hello, Vue3!');
    const changeMessage = () => {
      message.value = '消息已更改!';
    };
    return { message, changeMessage };
  }
}).mount('#app');
</script>
  • createApp 是Vue3中用来创建应用实例的函数。
  • ref 是用来定义响应式数据的函数,message.value 是获取和修改响应式数据的方式。

4. 组合式API(Composition API)

Vue3新增了组合式API,它通过setup函数来组织代码。比如上面的代码中,setup函数中定义了messagechangeMessage,它们可以被模板直接使用。

5. 响应式系统

Vue3使用Proxy来实现响应式系统,这比Vue2的Object.defineProperty更强大,可以监听对象属性的动态添加和删除。

Vue3和Vue2的区别

特性Vue2Vue3
响应式系统使用Object.defineProperty,无法监听对象属性的动态添加或删除使用Proxy,可以监听动态变化
API风格选项式API(Options API),逻辑分散在datamethods等选项中组合式API(Composition API),逻辑更集中,便于复用
性能性能较好性能大幅提升,虚拟DOM优化,打包体积更小
生命周期钩子beforeCreatecreatedmountedsetup替代beforeCreatecreated,其他钩子名前加on
多根节点支持不支持,必须有一个根节点支持多根节点
TypeScript支持需借助插件,原生支持较弱完全用TypeScript重写,支持更好
全局APInew Vue()创建实例,全局配置影响所有实例使用createApp()创建隔离实例,全局API改为实例方法
过滤器支持移除,推荐用计算属性或方法替代

案例对比

响应式数据

  • Vue2

    new Vue({
    data() {
      return {
        message: 'Hello, Vue2!'
      };
    }
    });
  • Vue3

    import { ref } from 'vue';
    const message = ref('Hello, Vue3!');

    在Vue3中,需要使用ref来定义响应式数据。

生命周期钩子

  • Vue2

    new Vue({
    created() {
      console.log('组件创建完成');
    }
    });
  • Vue3

    import { onMounted } from 'vue';
    onMounted(() => {
    console.log('组件挂载完成');
    });

    Vue3中生命周期钩子名前加on,且需要在setup中使用。

多根节点

  • Vue2

    <template>
    <div>
      <header></header>
      <main></main>
      <footer></footer>
    </div>
    </template>
  • Vue3

    <template>
    <header></header>
    <main></main>
    <footer></footer>
    </template>

    Vue3支持多根节点,不需要额外的包裹元素。

Vue3常用生命周期钩子表格

钩子名称触发时机用途
setup组件初始化时,替代beforeCreatecreated定义响应式数据、计算属性、方法
onBeforeMount组件挂载到DOM之前执行挂载前的准备工作
onMounted组件挂载到DOM之后访问DOM、发起网络请求、添加事件监听
onBeforeUpdate数据更新导致DOM更新之前获取更新前的DOM状态
onUpdated数据更新导致DOM更新之后访问更新后的DOM状态
onBeforeUnmount组件卸载之前执行清理工作,如取消事件监听
onUnmounted组件卸载之后执行卸载后的清理工作
onActivated<keep-alive>组件被激活时激活缓存组件
onDeactivated<keep-alive>组件被停用时停用缓存组件
onErrorCaptured组件内部捕获错误时处理组件错误

Vue3生命周期钩子案例

1. setup

import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const increment = () => count.value++;
    return { count, increment };
  }
};
  • 用途:在组件初始化时定义响应式数据和方法。

2. onMounted

import { ref, onMounted } from 'vue';

export default {
  setup() {
    const count = ref(0);

    onMounted(() => {
      console.log('组件已挂载');
      // 操作DOM或发起网络请求
    });

    return { count };
  }
};
  • 用途:在组件挂载到DOM后执行,适合操作DOM或发起网络请求。

3. onUpdated

import { ref, onUpdated } from 'vue';

export default {
  setup() {
    const count = ref(0);

    onUpdated(() => {
      console.log('组件已更新');
      // 注意避免在此修改响应式数据,以免造成无限循环
    });

    return { count };
  }
};
  • 用途:在组件更新后执行,适合访问更新后的DOM。

4. onUnmounted

import { ref, onUnmounted } from 'vue';

export default {
  setup() {
    const count = ref(0);
    let timer = setInterval(() => {
      count.value++;
    }, 1000);

    onUnmounted(() => {
      console.log('组件已卸载');
      clearInterval(timer); // 清除定时器
    });

    return { count };
  }
};
  • 用途:在组件卸载后执行,适合清理资源。

5. onActivatedonDeactivated

import { ref, onActivated, onDeactivated } from 'vue';

export default {
  setup() {
    const count = ref(0);

    onActivated(() => {
      console.log('组件被激活');
    });

    onDeactivated(() => {
      console.log('组件被停用');
    });

    return { count };
  }
};
  • 用途:在<keep-alive>组件被激活或停用时执行。

Vue3常用Composition API表格列举

API名称用途示例
ref创建一个响应式的基本类型数据const count = ref(0)
reactive创建一个响应式的对象或数组const state = reactive({ name: '张三', age: 25 })
computed创建一个计算属性,基于其他响应式数据自动更新const doubleCount = computed(() => count.value * 2)
watch监听响应式数据的变化,并在变化时执行回调watch(count, (newVal, oldVal) => { console.log(count 从 ${oldVal} 变为 ${newVal}) })
watchEffect自动运行一个副作用函数,并在依赖的响应式数据变化时重新运行watchEffect(() => console.log(count.value))
toRefs将响应式对象的属性转换为响应式的引用,便于在模板中直接使用const { name, age } = toRefs(state)
provide/inject实现祖孙组件间的通信provide(ThemeSymbol, themeRef)inject(ThemeSymbol)
defineProps/defineEmits声明组件的propsemits,用于类型检查和代码提示defineProps(['modelValue'])defineEmits(['update:modelValue'])

Vue3 Composition API案例列举

1. 基础响应式数据

import { ref, reactive } from 'vue';

export default {
  setup() {
    const count = ref(0); // 基本类型响应式数据
    const user = reactive({ name: '张三', age: 25 }); // 对象类型响应式数据

    return { count, user };
  }
};
  • 用途:定义响应式数据,用于模板渲染。

2. 计算属性

import { ref, computed } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const doubleCount = computed(() => count.value * 2);

    return { count, doubleCount };
  }
};
  • 用途:基于响应式数据计算派生值。

3. 监听数据变化

import { ref, watch } from 'vue';

export default {
  setup() {
    const count = ref(0);

    watch(count, (newVal, oldVal) => {
      console.log(`count 从 ${oldVal} 变为 ${newVal}`);
    });

    return { count };
  }
};
  • 用途:监听响应式数据的变化并执行回调。

4. 自动运行副作用

import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const count = ref(0);

    watchEffect(() => {
      console.log(`当前 count 值为 ${count.value}`);
    });

    return { count };
  }
};
  • 用途:自动运行副作用函数,并在依赖的响应式数据变化时重新运行。

5. 提供和注入

// 父组件
import { provide, ref } from 'vue';

export default {
  setup() {
    const theme = ref('dark');
    provide('theme', theme);

    return { theme };
  }
};

// 子组件
import { inject } from 'vue';

export default {
  setup() {
    const theme = inject('theme');
    return { theme };
  }
};
  • 用途:实现祖孙组件间的通信。

6. 使用toRefs

import { reactive, toRefs } from 'vue';

export default {
  setup() {
    const state = reactive({ name: '张三', age: 25 });
    const { name, age } = toRefs(state);

    return { name, age };
  }
};
  • 用途:将响应式对象的属性转换为响应式的引用,便于在模板中直接使用。

7. 使用definePropsdefineEmits

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);

const handleChange = (event) => {
  emit('update:modelValue', event.target.value);
};
</script>

<template>
  <input :value="modelValue" @input="handleChange" />
</template>
  • 用途:声明组件的propsemits,用于类型检查和代码提示。

这些API和案例可以帮助你更好地理解和使用Vue3的Composition API,从而更灵活地组织和复用组件逻辑。


目录:总目录
上篇文章:红宝书第四十讲:React 核心概念:组件化 & 虚拟 DOM 简单教程

下篇文章:红宝书第四十二讲:Angular核心特性精讲:依赖注入 & RxJS整合


kovli
13 声望6 粉丝