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

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

html 复制代码
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 相同的效果,同时也将触发状态更新:

java 复制代码
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

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

java 复制代码
example1.items.splice(newLength)

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

二、Vue3处理响应式的方式

javascript 复制代码
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属性。

示例代码:

vue 复制代码
<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用于创建一个响应式的对象。它会深度响应式地追踪对象内所有属性的变化。

示例代码:

vue 复制代码
<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创建一个响应式对象,但只对对象的第一层属性进行追踪,不会深度追踪嵌套对象的属性变化。

示例代码:

vue 复制代码
<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内部属性的变化。

示例代码:

vue 复制代码
<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用于将一个响应式对象转换为一组属性的引用,这样可以在解构响应式对象时保持属性的响应性。

示例代码:

vue 复制代码
<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创建一个对响应式对象中某个特定属性的引用。

示例代码:

vue 复制代码
<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

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

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

五、在 Vue 3 中可以继续使用 Vue 2 的一些生命周期方法

但 Vue 3 也引入了新的组合式 API 的生命周期钩子,并且推荐优先使用新的生命周期钩子。

1、Vue 2 生命周期在 Vue 3 中的兼容性

  1. beforeCreatecreated

    • 在 Vue 3 的选项式 API 中仍然可以使用这两个生命周期钩子,其行为与 Vue 2 基本一致。

    • 示例:

      vue 复制代码
      export default {
        beforeCreate() {
          console.log('beforeCreate called');
        },
        created() {
          console.log('created called');
        },
        //...
      };
  2. beforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed

    • 同样可以在 Vue 3 的选项式 API 中使用,功能也基本保持不变。

    • 例如:

      vue 复制代码
      export default {
        mounted() {
          console.log('mounted called');
        },
        updated() {
          console.log('updated called');
        },
        //...
      };

2、推荐使用 Vue 3 组合式 API 的生命周期钩子

Vue 3 引入了新的组合式 API,其中提供了与选项式 API 生命周期钩子相对应的函数形式的钩子:

  1. onBeforeMount:在组件挂载之前调用。
  2. onMounted:在组件挂载完成后调用。
  3. onBeforeUpdate:在组件即将更新之前调用。
  4. onUpdated:在组件更新完成后调用。
  5. onBeforeUnmount:在组件卸载之前调用。
  6. onUnmounted:在组件卸载完成后调用。

示例:

vue 复制代码
import { onMounted, onUpdated } from 'vue';

export default {
  setup() {
    onMounted(() => {
      console.log('onMounted called');
    });
    onUpdated(() => {
      console.log('onUpdated called');
    });
    //...
    return {};
  }
};

使用组合式 API 的生命周期钩子具有以下优点:

  • 可以更好地组织和复用逻辑,因为可以将相关的逻辑放在一起,而不是分散在不同的生命周期钩子中。
  • 与 Vue 3 的新特性更好地集成,如响应式系统和组合式函数。

综上所述,虽然 Vue 3 可以继续使用 Vue 2 的生命周期方法,但推荐使用 Vue 3 组合式 API 的生命周期钩子以充分利用新的特性和更好的开发体验。

六、 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 在性能、开发体验和功能方面都有了很大的提升,为开发者提供了更强大的工具来构建高效、可维护的前端应用。

相关推荐
雪碧聊技术5 分钟前
01-Ajax入门与axios使用、URL知识
前端·javascript·ajax·url·axios库
adminIvan10 分钟前
Element plus使用menu时候如何在折叠时候隐藏掉组件自带的小箭头
前端·javascript·vue.js
会发光的猪。29 分钟前
【 ElementUI 组件Steps 步骤条使用新手详细教程】
前端·javascript·vue.js·elementui·前端框架
我家媳妇儿萌哒哒30 分钟前
el-table合并单元格之后,再进行隔行换色的且覆盖表格行鼠标移入的背景色的实现
前端·javascript·elementui
baiduguoyun1 小时前
react的import 导入语句中的特殊符号
前端·react.js
前端青山1 小时前
webpack指南
开发语言·前端·javascript·webpack·前端框架
NiNg_1_2341 小时前
ECharts实现数据可视化入门详解
前端·信息可视化·echarts
励志前端小黑哥2 小时前
有了Miniconda,再也不用担心nodejs、python、go的版本问题了
前端·python
喵叔哟2 小时前
重构代码之取消临时字段
java·前端·重构
还是大剑师兰特2 小时前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts