Vue3 - 从 vue2 到 vue3 过渡,这一套就够了(案例 + 效果演示)(一)

本文详细介绍了Vue3相较于Vue2的改进,包括性能提升、源码升级、TypeScript支持以及新特性如setup、ref和reactive的使用。还讲解了如何创建Vue3项目、配置setup、响应式数据处理和组件间通信方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  免费查看本文章可前往我的网站:PiQiu

目录

一、Vue3 从入门到进阶

1.1、Vue3 相比于 Vue2 好在哪里?

1.2、创建 vue-cli3 脚手架

1.3、Vue3 的使用

1.3.1、拉开序幕的 setup

1.3.2、ref 函数

什么是响应式数据

ref 响应式处理

1.3.3、reactive

1.3.4、reactive 对比 ref

1.3.5、setup 的参数(props、context)

1.3.6、computed 计算属性


一、Vue3 从入门到进阶


1.1、Vue3 相比于 Vue2 好在哪里?

Ps:以下数据来源于官网

a)性能提升:

  • 打包大小减少 41%.
  • 初次渲染快 55%,更新渲染快 133%.
  • 内存减少 54%.
  • ......

b )源码升级:

  • 使用 Proxy 代替 defineProperty 实现响应式.
  • 重写虚拟 DOM 的实现和 Tree-Shaking
  • ......

c)拥抱 TypeScript:

  • Vue3 可以更好的支持 TypeScript

d)新特性:

  • setup 配置
  • ref 与 reactive
  • watch 与 watchEffect
  • provide 与 inject

1.2、创建 vue-cli3 脚手架

Ps:具体怎么创建,可以看这篇 http://t.csdnimg.cn/rq4slhttp://t.csdnimg.cn/rq4sl

a)查看当前 vue-cli 的版本,确保在 4.5.0 以上.

 b)安装或者升级 @vue/cli

npm install -g @vue/cli

c)创建

vue create vue_demo

d)启动

cd vue_demo
npm run serve

e)修改 vue.config.js 内容为如下内容,就是为了关闭语法检查

f)main.js 说明

//引入的不再是 vue 构造函数了, 引入的是一个名为 createApp 的工厂函数
import { createApp } from 'vue'
import App from './App.vue'

//创建应用实例对象 —— app
const app = createApp(App)
//挂载
app.mount('#app')

g)新特性之一,vue3 的模板接口可以没有根标签

1.3、Vue3 的使用

1.3.1、拉开序幕的 setup

vue3 中有一个新的配置项,值是一个函数.  他是所有组合 API 的“舞台”,也就是说,之前 vue2 组件中使用到的 data、methods...... 都要配置在 setup 中.

a)setup 函数有三种返回值:

  • 若返回一个对象,那么对象的属性、方法,在模板种就可以使用了.
  • 若返回的是一个渲染函数,那么就可以自定义渲染内容(后面细讲,当前只做了解).

b)注意点(请忘掉 vue2 中的 data、methods... 现在是 vue3 的时代):

  • 尽量不要和 vue2.x 混用,原因如下:
    • vue2.x 配置的 data、methods、 computed....... 种可以访问到 setup 中的属性方法,但是 setup 中不能访问到 vue2.x 配置中的 data、methos、computed......
    • 如果有重名,setup 优先.
  • setup 不是一个 async 函数,因为返回值不再是 return 的对象,而是 promise ,模板看不到 return 对象中的属性.

c)案例如下:

<template>
  <!-- vue3 中模板接口可以没有跟标签 -->
  <div>你好</div>
  <div>欢迎来到 vue3</div>
  <div>{{ name }}</div>
  <button @click="sayHi">点我,进行自我介绍~</button>
</template>

<script>
export default {
  name: "App",
  //这里暂时限不考虑响应式的问题
  setup() {
    //数据
    let name = "cyk";
    let age = 18;

    //方法
    function sayHi() {
      alert(`大家好啊,我是${name}, 今年 ${age} 了`);
    }

    return {
      //模板中需要什么数据,就返回什么
      name,
      age,
      sayHi,
    };
  },
};
</script>

点击按钮效果如下 

d)你会发现,当你定义的变量越多,需要 return 的就越多,代码可读性降低了不少.  我们实际上可以把一组关联的数据封装到对象中,这样直接返回这个对象就可以了(这样也要注意的是需要通过 对象.属性名 的方式获取属性). 

<template>
  <div>name: {{ user.name }}</div>
  <div>age: {{ user.age }}</div>
  <div>weight: {{ user.weight }}</div>
</template>

<script>

export default {
  name: "App",
  setup() {
    let user = {
      name: "cyk",
      age: 18,
      weight: "60kg",
    };

    return {
      user,
    };
  },
};
</script>

e)当然,有一天你发现自己定义的对象越来越多,最后 return 的东西越来越多,可读性又降低了,那么你可以借鉴 vue2 的方式这样定义数据(doge)

  setup() {

    let data = {
      student: {
        //...
      },
      teacher: {
        //...
      },

      //......
    };

    return {
      data,
    };

  },

1.3.2、ref 函数

什么是响应式数据

你可以简单的将响应式数据理解为动态数据,也就是说,你对响应式数据的修改,在页面是会得到及时的反馈.

例如通过点击按钮,对 name 进行修改操作,同时希望页面能得到及时的反馈.

非响应式:

<template>
  <div>name: {{ name }}</div>
  <button @click="changeName()">点我改变 name</button>
</template>

<script>
export default {
  name: "App",
  setup() {
    let name = "cyk";

    function changeName() {
      name = "lyj";
      alert("修改完成!");
    }

    return {
      name,
      changeName,
    };
  },
};
</script>

点击按钮之后,name 并没有修改,这就是非响应式,那么如果我们希望它是响应式就需要依靠 ref 函数了

ref 响应式处理

a)ref 就是用来处理一个响应式数据.

语法如下:

// 创建一个响应式数据的引用对象(reference 对象,简称 ref 对象)
const xxx = ref(initValue)

// js 中操作数据
xxx.value

// 模板中读取数据
<div>{{xxx}}</div>

使用步骤:

  1. 引入 ref 组件(这一步很容易忘记)
  2. 定义 响应式 对象
  3. 返回对象

通过 console.log(ref("lyj")),就可以观察到以下结果

ref 底层是通过 Object.defineProperty() 的 get 和 set 来实现响应式的 

b)例如通过点击按钮,对 name 进行修改操作,同时希望页面能得到及时的反馈.

<template>
  <div>name: {{ name }}</div>
  <button @click="changeName()">点我改变 name</button>
</template>

<script>
import { ref } from "vue"; //引入 ref 组件

export default {
  name: "App",
  setup() {
    let name = ref("cyk"); //这里返回的是一个对象,通过 .value 就可以拿到值

    function changeName() {
      name.value = "lyj"; //必须通过 value 才能获取到对应的值
      alert("修改完成!");
    }

    return {
      name,
      changeName,
    };
  },
};
</script>

点击按钮前

点击按钮后

c)那么问题来了,如果 ref 中的值是一个嵌套对象,该怎么获取里面的值呢?难道每嵌套一层都需要使用 value 来获取一层么?

如果是嵌套对象,我们可以先这样理解,ref 就相当于对对象的一层封装嘛,通过 .value 的方式就可以拿到对象,此时对象无论怎么封装,原先 js 语法怎么获取,现在就怎么处理.

如下,怎么获取 name 和 c 呢?

    let user = ref({
      name: "cyk",
      a: {
        b: {
          c: 666,
        },
      },
    });

 name 就不多说了,首先 ref 是通过里面的值是一个 {...} 对象,因此通过 value 就可以拿到这个对象,那么接下来通过对象拿属性值的方式获取即可.

    function getUser() {
      console.log(user);
      console.log(user.value.name);
      console.log(user.value.a.b.c);
    }

 

对于对象的处理, ref 底层是 调用了 reactive 的 Proxy 来实现响应式的,并通过 Reflect 操作内部的数据.

1.3.3、reactive

a)通过上面讲述可以看出,ref 每次获取值都需要通过 .value 的方法获取,很麻烦.  那么接下来要将的 reactive 就是用来解决这个问题的.

b)reactive 就是用来定义个 对象类型 的响应式数据(基本类型不能用它,只能使用 ref 函数).

Ps:实在想用,你可以把基本类型封装成对象啊

c)reactive 内部是基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作.

d)用法如下:

<template>
  <div>{{ user.name }}</div>
  <div>{{ user.age }}</div>
  <div>{{ user.likes[2] }}</div>
  <div>{{ user.a.b.c }}</div>
  <button @click="changeInfo">点我改变信息</button>
</template>

<script>
import { ref, reactive } from "vue"; //引入 reactive
export default {
  name: "App",
  setup() {
    let tips = ref(1);
    let user = reactive({
      name: "cyk",
      age: 18,
      likes: ["唱歌", "弹琴", "谈情"],
      a: {
        b: {
          c: 666,
        },
      },
    });

    function changeInfo() {
      // ref 定义的响应式对象需要通过 .value 的方式获取
      tips.value = 2;
      // reactive 定义的响应式对象可以直接获取
      user.name = "lyj";
      user.age = 17;
      user.likes[2] = "谈锤子";
      user.a.b.c = 999;
    }

    return {
      tips,
      user,
      changeInfo,
    };
  },
};
</script>

1.3.4、reactive 对比 ref

a)定义数据的角度:

  • ref 可定义的数据:基本类型、对象(或数组)类型, 但是对于 对象(或数组)类型,内部是通过 reactive 转为 代理对象。
  • reactive 可定义的数据:对象(或数组)类型.

b)使用的角度:

  • ref:操作数据需要 .value   在模板中读取数据不需要 .value
  • reactive:操作和读取数据都不用 .value

c)原理角度:

  • ref:通过 Object.defineProperty() 的 get 与 set 来实现响应式.
  • reactive:通过使用 Proxy 来实现响应式,并通过 Reflect 操作源对象内部的数据.

1.3.5、setup 的参数(props、context)

setup 的参数如下:

a)props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性

例如父组件向 User 子组件传递数据

<template>
  <User name="cyk" :age="age" />
</template>

<script>
import User from "./views/User.vue"; //引入自定义的组件 User
export default {
  name: "App",
  components: { User }, //声明
  setup() {
    let age = 18;
    return {
      age,
    };
  },
};
</script>

User 子组件中使用数据

<template>
  <h1>我是一个学生</h1>
  <div>name: {{ user.name }}</div>
  <div>age: {{ user.age }}</div>
</template>

<script>
export default {
  name: "User",
  props: ["name", "age"],
  setup(props) {
    let user = {
      name: props.name,
      age: props.age,
    };
    return {
      user,
    };
  },
};
</script>

b)context:上下文对象

  • atts:值为对象,包含:组件外传递过来,但没有在 props 配置中声明的属性,相当于 this.$attrs.
  • slots:受到的插槽内容,相当于 this.$slots.
  • emit:分发自定义事件的函数,相当于 this.$emit.

父组件中定义 hello 事件,自定义名为 helloBtn 传递给子组件 User.

<template>
  <!-- @自定义传递的事件名="当前组件 setup return 的函数" -->
  <User @helloBtn="hello" name="cyk" :age="age" />
</template>

<script>
import User from "./views/User.vue"; //引入自定义的组件 User
export default {
  name: "App",
  components: { User }, //声明
  setup() {
    let age = 18;
    function hello() {
      alert("hello");
    }
    return {
      age,
      hello,
    };
  },
};
</script>

子组件中通过 emits 接收 helloBtn 事件

<template>
  <h1>我是一个学生</h1>
  <div>name: {{ user.name }}</div>
  <div>age: {{ user.age }}</div>
  <button @click="test">父组件传递的事件</button>
</template>

<script>
export default {
  name: "User",
  props: ["name", "age"],
  //拿到父组件传递的事件,他会交给 setup 中的 context 参数
  emits: ["helloBtn"],
  setup(props, context) {
    let user = {
      name: props.name,
      age: props.age,
    };
    function test() {
      //拿到父组件的事件
      context.emit("helloBtn");
    }
    return {
      user,
      test,
    };
  },
};
</script>

1.3.6、computed 计算属性

与 vue2.x 中的 computed 配置功能一样,凡是需要实时计算的地方就使用它即可

a)简写:没有考虑计算属性被修改的情况

<template>
  <h1>求和</h1>
  <div>
    <input type="number" v-model="test.a" />
  </div>
  <div>
    <input type="number" v-model="test.b" />
  </div>
  <div>结果: {{ result }}</div>
</template>

<script>
import { computed, reactive } from "vue";
export default {
  name: "App",
  setup() {
    let test = reactive({
      a: 0,
      b: 0,
    });
    let result = computed(() => {
      return test.a + test.b;
    });
    return {
      test,
      result,
    };
  },
};
</script>

 

b)完整写法:重写 get  set 方法(考虑读和写)

假设需求是:读取时要 a 和 b 的和,修改时要求得到  result 的均分到 a 和 b 

<template>
  <h1>求和</h1>
  <div>
    <input type="number" v-model="test.a" />
  </div>
  <div>
    <input type="number" v-model="test.b" />
  </div>
  <div>
    <span>结果: </span>
    <input type="number" v-model="result" />
  </div>
</template>

<script>
import { computed, reactive } from "vue";
export default {
  name: "App",
  setup() {
    let test = reactive({
      a: 0,
      b: 0,
    });
    //简写:没有考虑计算属性被修改的情况
    // let result = computed(() => {
    //   return test.a + test.b;
    // });
    //完整写法:重写 get set 方法
    let result = computed({
      get() {
        return test.a + test.b;
      },
      set(value) {
        test.a = value / 2;
        test.b = value / 2;
      },
    });

    return {
      test,
      result,
    };
  },
};
</script>

当 a  = 5、b  = 9 ,读取如下:

当 result = 15,a 和 b 被修改的情况如下:

Ps:下一篇 “ Vue3 - 从入门到进阶,这一套就够了(案例 + 效果演示)(二)”

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值