1. main.js 不同
import { createApp } from "vue";
import App from "./App.vue";
import "./index.css";
//vue2
// const app = new Vue(options)
// app.$mount("#app")
//vue3
// 不存在构造函数Vue
// const app = createApp(App);
// app.mount("#app");
2. vue3的 template 可以存在多个根节点,而vue2不能存在多个根节点
3.生命周期钩子函数不同
vue2:vue2中的生命周期:
- beforeCreate 组件创建之前
- created 组件创建之后
- beforeMount 组价挂载到页面之前执行
- mounted 组件挂载到页面之后执行
- beforeUpdate 组件更新之前
- updated 组件更新之后
vue3:vue3中的生命周期:
- setup 开始创建组件
- onBeforeMount 组价挂载到页面之前执行
- onMounted 组件挂载到页面之后执行
- onBeforeUpdate 组件更新之前
- onUpdated 组件更新之后
而且vue3.x 生命周期在调用前需要先进行引入。除了这些钩子函数外,vue3.x还增加了onRenderTracked 和onRenderTriggered函数。
4. API不同
vue2:vue2使用选项类型api,选项型api在代码里分割了不同的属性:data,computed,methods等。
vue3:vue3使用组合式api,新的合成型api能让我们使用方法来分割,相比于旧的api使用属性来分组,这样代码会更加简便和整洁
组合式API更容易实现把高内聚的目的,更容易把相同的功能写在一坨,而不是写的到处都是。
vue2:vue2是把数据放入data中,在vue2中定义数据变量是data(){} ,创建的方法要在methods:{} 中。
vue3:,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。使用以下三个步骤来建立反应性数据:
- 从vue引入reactive;
- 使用reactive() 方法来声明数据为响应性数据;
- 使用setup()方法来返回我们的响应性数据,从而template可以获取这些响应性数据。
其实Vue3的本质就是将vue2的 data,method,computed等都放在setup里面,然后再将这些东西返回,返回后就会挂载在vue实例上,这样就可以在模版里面使用了。
vue3 其实是将不同的功能可以分在不同的文件中,不同的文件提供不同的响应式数据,计算属性和方法。 这些不同的文件都是给模版使用的,不同的文件一般是代表不同的功能,有时候需要一个模块需要用到别的模块的数据,就可以在模版所在文件中,将数据以参数的形式传给另一个模块,所有的模块都使用的是响应式数据,这样就可以形成一个响应式链条,而且可以将这个聊天进行随意的修改。这其实就是vue3 组合式API的本质
import { ref, onMounted, onUnmounted, computed } from "vue";
import { filter } from "../util/todoStorage";
const validHash = ["all", "active", "completed"];
export default function useFilter(todosRef) {
const visibilityRef = ref("all");
const onHashChange = () => {
const hash = location.hash.replace(/#\/?/, "");
if (validHash.includes(hash)) {
//有效的
visibilityRef.value = hash;
} else {
location.hash = "";
visibilityRef.value = "all";
}
};
// 1. 组件挂载完成的生命周期函数
onMounted(() => {
window.addEventListener("hashchange", onHashChange);
});
// 2. 组件销毁过后的生命周期函数
onUnmounted(() => {
window.removeEventListener("hashchange", onHashChange);
});
// 计算属性
const filteredTodosRef = computed(() => {
return filter(todosRef.value, visibilityRef.value);
});
// 计算属性
const remainingRef = computed(() => {
return filter(todosRef.value, "active").length;
});
// 计算属性
const completedRef = computed(() => {
return filter(todosRef.value, "completed").length;
});
return {
// 以下是响应式数据
visibilityRef,
//下面是计算属性
filteredTodosRef,
remainingRef,
completedRef,
};
}
import { ref } from "vue";
import { generateId } from "../util/todoStorage";
export default function useNewTodo(todosRef) {
const newTodoRef = ref(""); // 新任务的标题
// 代替原来方法的位置
const addTodo = () => {
// 新增一个任务
const value = newTodoRef.value && newTodoRef.value.trim();
if (!value) {
return;
}
// 生成一个任务对象,将其加入到任务列表中
const todo = {
id: generateId(),
title: value,
completed: false, // 任务是否完成
};
todosRef.value.push(todo);
newTodoRef.value = "";
};
return {
newTodoRef,
//供模版和其他模块使用的方法
addTodo,
};
}
还有一个就是对响应式数据的处理问题,vue2 放在data,computed里面就是响应式数据。而在vue3 中需要将响应式数据用ref包装一下,然后在setup里面数据被包装成一个对象,由于setup函数是在所有的 props 被赋值后就会执行,在vue实例被创建前调用,所以这时setup 中的this指向 undefined,接着前面的,由于数据被包装成一个对象,此时访问该数据需要用data.value去访问。而在temple里面数据,vue实例已经生成。
下图是vue3 响应式数据的处理
5.组件里面的this指向不同
vue2 中this指向组件实例,vue3中this指向的是代理,代理里面也有一个组件实例对象。