Vue3的变化
性能的提升
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
源码的升级
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现和Tree-Shaking
拥抱TypeScript
Vue3可以更好的支持TypeScript
新的特性
Composition API(组合API)
setup配置
ref与reactive
watch与watchEffect
provide与inject
新的内置组件
Fragment
Teleport
Suspense
其他改变
新的生命周期钩子
data 选项应始终被声明为一个函数
移除keyCode支持作为 v-on 的修饰符
组合式API和配置项API
使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
组件中的template标签可以没有根标签
创建Vue3项目的两种方式
vue-cl创建
vue-cli创建和之前创建vue2一样,选择vue版本时选择3.x即可。
vite创建
创建的项目将使用基于 Vite 的构建设置,并允许我们使用 Vue 的单文件组件 (SFC)。
在终端输入以下命令
npm init vue@latest
cd到项目文件夹,执行npm install,然后执行npm run dev
项目启动成功,访问网址。
也可在vscode中打开项目文件夹
常用API
setup
setup为Vue3.0中一个新的配置项,值为一个函数
setup是所有Composition API(组合API)编写的位置
组件中所用到的:数据、方法等等,均要配置在setup中
setup函数的返回值:返回一个对象,对象中的属性、方法, 在模板中均可以直接使用
注意:尽量不要与Vue2.x配置混用
Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。
但在setup中不能访问到Vue2.x配置(data、methos、computed…)。
如果有重名, setup优先。
<template>
{{ name }}
<br>
{{ age }}
<br>
<button @click="ageAdd">点击年龄+1</button>
</template>
<script>
export default {
name: 'App',
created(){
console.log(this)
},
setup() {
let name = 'yietong'
let age = 22
console.log(this)
let ageAdd = () => {
age++
console.log(age)
}
return {
name, age,ageAdd
}
}
}
</script>
setup函数中没有了this,在setup函数外是有this的,但是不是Vc实例了,而变成了Proxy实例。
所有的变量和方法都在setup函数中写。
定义了变量,变量可以渲染,但是没有响应式,值变了,但是渲染的值没有跟着改变。
setup必须要有返回值,返回的值才能在模板中使用。
ref和reactive
作用: 定义一个响应式的数据
语法: const 变量= ref(值)
创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
JS中操作数据: 变量.value
模板中读取数据: 不需要.value,直接:
{{变量}}
<template>
{{ name }}
<br>
{{ age }}
<br>
<button @click="ageAdd">点击年龄+1</button>
</template>
<script>
import { ref } from 'vue'
export default {
name: 'App',
setup() {
let name = ref('yietong')
let age = ref(22)
console.log(name)
console.log(age)
let ageAdd = () => {
age.value++
console.log(age.value)
}
return {
name, age,ageAdd
}
}
}
</script>
接收的数据可以是:基本类型、也可以是对象类型。
基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的
对象类型的数据:内部 求助 了Vue3.0中的一个新函数—— reactive函数
<template>
{{ info.name }}
<br>
{{ info.age }}
<br>
<button @click="info.ageAdd">点击年龄+1</button>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let info = reactive({
name: 'yietong',
age: 22
})
info.ageAdd = () => {
info.age += 1
console.log(info.age)
}
console.log(info)
return {
info
}
}
}
</script>
对象在渲染时直接对象点key就可以获取到value,也可以直接给对象添加方法。
计算和监听属性
computed函数使用
<template>
<p>姓:<input type="text" v-model="info.firstName"></p>
<p>名:<input type="text" v-model="info.lastName"></p>
<p>全名:<input type="text" v-model="info.fullName"></p>
</template>
<script>
import { computed, reactive } from 'vue'
export default {
name: 'App',
setup() {
const info = reactive({
firstName: '',
lastName: ''
})
info.fullName = computed({
get() {
return info.firstName + '_' + info.lastName
},
// 修改属性会执行set函数,并将修改后的值传入
set(val) {
console.log(val)
let strArray = val.split('_')
info.firstName = strArray[0]
info.lastName = strArray[1]
}
})
return {
info
}
}
}
</script>
watch函数
<template>
<p><input type="text" v-model="name">{{ name }}</p>
</template>
<script>
import { watch, ref, watchEffect } from 'vue'
export default {
name: 'App',
setup() {
const name = ref('yietong')
watch(name, (value, oldvalue) => {
console.log(value)
console.log(oldvalue)
})
watchEffect(()=>{
// 只有当watchEffect里使用的变量值改变才会执行该函数
let a = name.value
console.log('执行了')
})
return {
name
}
}
}
</script>
生命周期
beforeCreate:在组件实例初始化完成之后立即调用。组合式 API 中的 setup() 钩子会在所有选项式 API 钩子之前调用,beforeCreate() 也不例外。
created:在组件实例处理完所有与状态相关的选项后调用。当这个钩子被调用时,以下内容已经设置完成:响应式数据、计算属性、方法和侦听器。然而,此时挂载阶段还未开始,因此 $el 属性仍不可用。
beforeMount:在组件被挂载之前调用。当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。这个钩子在服务端渲染时不会被调用。
mounted:在组件被挂载之后调用。这个钩子在服务端渲染时不会被调用。
beforeUpdate:在组件即将因为一个响应式状态变更而更新其 DOM 树之前调用。
updated:在组件因为一个响应式状态变更而更新其 DOM 树之后调用。
beforeUnmount:在一个组件实例被卸载之前调用。当这个钩子被调用时,组件实例依然还保有全部的功能。
在一个组件实例被卸载之后调用。可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。
<template>
<h1>生命周期</h1>
<hr>
<button @click="handleClick">点我消失</button>
<Child v-if="show"></Child>
</template>
<script>
import Child from "./components/Child.vue";
import { ref } from 'vue'
export default {
name: 'App',
components: { Child },
setup() {
let show = ref(true)
const handleClick = () => {
show.value = !show.value
}
return {
show, handleClick
}
}
}
</script>
<template>
<h1>我是Child组件</h1>
</template>
<script>
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'
export default {
name: 'Child',
setup() {
console.log('组合式api的beforeCreate')
console.log('组合式api的created')
onBeforeMount(() => {
console.log('组合式api的onBeforeMount')
})
onMounted(() => {
console.log('组合式api的onMounted')
})
onBeforeUpdate(() => {
console.log('组合式api的onMounted')
})
onBeforeUnmount(() => {
console.log('组合式api的onBeforeUnmount')
})
onUnmounted(() => {
console.log('组合式api的onUnmounted')
})
return{}
}
}
</script>
自定义hook函数
在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。
相比之下,有状态逻辑负责管理会随时间而变化的状态。一个简单的例子是跟踪当前鼠标在页面中的位置。在实际应用中,也可能是像触摸手势或与数据库的连接状态这样的更复杂的逻辑。
鼠标跟踪器示例
如果我们要直接在组件中使用组合式 API 实现鼠标跟踪功能,它会是这样的:
<template>当前鼠标点击坐标为:({{ coord.x }} ,{{ coord.y }})</template>
<script setup>
import { reactive, onMounted, onUnmounted } from "vue";
const coord = reactive({
x: 0,
y: 0,
});
const mouseClick = (event) => {
console.log(event);
coord.x = event.x;
coord.y = event.y;
};
onMounted(() => window.addEventListener("click", mouseClick));
onUnmounted(() => window.removeEventListener("click", mouseClick));
</script>
但是,如果我们想在多个组件中复用这个相同的逻辑呢?我们可以把这个逻辑以一个组合式函数的形式提取到外部文件中:
// mouse.js
import { reactive, onMounted, onUnmounted } from "vue";
export function useMouse() {
const coord = reactive({
x: 0,
y: 0,
})
const mouseClick = (event) => {
console.log(event)
coord.x = event.x
coord.y = event.y
}
onMounted(() => window.addEventListener("click", mouseClick))
onUnmounted(() => window.removeEventListener("click", mouseClick))
return coord
}
下面是它在组件中使用的方式:
<template>当前鼠标点击坐标为:({{ coord.x }} ,{{ coord.y }})</template>
<script setup>
import { useMouse } from "./mouse.js";
const coord = useMouse();
</script>
🔗 vue3官方文档 简介 | Vue.js