vue3简介
性能的提升
- 打包大小减少41%
- 初次渲染快55%,更新渲染快133%
- 内存减少54%
源码的升级
- 使用Proxy代替defineProperty实现响应式
- 重写虚拟DOM的实现和Tree-Shaking
新的特性
1. Composition API(组合API)
- setup
- ref与reactive
- computed与watch
2. 新的内置组件
- Fragment
- Teleport
- Suspense
3. 其他改变
- 新的生命周期钩子
- data选项应始终被声明为一个函数
- 移除keyCode支持作为v-on的修饰符
创建vue3项目
基于vue-cli创建(基于webpack)
// 安装或升级@vue.cli
npm install -g @vue/cli
// 执行创建命令
vue create project_name
基于vite创建
vite是新一代前端构建工具,官网地址:Vite中文网
vite的优势:
- 轻量快速的热重载(HMR),能实现极速的服务启动
- 对TypeScript、JSX、CSS等支持开箱即用
- 真正的按需编译,不再等待整个应用编译完成
- webpack构建与vite构建对比图如下:
webpack构建:
vite构建:
创建项目的命令
npm create vue@latest
Tips:
- 确保 Node.js 版本支持 Vue 3:推荐使用 Node.js 14 及以上版本
尝试使用node版本 14.21.3,创建项目时有报错,升级node版本为 16.20.2 之后就可以了
创建项目时的一些配置项设置,仅供参考
安装好的项目文件目录:
这个文件里面有报错,执行一下 npm install 就好了
并且这个文件里面的内容不能删除,他的作用是告诉 TypeScript 引入 Vite 的类型定义
可能还会有上图中这样的报错提示,在确保已经执行npm install之后,重新打开编辑器,报错提示就会消失了
选项式API的弊端
vue2(选项式API)数据、方法、计算属性等,是分散在:data、methods、computed中的,若想新增或者修改一个需求,就需要分别修改data、methods、computed,不便于维护和复用
组合式API的优势
可以用函数的方式,更加优雅的组织代码,让相关功能的代码有序的组织在一起
setup
setup中的this是undefined,vue3中已经弱化this了
setup的执行顺序在beforeCreate之前
setup的返回值可以是一个渲染函数,返回内容直接渲染在页面上
return () => '直接在页面上展示的内容'
<template><div class="person"><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><button @click="changeName">修改姓名</button><button @click="changeAge">修改年龄</button><button @click="showTel">查看联系方式</button></div>
</template><script lang="ts">
export default {// eslint-disable-next-line vue/multi-word-component-namesname: 'Person',setup() {// 这样写的name age tel不是响应式的 vue2中是写在data中的let name = '张三';let age = 18;const tel = '13800138000';function changeName() {name = '李四'; // 这样修改之后页面不会更新 值确实改了但不是响应式的 因此页面未更新};function changeAge() {age += 1;};function showTel() {alert(tel);};// 将数据、方法交出去,模板中才可以使用return {name,age,tel,changeName,changeAge,showTel,};},
};
</script><style scoped lang="less">
.person {button {display: block;margin: 10px 0;}
}
</style>
data、methods可以和setup同时存在
data中可以读取setup中的数据,通过this.xxx来获取,但是setup中是无法读取data中的数据的,因为setup是在data之前执行的
setup语法糖
<template><div class="person"><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><button @click="changeName">修改姓名</button><button @click="changeAge">修改年龄</button><button @click="showTel">查看联系方式</button></div>
</template><script lang="ts">
export default {// eslint-disable-next-line vue/multi-word-component-namesname: 'Person',
};
</script><script setup lang="ts">
// 这样写的name age tel不是响应式的 vue2中是写在data中的
let name = '张三';
let age = 18;
const tel = '13800138000';function changeName() {name = '李四'; // 这样修改之后页面不会更新 值确实改了但不是响应式的 因此页面未更新
};
function changeAge() {age += 1;
};
function showTel() {alert(tel);
};
</script><style scoped lang="less">
.person {button {display: block;margin: 10px 0;}
}
</style>
由于这样需要写两块script标签 ,第一块的主要作用是自定义组件名称,可以借助插件,省略第一块script标签
npm i vite-plugin-vue-setup-extend -D
安装之后在 vite.config.ts 中进行引入配置
<template><div class="person"><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><button @click="changeName">修改姓名</button><button @click="changeAge">修改年龄</button><button @click="showTel">查看联系方式</button></div>
</template><script setup lang="ts" name="Person">
// 这样写的name age tel不是响应式的 vue2中是写在data中的
let name = '张三';
let age = 18;
const tel = '13800138000';function changeName() {name = '李四'; // 这样修改之后页面不会更新 值确实改了但不是响应式的 因此页面未更新
};
function changeAge() {age += 1;
};
function showTel() {alert(tel);
};
</script><style scoped lang="less">
.person {button {display: block;margin: 10px 0;}
}
</style>
ref
用于(可以)定义基本类型的响应式数据,也可以定义对象类型的响应式数据,想让哪个数据是响应式的 就用ref包一下,在js代码中使用响应式数据需要用 .value 在模板中不需要
<template><div class="person"><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><h2>地址:{{ address }}</h2><button @click="changeName">修改姓名</button><button @click="changeAge">修改年龄</button><button @click="showTel">查看联系方式</button></div>
</template><script setup lang="ts" name="Person">
import { ref } from 'vue';let name = ref('张三');
let age = ref(18);
const tel = '13800138000';
const address = '北京';function changeName() {name.value = '李四';
};
function changeAge() {age.value += 1;
};
function showTel() {alert(tel);
};
</script><style scoped lang="less">
.person {button {display: block;margin: 10px 0;}
}
</style>
定义对象类型的响应式数据,表面使用的是ref,其实底层用的还是reactive
<template><div class="person"><h2>汽车信息: 一辆{{ car.brand }}车,价值{{ car.price }}</h2><button @click="changePrice">修改汽车的价格</button><br><h2>游戏列表: </h2><ul><li v-for="game in games" :key="game.id">{{ game.name }}</li></ul><button @click="changeFirstGameName">修改第一个游戏的名字</button></div>
</template><script setup lang="ts" name="Person">
import { ref } from 'vue';let car = ref({brand: 'BMW',price: 100,
});
let games = ref([{ name: 'LOL', id: 1 },{ name: 'CSGO', id: 2 },{ name: 'DOTA', id: 3 },
]);function changePrice() {car.value.price += 10;
};
function changeFirstGameName() {games.value[0].name = '王者荣耀';
};
</script>
reactive
用于(只能)定义对象类型的响应式数据
<template><div class="person"><h2>汽车信息: 一辆{{ car.brand }}车,价值{{ car.price }}</h2><button @click="changePrice">修改汽车的价格</button><br><h2>游戏列表: </h2><ul><li v-for="game in games" :key="game.id">{{ game.name }}</li></ul><button @click="changeFirstGameName">修改第一个游戏的名字</button><br><h2>{{ obj.a.b.c }}</h2><button @click="changeObj">修改obj</button></div>
</template><script setup lang="ts" name="Person">
import { reactive } from 'vue';let car = reactive({brand: 'BMW',price: 100,
});
let games = reactive([{ name: 'LOL', id: 1 },{ name: 'CSGO', id: 2 },{ name: 'DOTA', id: 3 },
]);
let obj = reactive({a: {b: {c: 666,}}
})function changePrice() {car.price += 10;
};
function changeFirstGameName() {games[0].name = '王者荣耀';
};
function changeObj() {// reactive的响应式是深层次的obj.a.b.c = 1000;
};
</script>
ref与reactive
1. ref用来定义:基本类型数据、对象类型数据
2. reactive用来定义:对象类型数据
区别:
1. ref创建的变量必须使用 .value (可以使用volar插件自动添加 .value)
2. reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)
<template><div class="person"><h2>汽车信息: 一辆{{ car.brand }}车,价值{{ car.price }}</h2><button @click="changeCar">修改汽车</button></div>
</template><script setup lang="ts" name="Person">
import { reactive } from 'vue';let car = reactive({brand: 'BMW',price: 100,
});function changeCar() {// 这样会失去响应式// car = {// brand: '奔驰',// price: 200,// };// 这样不会失去响应式Object.assign(car, {brand: '奔驰',price: 200,});
};
</script>
使用原则:
1. 若需要一个基本类型的响应式数据,必须使用ref
2. 若需要一个响应式对象,层级不深,ref、reactive都可以
3. 若需要一个响应式对象,且层级较深,推荐使用reactive
toRefs
把一个响应式对象中的内容拿出来,依然具备响应式的能力
<template><div class="person"><h2>{{ person.name }}</h2><h2>{{ person.age }}</h2><button @click="changeName">修改姓名</button><button @click="changeAge">修改年龄</button></div>
</template><script setup lang="ts" name="Person">
import { reactive, toRefs } from 'vue';const person = reactive({name: '张三',age: 18,
});// 直接从响应式对象中解构出来的变量都不是响应式的 需要toRefs包裹才会变成响应式的
let { name, age } = toRefs(person);function changeName() {// 这里修改之后 name、person.name 都会改变name.value += '~';
};
function changeAge() {age.value += 1;
};
</script><style scoped lang="less">
.person {button {margin: 10px;}
}
</style>
toRef
作用和toRefs一样,但每次只能取一个
<template><div class="person"><h2>{{ person.name }}</h2><h2>{{ person.age }}</h2><button @click="changeName">修改姓名</button></div>
</template><script setup lang="ts" name="Person">
import { reactive, toRef } from 'vue';const person = reactive({name: '张三',age: 18,
});let name = toRef(person, 'name');function changeName() {// 这里修改之后 name、person.name 都会改变name.value += '~';
};
</script>