https://composition-api.vuejs.org/zh/api.html
1、创建vue3项目
(1)使用vue-cli创建
## 安装或者升级
npm install -g @vue/cli
## 保证 vue cli 版本在 4.5.0 以上
vue --version
## 创建项目
vue create my-project
(2)使用vite创建【npm init vite-app 项目名称】
2、setup
setup是新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次
【setup执行时机】
在beforeCreate之前执行(一次), 此时组件对象还没有创建;
setup中,this是undefined, 不能通过this来访问data/computed/methods / props,其实所有的composition API相关回调函数中也都不可以。
【setup的返回值】
setup返回值是一个对象,内部的属性和方法是给html模板使用的。
setup中的对象内部的属性和data函数中的return对象的属性都可以在html模板中使用。
setup中返回对象中的属性会与data函数返回对象的属性合并成为组件对象的属性,返回对象中的方法会与methods中的方法合并成功组件对象的方法
在vue3中尽量不要混合使用data和setup及methods和setup。methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问data和methods
setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性数据。
【setup的参数】
setup(props, context) 或setup(props, {attrs, slots, emit})
props: 包含props配置声明且传入了的所有属性的对象
attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs
slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots
emit: 用来分发自定义事件的函数, 相当于 this.$emit
3、ref与reactive
ref与reactive--vue3中的两个最重要的响应式的API
(1)ref
ref作用:定义一个数据的响应式,用来处理基本类型数据。
语法:【const user=ref(xxx)】
通过给value属性添加getter/setter来实现对数据的劫持。
注意:js中操作数据【user.value】模板中操作数据【user】,不需要.value
用ref对象/数组, 内部会自动将对象/数组转换为reactive的代理对象。
ref的另外一个作用:获取元素-利用ref函数获取组件中的标签元素
<template>
<h2>ref的另一个作用:获取组件中的标签元素</h2>
<input type="text" ref="inputRef" />
</template>
<script lang="ts">
import { defineComponent, ref, reactive, onMounted } from "vue";
export default defineComponent({
name: "App",
setup() {
const inputRef = ref<HTMLElement | null>(null);
onMounted(() => {
inputRef.value && inputRef.value.focus();
});
return {
inputRef,
};
},
});
</script>
(2)reactive
reactive作用: 定义多个数据的响应式,用来处理对象(递归深度响应式:响应式转换是“深层的”:会影响对象内部所有嵌套的属性)。
通过使用Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据。
语法:【const proxy = reactive(obj)】 接收一个普通对象然后返回该普通对象的响应式代理器对象
内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的。
4、vue2 和 vue3对比
vue2 和 vue3响应式对比
| 核心 | 存在的问题 |
vue2的响应式 | 对象: 通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截) | 对象直接新添加的属性或删除已有属性, 界面不会自动更新 |
数组: 通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持 | 直接通过下标替换元素或更新length, 界面不会自动更新 | |
vue3的响应式 | 通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等... 通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作 |
|
vue2中html模板中必须要有一对根标签,vue3组件html模板中可以没有根标签
<template>
<!-- vue2中html模板中必须要有一对根标签,vue3组件html模板中可以没有根标签 -->
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</template>
<script lang="ts">
// defineComponent函数,目的是定义一个组件,内部可以传入一个配置对象
import { defineComponent } from "vue";
// 引入子组件
import HelloWorld from "./components/HelloWorld.vue";
export default defineComponent({
// 当前组件的名字是App
name: "App",
// 注册组件
components: {
// 注册子组件
HelloWorld,
},
});
</script>
<style>
#app {
}
</style>
实现方法
vue2
<script lang="ts">
// defineComponent函数,目的是定义一个组件,内部可以传入一个配置对象
import { defineComponent} from "vue";
export default defineComponent({
name: "App",
//vu2的实现方法
data() {
return {
count: 0,
};
},
methods: {
add() {
this.count++;
},
},
});
</script>
vue3: setup是组合API的入口函数
<script lang="ts">
// defineComponent函数,目的是定义一个组件,内部可以传入一个配置对象
import { defineComponent, ref, reactive } from "vue";
export default defineComponent({
name: "App",
// vue3的实现方法
// setup是组合API的入口函数
setup() {
// ref定义一个基本类型的响应式数据
const count = ref(0);
const obj: any = { name: "朗朗", age: 12, hobby: ["跳舞", "打球"] };
function add() {
count.value++;
}
// user为代理对象,obj为目标对象, user对象的类型是proxy
const user = reactive<any>(obj);
const updateInfo = () => {
user.name += "==";
obj.name = "哈哈";
user.age += 1;
obj.sex = "女";
// delete obj.age;
// delete user.age;
};
return {
count,
add,
user,
updateInfo,
};
},
});
</script>
5、vue3的响应式数据的核心原理
通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等,通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>响应式的原理</title>
</head>
<body>
<script type="text/javascript">
// 目标对象
const user = {
name: "唐三",
age: 20,
wife: {
name: "小舞",
age: 18,
hobby: ["跳舞", "吃萝卜"],
},
};
// 把目标对象变成代理对象
// 参数1:user---》target目标对象
// 参数2:handler--->处理器对象,用来监视数据,及数据的操作
const proxyUser = new Proxy(user, {
// 拦截读取属性值
get(target, prop) {
console.log("get方法被调用了");
// Reflect配合handler使用实现对数据的操作
return Reflect.get(target, prop);
},
// 修改、添加属性值-拦截设置属性值或添加新属性
set(target, prop, val) {
console.log("set方法调用了");
return Reflect.set(target, prop, val);
},
deleteProperty(target, prop) {
//拦截删除属性
console.log("delete方法调用了");
return Reflect.deleteProperty(target, prop);
},
});
// 1.通过代理对象获取目标对象中的某个属性值
console.log(proxyUser.name);
// 2.通过代理对象更新目标对象上的某个属性值
proxyUser.name = "小三";
console.log(user);
// 3.通过代理对象向目标对象中添加一个新的属性
proxyUser.gender = "女";
console.log(user);
// 4.通过代理对象删除目标对象中的属性
delete proxyUser.name;
console.log(user);
proxyUser.wife.name = "舞";
console.log(user);
</script>
</body>
</html>