前端宝典二十六:vue3的新特性

一、Vue2处理响应式的源码方式:

const initData =  {
  value: 1
}
const data = {};

Object.keys(initData).forEach(key => {
  Object.defineProperty(data, key, {
    get() {
      return initData[key]
    },
    set(value) {
      initData[key] = value
    }
  })
})

console.log(data.value) // 1
initData.value2 = 4;
console.log(initData.value2) // 4
console.log(data.value2) // undefined

修改initData.value2的值,data值没有修改,这是因为初始化劫持时已经拿到了initData所有的key,然后使用Object.defineProperty来修改getter和setter方法,如果再用initData.value2 = 4方法修改,data是拿不到更新的值的
因此,在Vue2中有几种修改方式是无法更新data值的:

  • 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

为了解决第二类问题,你可以使用 splice:

example1.items.splice(newLength)

为了解决Vue2中的问题,Vue3进行了修改

二、Vue3处理响应式的方式

const initData =  {
  value: 1
}

const proxy = new Proxy(initData, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver);
  }
}) 

console.log(proxy.value)
proxy.value = 2
console.log(proxy.value)

Reflect与Proxy的handler结合,修改getter和setter方法,实现数据劫持响应

三、Vue3响应式的使用方式

在 Vue 3 中,refreactiveshallowReactiveshallowReftoRefstoRef都用于处理响应式数据,但它们之间存在一些区别。

一、ref

ref用于创建一个响应式的数据对象,内部包含一个值,访问时需要通过 .value属性。

示例代码:

<template>
  <div>
    <p>{{ counter }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const counter = ref(0);
    const increment = () => {
      counter.value++;
    };
    return {
      counter,
      increment
    };
  }
};
</script>

在这个例子中,counter是一个使用ref创建的响应式变量,通过修改counter.value来更新其值,视图也会随之更新。

注意:
ref只追踪对 .value 的直接修改。如果 .value 是一个对象,内部属性的修改不会自动触发响应。但可以通过 reactive 包裹 .value 内部的对象来实现深度响应性。
例如:const objRef = ref({ prop: 1 }); objRef.value.prop = 2;(这不会触发响应,除非使用特殊方法如 Vue.set(objRef.value, 'prop', 2))。
二、reactive

reactive用于创建一个响应式的对象。它会深度响应式地追踪对象内所有属性的变化。

示例代码:

<template>
  <div>
    <p>{{ person.name }}</p>
    <p>{{ person.age }}</p>
    <button @click="updatePerson">Update Person</button>
  </div>
</template>

<script>
import { reactive } from 'vue';

export default {
  setup() {
    const person = reactive({
      name: 'John',
      age: 30
    });
    const updatePerson = () => {
      person.name = 'Jane';
      person.age++;
    };
    return {
      person,
      updatePerson
    };
  }
};
</script>

这里,person对象是使用reactive创建的响应式对象,修改其属性会触发视图更新。
reactive深度响应式地追踪对象内所有属性的变化。当对象的属性被修改时,会自动触发响应。
例如:const obj = reactive({ prop: 1 }); obj.prop = 2;(这会触发响应)。

因此:

  • 如果只是对值的响应式请用ref
  • 如果是对复杂对象的响应式请用reactive

三、shallowReactive

shallowReactive创建一个响应式对象,但只对对象的第一层属性进行追踪,不会深度追踪嵌套对象的属性变化。

示例代码:

<template>
  <div>
    <p>{{ shallowPerson.name }}</p>
    <p>{{ shallowPerson.age }}</p>
    <p>{{ shallowPerson.nestedObj.prop }}</p>
    <button @click="updateShallowPerson">Update Shallow Person</button>
  </div>
</template>

<script>
import { shallowReactive } from 'vue';

export default {
  setup() {
    const shallowPerson = shallowReactive({
      name: 'John',
      age: 30,
      nestedObj: {
        prop: 'initial'
      }
    });
    const updateShallowPerson = () => {
      shallowPerson.name = 'Jane';
      shallowPerson.age++;
      // 修改嵌套对象的属性,不会触发视图更新
      shallowPerson.nestedObj.prop = 'updated';
    };
    return {
      shallowPerson,
      updateShallowPerson
    };
  }
};
</script>

四、shallowRef

shallowRef创建一个响应式的引用,但只追踪对其 .value的直接修改,不会深度追踪其 .value内部属性的变化。

示例代码:

<template>
  <div>
    <p>{{ shallowRefValue.num }}</p>
    <button @click="updateShallowRefValue">Update Shallow Ref Value</button>
  </div>
</template>

<script>
import { shallowRef } from 'vue';

export default {
  setup() {
    const shallowRefValue = shallowRef({ num: 1 });
    const updateShallowRefValue = () => {
      // 直接修改 shallowRefValue.value 会触发更新
      shallowRefValue.value = { num: 2 };
      // 修改 shallowRefValue.value 内部属性不会触发更新
      shallowRefValue.value.num = 3;
    };
    return {
      shallowRefValue,
      updateShallowRefValue
    };
  }
};
</script>

五、toRefs

toRefs用于将一个响应式对象转换为一组属性的引用,这样可以在解构响应式对象时保持属性的响应性。

示例代码:

<template>
  <div>
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <button @click="updatePerson">Update Person</button>
  </div>
</template>

<script>
import { reactive, toRefs } from 'vue';

export default {
  setup() {
    const person = reactive({
      name: 'John',
      age: 30
    });
    // 使用 toRefs 将 person 转换为一组引用
    const { name, age } = toRefs(person);
    const updatePerson = () => {
      person.name = 'Jane';
      person.age++;
    };
    return {
      name,
      age,
      updatePerson
    };
  }
};
</script>

六、toRef

toRef创建一个对响应式对象中某个特定属性的引用。

示例代码:

<template>
  <div>
    <p>{{ personName }}</p>
    <button @click="updatePersonName">Update Person Name</button>
  </div>
</template>

<script>
import { reactive, toRef } from 'vue';

export default {
  setup() {
    const person = reactive({
      name: 'John',
      age: 30
    });
    const personName = toRef(person, 'name');
    const updatePersonName = () => {
      personName.value = 'Jane';
    };
    return {
      personName,
      updatePersonName
    };
  }
};
</script>

综上所述,refreactive分别用于创建单个响应式值和对象,shallowReactiveshallowRef提供了更浅层的响应性追踪,toRefs用于在解构响应式对象时保持属性的响应性,toRef用于创建对特定属性的引用。在实际应用中,可以根据具体需求选择合适的方法来处理响应式数据。

四、watch

watch(()=> state.count, (val, oldVal)=>{
    console.log('watch', val, oldVal)
})
watch([()=> state.count, ()=> state.name], ([val1, val2], [oldVal1, oldVal2])=>{
     

这里有两种,一种是监听单个,一种是监听数组

五、 Vue 3 相比 Vue 2 有很多新特性

以下是一些主要的方面:

一、性能提升

  1. 编译优化:

    • 静态提升(Static Hoisting):Vue 3 在编译阶段会分析模板,将静态的节点提升到渲染函数之外,避免在每次渲染时重复创建。这可以提高运行时的性能,特别是在大型应用中。
    • 补丁算法优化:Vue 3 的虚拟 DOM 补丁算法更加高效,能够快速识别和更新变化的部分,减少不必要的 DOM 操作。
    • 事件监听缓存:对于频繁触发的事件监听器,Vue 3 会进行缓存,避免在每次更新时重新绑定事件监听器,提高性能。
  2. 体积更小:Vue 3 进行了优化,整体包体积更小,使得应用加载更快,占用的网络带宽更少。

二、组合式 API(Composition API)

  1. 更好的逻辑复用:组合式 API 允许开发者将相关的逻辑封装在函数中,然后在不同的组件中复用这些函数。这使得逻辑复用更加灵活和可维护,避免了在 Vue 2 中使用 mixins 可能带来的命名冲突和不清晰的问题。
  2. 更清晰的代码结构:通过组合式 API,可以将组件的逻辑按照功能进行分组,使得代码结构更加清晰,易于理解和维护。例如,可以将数据获取、状态管理、副作用处理等分别封装在不同的函数中。
  3. 响应式系统改进:Vue 3 的响应式系统基于 Proxy 对象实现,相比 Vue 2 的 Object.defineProperty 更加高效和强大。可以直接监听对象和数组的变化,而不需要进行额外的处理。

三、Teleport(传送门)

Vue 3 引入了 Teleport 组件,允许将一个组件的模板内容传送到指定的 DOM 节点中,而不是在组件的父级层次结构中渲染。这在处理模态框、弹出窗口等场景时非常有用,可以将这些元素渲染到页面的特定位置,而不受组件层次结构的限制。

四、Fragments(片段)

在 Vue 2 中,组件的模板必须有一个根元素。而在 Vue 3 中,可以使用 Fragments,即组件的模板可以没有根元素,多个元素可以直接作为组件的模板内容。这使得模板更加灵活,特别是在处理复杂的布局时。

五、Emits 选项的改进

Vue 3 对组件的 emits 选项进行了改进,使其更加严格和明确。可以在 emits 选项中定义组件触发的事件名称和参数类型,从而提高代码的可读性和可维护性。

六、更好的 TypeScript 支持

Vue 3 对 TypeScript 的支持更加友好,提供了更好的类型推断和类型定义。组合式 API 与 TypeScript 结合使用时,可以获得更好的类型安全和代码提示。

七、Suspense(异步组件加载)

Vue 3 改进了异步组件的加载方式,引入了 Suspense 组件,可以在异步组件加载过程中显示加载状态或错误信息。这使得异步组件的使用更加方便和用户友好。

这些只是 Vue 3 的一些主要新特性,还有其他一些小的改进和优化。总的来说,Vue 3 在性能、开发体验和功能方面都有了很大的提升,为开发者提供了更强大的工具来构建高效、可维护的前端应用。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值