2023-09-08 15:14:45 +08:00

11 KiB
Raw Blame History

响应式

在Vue 3中响应式是通过reactive函数和ref函数实现的。reactive函数用于创建一个响应式对象,而ref函数用于创建一个包装对象,将基本类型的值转换为响应式对象。

具体来说,reactive函数接收一个普通对象作为参数,并返回一个响应式对象,如下所示:

import { reactive } from 'vue';

const state = reactive({
  count: 0
});

在这个例子中,我们使用reactive函数创建了一个响应式对象state,它包含一个属性count初始值为0。

在组件中,你可以使用setup函数来访问响应式对象,如下所示:

<template>
  <div>
    <p>Count: {{ state.count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

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

export default {
  setup() {
    const state = reactive({
      count: 0
    });

    const increment = () => {
      state.count++;
    };

    return {
      state,
      increment
    };
  }
}
</script>

在这个例子中,我们在setup函数中访问了响应式对象state,并将它绑定到模板中。当点击按钮时,我们调用increment函数来增加state.count的值。由于state是响应式对象,当state.count的值发生变化时,模板中的内容也会自动更新。

除了reactive函数外Vue 3还提供了ref函数,用于将基本类型的值转换为响应式对象。例如,你可以使用ref函数来创建一个响应式的计数器,如下所示:

import { ref } from 'vue';

const count = ref(0);

在这个例子中,我们使用ref函数创建了一个响应式对象count它的初始值为0。

在组件中,你可以使用setup函数来访问响应式对象,如下所示:

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

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

export default {
  setup() {
    const count = ref(0);

    const increment = () => {
      count.value++;
    };

    return {
      count,
      increment
    };
  }
}
</script>

在这个例子中,我们在setup函数中访问了响应式对象count,并将它绑定到模板中。当点击按钮时,我们调用increment函数来增加count.value的值。由于count是响应式对象,当count.value的值发生变化时,模板中的内容也会自动更新。

总之Vue 3中的响应式是通过reactive函数和ref函数实现的。reactive函数用于创建一个响应式对象,而ref函数用于将基本类型的值转换为响应式对象。你可以在setup函数中访问响应式对象,并将它们绑定到模板中。

依赖注入

Vue 3中的依赖注入是通过provide和inject实现的。provide和inject是一对API用于在父组件和子组件之间共享数据。具体来说provide用于在父组件中提供数据而inject用于在子组件中注入数据。

在父组件中你可以使用provide来提供数据如下所示

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

export default {
  setup() {
    const data = 'Hello, World!';
    provide('data', data);
  }
}
</script>

在子组件中你可以使用inject来注入数据如下所示

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

export default {
  setup() {
    const data = inject('data');
    console.log(data); // 输出Hello, World!
  }
}
</script>

在这个例子中,父组件提供了一个名为'data'的数据子组件通过inject来注入这个数据。注意子组件中的inject必须在setup函数中使用而且必须在模板中使用才能生效。

总之Vue 3中的依赖注入是通过provide和inject实现的它可以帮助你在父组件和子组件之间共享数据。

插槽

默认插槽

Vue 3中的插槽是通过<slot>元素实现的。插槽允许你在组件中定义一些占位符,然后在使用组件时填充这些占位符。具体来说,你可以在组件中使用<slot>元素来定义插槽,如下所示:

<template>
  <div>
    <h2>{{ title }}</h2>
    <slot></slot>
  </div>
</template>

在这个例子中,我们定义了一个名为title的属性和一个插槽。插槽使用了<slot>元素,它表示这里是一个插槽占位符,可以在使用组件时填充内容。

在使用组件时,你可以在组件标签中填充内容,如下所示:

<template>
  <div>
    <my-component title="Hello, World!">
      <p>This is the content of the slot.</p>
    </my-component>
  </div>
</template>

在这个例子中,我们使用了<my-component>组件,并在组件标签中填充了一个<p>元素。这个<p>元素就是填充了组件中定义的插槽。

除了默认插槽外Vue 3还支持具名插槽和作用域插槽。具名插槽允许你定义多个插槽并在使用组件时指定要填充哪个插槽。作用域插槽允许你将数据传递给插槽内容以便在插槽中使用。

总之Vue 3中的插槽是通过<slot>元素实现的它允许你在组件中定义占位符并在使用组件时填充内容。除了默认插槽外Vue 3还支持具名插槽和作用域插槽。

具名插槽

在Vue 3中具名插槽允许你定义多个插槽并在使用组件时指定要填充哪个插槽。具名插槽可以通过在<slot>元素上添加name属性来定义,如下所示:

<template>
  <div>
    <slot name="header"></slot>
    <slot></slot>
    <slot name="footer"></slot>
  </div>
</template>

在这个例子中,我们定义了三个插槽,其中第一个和第三个是具名插槽,分别使用了name属性来定义。第二个插槽没有使用name属性,它是默认插槽。

在使用组件时,你可以使用v-slot指令来指定要填充哪个插槽,如下所示:

<template>
  <div>
    <my-component>
      <template v-slot:header>
        <h1>This is the header slot.</h1>
      </template>
      <p>This is the default slot.</p>
      <template v-slot:footer>
        <p>This is the footer slot.</p>
      </template>
    </my-component>
  </div>
</template>

在这个例子中,我们使用了<my-component>组件,并在组件标签中填充了三个插槽。使用v-slot指令来指定要填充哪个插槽,语法为v-slot:name,其中name是插槽的名称。

除了v-slot指令外Vue 3还支持另一种简写语法#,如下所示:

<template>
  <div>
    <my-component>
      <template #header>
        <h1>This is the header slot.</h1>
      </template>
      <p>This is the default slot.</p>
      <template #footer>
        <p>This is the footer slot.</p>
      </template>
    </my-component>
  </div>
</template>

在这个例子中,我们使用了#来代替v-slot指令,语法更加简洁。

总之Vue 3中的具名插槽允许你定义多个插槽并在使用组件时指定要填充哪个插槽。你可以使用v-slot指令或#来指定要填充哪个插槽。

作用域插槽

在Vue 3中作用域插槽允许你将数据传递给插槽内容以便在插槽中使用。作用域插槽可以通过在<slot>元素上添加v-bind指令来定义,如下所示:

<template>
  <div>
    <slot v-bind:user="user"></slot>
  </div>
</template>

在这个例子中,我们定义了一个作用域插槽,并使用了v-bind指令来将user数据传递给插槽内容。

在使用组件时,你可以在插槽标签中使用v-slot指令来定义插槽,并在插槽内容中使用传递的数据,如下所示:

<template>
  <div>
    <my-component>
      <template v-slot:default="slotProps">
        <p>{{ slotProps.user.name }}</p>
        <p>{{ slotProps.user.age }}</p>
      </template>
    </my-component>
  </div>
</template>

在这个例子中,我们使用了<my-component>组件,并在组件标签中填充了一个作用域插槽。使用v-slot指令来定义插槽,并使用default作为插槽的名称。在插槽内容中,我们可以通过slotProps来访问传递的数据。

除了v-slot指令外Vue 3还支持另一种简写语法#,如下所示:

<template>
  <div>
    <my-component>
      <template #default="slotProps">
        <p>{{ slotProps.user.name }}</p>
        <p>{{ slotProps.user.age }}</p>
      </template>
    </my-component>
  </div>
</template>

在这个例子中,我们使用了#来代替v-slot指令,语法更加简洁。

总之Vue 3中的作用域插槽允许你将数据传递给插槽内容以便在插槽中使用。你可以在<slot>元素上使用v-bind指令来定义作用域插槽,并在插槽标签中使用v-slot指令或#来定义插槽,并在插槽内容中使用传递的数据。

比较重要的知识点总结

对vue.js的响应式数据的理解

Vue 2.x

对象类型:通过object.defineProperty()对属性的读取、修改进行拦截(数据劫持)

数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)

图片

  • 当你把一个普通的JavaScript对象传入Vue实例作为data选项Vue将遍历此对象所有的property并使用Object.defineProperty把这些property全部转为getter/setter

    • Object.defineProperty是ES5中一个无法shim的特性这也就是Vue不支持IE8以及更低版本浏览器的原因。
  • 当使用这些数据属性是会进行依赖收集收集到当前组件的watcher

    • 每个组件都对应一个watcher实例它会在组件渲染的过程中把“接触”过的数据记录为依赖之后当依赖项的setter触发时会通知watcher从而使它关联的组件重新渲染

存在问题

  • 新增属性、删除属性,界面不会更新
  • 直接通过下标修改数组,界面不会自动更新

Vue 3.x

通过Proxy代理:拦截对象中任意属性的变化,包括:属性值的读写,属性的增加,属性的删除等。

通过Reffect反射:对源对象的属性进行操作

Proxy是 ECMAScript 6 中新增的属性。

Proxy对象用于创建一个对象的代理从而实现基本操作的拦截和自定义如属性查找、赋值、枚举、函数调用等

被Proxy代理虚拟化的对象。它常被作为代理得存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量保持不变的语义

语法:

const p = new Proxy(target, handler)

参数:

target

要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler

一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。