目录
- 更小的打包体积和内存
- 更好的支持 TypeScript
- 页面第一次的渲染速度和更新速度更快
- 新增了 Composition API 和内置组件
npm install -g @vue/cli
Node 版本要求
Vue CLI 4.x 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)。你可以使用 n,nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。
vue create hello-vue3
报错:vue : 无法加载文件xxx 因为在此系统上禁止运行脚本
解决:以管理员身份运行VS Code,在终端输入 set-ExecutionPolicy RemoteSigned 即可。
使用 vue -V 查看 Vue CLI版本
vue -V
选择 Vue 3 

然后
cd hello-vue3
npm run serve

打开网页 http://localhost:8080。这样一个 Vue3 脚手架项目就创建完成了

整个项目的入口文件

所有⼦组件的⽗组件

- setup 函数是Vue3新的配置项
- 是使用组合API的前提,数据、方法都要放到 setup 函数里声明
- 在生命周期函数 beforeCreate 之前执行一次,而且 setup 函数没有 this
- <div>姓名:{{name}}div>
- <div>年龄:{{age}}div>
- <button @click="hello">打招呼button>
- <script>
- export default {
- setup() { // setup函数,里面使用 js 原生语法
- let name = '张三';
- let age = 18;
- function hello () {
- alert(`你好,我是${name},今年${age}岁了`);
- }
- return { // vue 中要使用 setup 里定义的变量、函数的话,需要把变量、函数 return 出去
- name,
- age,
- hello
- }
- }
- }
- script>
用于接收父组件的值
- export default {
- props: ["msg"], // 接收父组件的值
- setup(props) {
- console.log(props.msg); // setup 中获取父组件的值
- }
- }
上下文对象,触发自定义事件
父组件代码
-
- <HelloWorld @dj="handleDianji"/>
-
- <script>
- import HelloWorld from './components/HelloWorld.vue'
-
- export default {
- components: {
- HelloWorld
- },
- setup() {
- // 自定义事件回调
- function handleDianji(value) {
- console.log("打印子组件传过来的值=", value);
- }
- return {
- handleDianji
- }
- }
- }
- script>
子组件代码
- <button @click="dianji">点击button>
- <script>
- export default {
- emits: ["dj"], // 声明自定义事件
- setup(props, context) {
- function dianji() {
- context.emit("dj", "我是子组件的值"); // 触发自定义事件
- }
- return {
- dianji
- }
- }
- }
- script>
实现数据的响应式 // setup定义的变量数据,如果想通过setup中定义的函数改变数据是没有作用的。这里就要用到 ref 函数改变数据
- 可以处理基本类型数据、数组或者对象类型的数据
- 基本类型数据的响应式是通过 Object.defineProperty() 实现
- 对象类型数据的响应式是通过 ES6 中的 Proxy 实现
- <div>姓名:{{name}}div>
- <div>年龄:{{age}}div>
- <div>性别:{{obj.sex}}div>
- <button @click="hello">打招呼button>
- <button @click="changePreson">切换人员button>
- <script>
- import { ref } from "vue"; // 引入 ref 函数
-
- export default {
- setup() {
- let name = ref("张三"); // ref 操作基本数据类型
- let age = ref(18);
-
- let obj = ref({ // ref 操作对象
- sex: "man"
- });
-
- function hello() {
- alert(`你好,我是${name.value},今年${age.value}岁了, 性别${obj.value.sex}`);
- }
-
- function changePreson() {
- name.value = "李四";
- age.value = "20";
- obj.value.sex = "female"
- }
-
- return {
- name,
- age,
- obj,
- hello,
- changePreson
- }
- }
- }
- script>
定义一个对象类型的响应式数据(不能处理基本类型数据)
- <div>姓名:{{name}}div>
- <div>年龄:{{age}}div>
- <div>性别:{{obj.sex}}div>
- <button @click="hello">打招呼button>
- <button @click="changePreson">切换人员button>
- <script>
- import { ref, reactive } from "vue"; // 引入 ref 函数
-
- export default {
- setup() {
- let name = ref("张三"); // ref 操作基本数据类型
- let age = ref(18);
-
- let obj = reactive({ // reactive 操作对象
- sex: "man"
- });
-
- function hello() {
- alert(`你好,我是${name.value},今年${age.value}岁了, 性别${obj.sex}`);
- }
-
- function changePreson() {
- name.value = "李四";
- age.value = "20";
- obj.sex = "female"
- }
-
- return {
- name,
- age,
- obj,
- hello,
- changePreson
- }
- }
- }
- script>
- 处理数据类型不同:ref 可以处理基本类型和对象(数组)类型数据, reactive 只能处理对象(数组)类型数据
- 实现原理不同:ref 处理基本类型数据通过 Object.defineProperty() 实现, reactive 通过Proxy 实现
- 操作不同: ref 操作数据需要加 .value
- <div>{{fullName}}div>
- <script>
- import { ref, computed } from "vue";
- export default {
- setup() {
- let firstName = ref("张");
- let lastName = ref("三");
- let fullName = computed({
- get() {
- return firstName.value + "-" + lastName.value;
- },
- set(value) {
- const arr = value.split("-");
- firstName.value = arr[0];
- lastName.value = arr[1];
- }
- })
- return {
- firstName,
- lastName,
- fullName
- }
- }
- }
- script>
- <h1>
- 当前的计数a:<span>{{ numa }}span> <br />
- 当前的计数b:<span>{{ numb }}span> <br />
- h1>
- <button @click="numa++">增加abutton>
- <button @click="numb++">增加bbutton>
- <hr />
- <script>
- import { ref, watch } from "vue";
- export default {
- setup() {
- let numa = ref(1);
- let numb = ref(1);
-
- watch([numa, numb], (newValue, oldValue) => {
- console.log("numa或者numb变化了", newValue, oldValue);
- }, { immediate: true, deep: true });
-
- return {
- numa,
- numb
- };
- },
- };
- script>
监听对象
- watch(numObj, (newValue, oldValue) => {
- console.log("numObj变化了", newValue, oldValue);
- })
监听对象中的一个基本类型属性
- watch(
- () => numObj.a,
- (newValue, oldValue) => {
- console.log("numObj变化了", newValue, oldValue);
- }
- );
监听对象中的一些基本类型属性
- watch([() => numObj.a, () => numObj.b], (newValue, oldValue) => {
- console.log("numObj变化了", newValue, oldValue);
- });
监听对象中的对象属性类型
- watch(
- numObj.c,
- (newValue, oldValue) => {
- console.log("numObj.c变化了", newValue, oldValue);
- }
- );
- ref 定义的数据
- 基本类型数据作为监听值
- 对象作为监听值,需要加 .value (⽤的少)
- reactive 定义的数据
- 对象作为监听值
- 属性作为监听值,需要放在回调函数中
- 如果监听 reactive 定义的对象,则无法正确输出 oldValue ,且深度监听是强制开启的,无法关闭 (vue3配置)
在监听的回调函数中使⽤了属性,则监听该属性,不⽤在参数上指明监听哪个属性
- import { ref, watchEffect } from "vue";
- export default {
- setup() {
- let numa = ref(1);
- watchEffect(() => {
- console.log(numa.value); // 在监听中使用了 numa 属性,就默认监听此属性
- console.log("watchEffect函数执行了");
- });
- return {
- numa
- };
- }
- };
创建一个 ref 对象,其 value 值指向另一个对象中指定的属性 // 相当于起了个别名
- <h1>
-
- {{aliasName}}
- h1>
- <script>
- import { reactive, toRef} from "vue";
- export default {
- setup() {
- let data = reactive({
- name: "张三"
- });
-
- let aliasName = toRef(data, "name"); // 相当于 把data的name属性定义了一个别名
-
- return {
- data,
- aliasName,
- }
- }
- };
- script>
批量创建 ref 对象,其 value 值指向另一个对象 // 相当于批量起别名
- <h1>
- {{name}}
- {{age}}
- h1>
- <script>
- import { reactive, toRefs} from "vue";
- export default {
- setup() {
- let data = reactive({
- name: "张三",
- age: 18
- });
-
- return {
- ...toRefs(data)
- }
- }
- };
- script>
- import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from "vue";
- export default {
- setup() {
- console.log("===setup===");
-
- onBeforeMount(()=>{
- console.log("===挂载前===");
- })
- onMounted(()=>{
- console.log("===挂载后===");
- })
- onBeforeUpdate(()=>{
- console.log("===更新前===");
- })
- onUpdated(()=>{
- console.log("===更新后===");
- })
- onBeforeUnmount(()=>{
- console.log("===卸载前===");
- })
- onUnmounted(()=>{
- console.log("===卸载后===");
- })
- }
- };
- provide:祖组件使用此函数传递数据
- inject:后代组件使用此函数接收数据
- // 上级组件代码
- import { ref, reactive, provide } from 'vue';
- export default {
- components: {
- HelloWorld
- },
- setup() {
- let name = ref("张三");
- provide("name", name) // 父组件使用 provide 向下级(多级都可以)组件传值
-
- let obj = reactive({
- name: "李四",
- age: 18
- });
- provide("obj", obj);
- }
- }
- // 下级(多层下级都可以)组件代码
- import { inject } from "vue";
- export default {
- setup() {
- let name = inject("name");
- console.log("下级组件接收到值=",name.value);
-
- let obj = inject("obj");
- console.log("下级组件接收到值=",obj);
- }
- };