Vue.js --- Vue3中其他组合式API

1. 前言

组合式API可以让我们更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。组合式 API 提供了更灵活的方式来组织和复用代码。在选项式 API 中,组件的逻辑是按照生命周期钩子、计算属性、方法等进行组织的,这在某些情况下可能会导致功能之间的耦合。而组合式 API 允许将相关的功能组织到一个或多个"组合函数"(composables)中,并在不同组件中复用。

2. 浅层次响应

2.1 shallowReactive

与reactive不同的是,shallowReactive只会对对象的第一层属性进行响应式处理,而不会递归地处理深层的嵌套属性。也就是说,只有顶层属性会被代理,深层次的对象则不会被代理

javascript 复制代码
import { shallowReactive } from 'vue';

const state = shallowReactive({
  a: 1,
  b: { x: 10, y: 20 }
});

state.a = 2;  // 响应式,修改会触发视图更新
state.b.x = 30;  // 非响应式,修改不会触发视图更新

2.2 readonly

用于创建一个只读的响应式对象,通过 readonly 创建的对象,所有属性都变成了只读的,即不能对该对象进行修改。如果尝试修改它的属性,Vue 会在开发环境中发出警告,但不会抛出错误。

javascript 复制代码
import { readonly } from 'vue';

const state = readonly({
  a: 1,
  b: { x: 10, y: 20 }
});

state.a = 2;  // 会发出警告,不能修改属性
state.b.x = 30;  // 会发出警告,不能修改嵌套属性

2.3 shallowReadonly

与readonly类似,但可以看出多了一个shallow,也只会局限于第一层属性,而不会递归处理、

更深层属性仍可以被修改,只有顶层属性是只读的

javascript 复制代码
import { shallowReadonly } from 'vue';

const state = shallowReadonly({
  a: 1,
  b: { x: 10, y: 20 }
});

state.a = 2;  // 会发出警告,不能修改顶层属性
state.b.x = 30;  // 不会发出警告,可以修改嵌套属性

3. 数据代理

3.1 toRaw

用来获取响应式对象的原始非响应式版本,当你在 Vue 中创建一个响应式对象时,Vue 会为该对象添加代理,进行数据的响应式追踪。而有时你可能需要访问该对象的原始数据,toRaw 就是用来实现这个功能的。

简单来讲就是储存原始的响应式对象的数据,随便我怎么改变响应式数据,toRaw的对象都是返回原始数据

javascript 复制代码
import { reactive, toRaw } from 'vue';

const state = reactive({
  a: 1,
  b: { x: 10, y: 20 }
});

const rawState = toRaw(state);

state.a = 2;  // 修改响应式对象
console.log(rawState.a);  // 输出 1,原始数据不受影响

3.2 markRaw

用来标记某个对象不需要被 Vue 代理 。当你想让某个对象避免成为响应式对象时,可以使用 markRaw。该对象会被 Vue 视为普通的非响应式对象,Vue 不会为其创建代理,也不会进行响应式追踪。

javascript 复制代码
import { markRaw } from 'vue';

const rawObject = markRaw({
  a: 1,
  b: { x: 10, y: 20 }
});

console.log(rawObject);  // 不会被 Vue 代理,保持原始状态

4. 自定义响应 customRef

4.1 声明

customRef是一个允许开发者自定义响应式引用 的 API。它使你能够控制响应式对象的 getter 和 setter 行为,提供了更灵活的方式来处理响应式数据。与 Vue 内置的 ref 不同,customRef 允许你定义如何在响应式更新过程中处理数据。

通过设置getter去获取数据,setter去设置数据

声明

javascript 复制代码
import { customRef } from 'vue';

export default {
  setup() {
    const value = customRef((track, trigger) => {
      let internalValue = 0;

      return {
        get() {
          track();  // 触发依赖追踪
          return internalValue;
        },
        set(newValue) {
          if (Math.abs(newValue - internalValue) > 5) {  // 设置条件
            internalValue = newValue;
            trigger();  // 触发视图更新
          }
        }
      };
    });

    return {
      value
    };
  }
};

track与trigger是由Vue传入的内部函数,该函数返回一个包含get,set的对象。

track用于追踪依赖,可以理解为找到目标数据

trigger用于在数据更新时触发视图更新

4.2 调用

想要调用或者修改customRef对象中的数值,需要使用后缀.value的方式

javascript 复制代码
value.value= 10;

例子:

javascript 复制代码
<template>
  <h1>{{value}}</h1>
  <button @click="changeValue">点我改变数值</button>
</template>

<style>

</style>

<script>
  import {customRef} from 'vue'
  export default {
    setup() {
      let sum = 0;

      const value = customRef((track,trigger) => {
        let interValue = 0;
        return {
          get() {
            track();
            return interValue;
          },
          set(newValue) {
            if (newValue > interValue) {
              interValue = newValue;
              trigger();
            }
          }
        }
      })

      function changeValue() {
        value.value = 50;
      }

      return {sum,value,changeValue}
    }
  }
</script>

5. 数据传递 provide与inject

provide: 在父组件中使用,目的是将数据提供给后代组件。它将某些数据提供到组件树中,所有嵌套的子组件(不论是直接子组件还是间接子组件)都可以通过 inject 来访问这些数据。

inject: 在子组件中使用,用来接收父组件通过 provide 提供的数据。inject 使得子组件可以访问到父组件提供的特定数据,而不需要通过逐层的 props 传递。

相比以往的props传参,vuex定义全局参数,这样更加的方便快捷

父组件提供数据

javascript 复制代码
import {provide} from 'vue'
export default{
    setup(){
        provide('myValue',''HelloWorld);
    }
}

结构体为(参数名,参数内容)

子组件接受数据

inject后直接接受参数名即可

javascript 复制代码
import {inject} from 'vue'

export default()
{
    setup(){
        const injectedValue = inject('myValue')
        return {injectedValue}
    }
}

6. 响应式数据的判断

|--------------|---------------------------|
| isRef() | 判断是否为响应数据 |
| isReactive() | 判断是否为响应对象 |
| isReadonly() | 判断是否为只读属性 |
| isProxy() | 判断是否为响应式系统,包括ref,reactive |

7. 渲染DOM组件 - Teleport组件

Teleport是一个非常实用的组件,允许将子组件的内容渲染到DOM中不同的位置,而不依赖于父组件的嵌套结构。对于管理模态框,弹出层,工具提示,通知等UI元素非常有用,特别是当这些元素需要在DOM的不同位置进行渲染时,避免了许多的嵌套和复杂的样式问题

例如,消息通知栏常常需要放置在顶部,但又受到某一子组件的控制,通过Teleport组件控制标签位置到指定目标容器

格式:

javascript 复制代码
<teleport to="body">
</teleport>

to指向目标容器

示例:模拟弹窗

javascript 复制代码
<template>
  <div>
    <h1>Vue3 Teleport 示例</h1>
    <button @click="closeModel">点我</button>
    <teleport to="body">
      <div class="model" v-if="controller">
        <p>这是一个模板!</p>
        <button @click="closeModel">关闭</button>
      </div>
    </teleport>
  </div>
</template>

<style>
  .model{
    position:fixed;
    top:50%;
    left:50%;
    background-color:yellow;
    border-radius:8px;
  }
</style>

<script>
  export default {
    data() {
      return {
        controller:false
      }
    },
    methods: {
      closeModel() {
        this.controller = !this.controller
      }
    }
  }
</script>

8. 异步组件

8.1 异步加载组件

让我们先来了解异步加载组件

它允许我们根据需要加载和渲染组件,而不是在应用加载时一次性加载所有组件。这样可以显著提高应用的性能,尤其是在大型应用中,避免一次性加载所有的 JavaScript 代码和组件。

javascript 复制代码
import { defineAsyncComponent } from 'vue';

export default {
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./AsyncComponent.vue') // 异步加载组件
    )
  }
}

在defineAsyncComponent方法中传入一个函数

suspense组件用于处理异步组件的加载和显示一个加载状态。它为开发者提供了一种优雅的方式来处理异步数据加载的状态,特别是在处理组件加载、API 请求或其他需要等待的操作时,Suspense 让应用能够在等待数据或资源时优雅地过渡。

在vue中还提供了异步组件的加载状态,加载失败和超时处理的功能

javascript 复制代码
const AsyncComponent = () => ({
  // 需要加载的组件 (should be a promise)
  component: import('./components/AsyncComponent.vue'),
  
  // 加载中时的组件
  loading: LoadingComponent,
  
  // 加载失败时的组件
  error: ErrorComponent,
  
  // 超过时间后显示的组件
  timeout: 3000
});

8.2 suspense结构

default插槽:用于放置异步组件,vue会等待其最终的加载完成

fallback插槽:当异步组件正在加载时,会显示fallback插槽中的内容,通常是文字或者加载动画

javascript 复制代码
<template>
  <Suspense>
    <!-- 异步组件 -->
    <template #default>
      <AsyncComponent />
    </template>

    <!-- 加载时显示的内容 -->
    <template #fallback>
      <p>加载中...</p>
    </template>
  </Suspense>
</template>

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

export default {
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./AsyncComponent.vue') // 异步加载组件
    )
  }
}
</script>
相关推荐
陈随易5 分钟前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding9 分钟前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马15 分钟前
前沿视界
前端
kyriewen20 分钟前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易37 分钟前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒44 分钟前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端
程序员大阳1 小时前
HTML+CSS+JS对话式实战(9)-项目总结与问题分析
javascript·css·html·实战·项目总结
Flynt2 小时前
别写拖拽行为,只声明"能拖到哪":UIST 最佳论文的拖拽方案我实测了
前端·svg·preact
Moment3 小时前
代码都能让 Agent 写了,我们为什么还要学前端?
前端·后端·面试
Hilaku3 小时前
MCP 协议会成为前端 AI 工程的标准接口吗?
前端·javascript·程序员