官方笔记地址: https://24kcs.github.io/vue3_study/
https://github.com/vuejs/vue-next/releases/tag/v3.0.0
性能的提升、源码的升级、拥抱TypeScript、新的特性
vue --version
vue -V
npm install -g @vue/cli // 安装或者升级@vue/cli
vue create vue_test // 创建
使用vite创建
https://v3.cn.vuejs.org/gulde/installation.html#vite
https://vitejs.cn
npm init vite-app vue3_test_vite
新一代前端构建工具
vue2,vue3对比
// 引入的不再是Vue构造函数,引入的是一个名字、为createApp的工厂函数
import { createApp } from "vue";
// import 'Vue' from Vue
import App from "./App.vue";
import "./index.css";
// 创建应用实例对象--app(类似于之前V2中的vm,但app比vm更”轻“)
createApp(App).mount("#app");
// debugger;
// const vm = new Vue({
// render: (h) => h(App),
// });
// vm.$mount('#app')
console.log(createAPP(App))
<template>
<h1>一个人的信息h1>
<h2>姓名: {{ name }}h2>
<h2>年龄:{{ age }}h2>
<button @click="sayHello">说话button>
template>
<script>
export default {
name: "App",
// 此处只是测试一下setup,暂时不考虑响应式的问题
setup() {
// 数据
let name = "张三";
let age = 18;
// 方法
function sayHello() {
alert(`我叫${name},我${age}岁了,你好啊!`);
}
// 返回一个对象(常用)
return {
name,
age,
sayHello,
};
},
};
script>
setup函数的两个返回值:
注意点: 尽量不要与Vue2.X配置混用
setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性
引用实现的实例
<template>
<!-- Vue3组件中的模板结构可以没有跟标签 -->
<h1>一个人的信息</h1>
<h2>姓名: {{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>工作种类: {{ job.type }}</h2>
<h2>工作薪水: {{ job.salary }}</h2>
<button @click="changeInfo">修改人的信息</button>
<h2>测试c的数据:{{ job.a.b.c }}</h2>
<h2>hobby: {{ hobby[0] }}</h2>
</template>
<script>
import { ref, reactive } from "vue";
export default {
name: "App",
// 此处只是测试一下setup,暂时不考虑响应式的问题
setup() {
// 数据,数据响应式
// refImpl: reference/implement(引用实现)
let name = ref("张三");
let age = ref(18);
let job = reactive({
// Objet---->Proxy
type: "前端工程师",
salary: "30K",
a: {
b: {
c: 666,
},
},
});
let hobby = reactive(["抽烟", "喝酒", "烫头"]);
// 方法
function changeInfo() {
name.value = "李四";
age.value = 48;
// job.value.type = "UI设计师"; // ref时修改数据
job.type = "UI设计师";
console.log(job);
job.a.b.c = 999;
hobby[0] = "学习";
}
// 返回一个对象(常用)
return {
name,
age,
job,
hobby,
changeInfo,
};
},
};
</script>
const xxx = ref(initValue)
xxx.value
{{xxx}}
Object.defineProperty()
的get与set完成的reactive
函数
数据劫持才是响应式数据实现的根基
作用: 定义一个对象类型的响应式数据(基本类型不能用它,要用ref函数)
语法:const 代理对象 = reactive(源对象)
接受一个对象(或数组),返回一个代理对象(proxy的实例对象,简称proxy对象)
reactive定义的响应式数据是“深层次的”
内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作
例子
<template>
<h1>一个人的信息h1>
<h2>姓名: {{ person.name }}h2>
<h2 v-show="person.sex">性别: {{ person.sex }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>工作种类: {{ person.job.type }}h2>
<h2>工作薪水: {{ person.job.salary }}h2>
<button @click="changeInfo">修改人的信息button>
<h2>测试c的数据:{{ person.job.a.b.c }}h2>
<h2>hobby: {{ person.hobby[0] }}h2>
<button @click="addSex">添加一个sex属性button>
<button @click="deleteName">删除一个name属性button>
template>
<script>
import { reactive } from "vue";
export default {
name: "App",
// 此处只是测试一下setup,暂时不考虑响应式的问题
setup() {
let person = reactive({
name: "张三",
age: 18,
job: {
// Objet---->Proxy
type: "前端工程师",
salary: "30K",
a: {
b: {
c: 666,
},
},
},
hobby: ["抽烟", "喝酒", "烫头"],
});
// 方法
function changeInfo() {
person.name = "李四";
person.age = 48;
person.job.type = "UI设计师";
console.log(person.job);
person.job.a.b.c = 999;
person.hobby[0] = "学习";
}
function addSex() {
person.sex = "男";
}
function deleteName() {
delete person.name;
}
// 返回一个对象(常用)
return {
person,
changeInfo,
addSex,
deleteName,
};
},
};
script>
实现原理:
对象类型: 通过Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)
数组类型: 通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行包裹)
Object.defineProperty(data, 'count', {
get() {},
set() {}
})
例子
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>Documenttitle>
head>
<body>
<script>
let person = {
name: "张三",
age: 18,
};
let p = {};
Object.defineProperty(p, "name", {
get() {
return person.name;
},
set(value) {
console.log("有人修改了name属性,我发现了,我要去更新界面!");
person.name = value;
},
});
script>
body>
html>
存在问题:
通过Proxy(代理): 拦截对象中任意属性的变化,包括: 属性值的读写、属性的添加、属性的删除
<!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>Document</title>
</head>
<body>
<script>
// 源数据
let person = {
name: "张三",
age: 18,
};
// 模拟Vue3中实现响应式
const p = new Proxy(person, {
// 有人读取p的某个属性时调用
get(target, propName) {
console.log("有人读取了p身上的${propName}属性", target, propName);
return target[propName];
},
set(target, propName, value) {
// console.log(target, propName, value);
console.log(`有人读取了p身上的${propName}属性", 我要去更新界面了`);
},
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`);
delete target[propName];
return 100;
},
});
</script>
</body>
</html>
通过Reflect(反射): 对被代理对象的属性进行操作
Object上有用的属性转到reflect
new Proxy(data, {
get(target, prop) {
return Reflect.get(target, prop);
},
// 拦截设置属性值或添加新属性
set(target, prop, value) {
return Reflect.set(target, prop, value);
},
// 拦截删除属性
deleteProperty(target, prop) {
return Reflect.deleteProperty(target, prop);
},
});
Object.defineProperty()
的get与set来实现响应式(数据劫持)