WangShuXian6 / blog

FE-BLOG
https://wangshuxian6.github.io/blog/
MIT License
46 stars 10 forks source link

Vue3 代码片段 #191

Open WangShuXian6 opened 5 months ago

WangShuXian6 commented 5 months ago

Vue3

VSCode 插件

Vue - Official 【原 volar】 https://marketplace.visualstudio.com/items?itemName=Vue.volar 禁止使用 vetur,已废弃。

WangShuXian6 commented 5 months ago

watchEffect(async (onCleanup) => {
  const { response, cancel } = doAsyncWork(id.value)
  // `cancel` 会在 `id` 更改时调用
  // 以便取消之前
  // 未完成的请求
  onCleanup(cancel)
  data.value = await response
})

这段代码是一个 watchEffect 的使用示例,通常在 Vue.js 或类似的响应式框架中使用。watchEffect 用于创建一个副作用,它会自动追踪其依赖并在依赖改变时重新执行。让我们逐步分析并补全这段代码:

代码解析

  1. watchEffect 函数

    • watchEffect 是用于自动监测其中包含的响应式引用(如 id.value)的变化,并在变化时重新执行这个副作用函数。
    • id.value 改变时,整个函数会重新执行。
  2. 异步函数 doAsyncWork

    • doAsyncWork 是一个异步函数,根据 id.value 进行某些异步操作(如 API 请求),并返回一个包含响应和取消函数的对象。
    • response 是一个异步得到的响应。
    • cancel 是一个函数,用于取消当前的异步操作。
  3. onCleanup 函数

    • 这是 watchEffect 提供的一个函数,用于注册清理逻辑,这里的清理逻辑是调用 cancel 函数。
    • watchEffect 的依赖发生变化并重新执行前,onCleanup 注册的函数会被调用,用于清理或取消之前的副作用。
  4. 数据更新

    • data.value = await response 用于更新某个响应式数据 data.value,等待异步响应完成。

补全代码

为了完善这段代码,我们需要定义 doAsyncWork 函数,假设它是发起 HTTP 请求的函数。下面是如何实现它,包括取消逻辑:

async function doAsyncWork(id) {
  let abortController = new AbortController();

  try {
    let response = await fetch(`https://api.example.com/data/${id}`, { signal: abortController.signal });
    let data = await response.json();
    return { response: data, cancel: () => abortController.abort() };
  } catch (error) {
    console.error('Request failed:', error);
    return { response: null, cancel: () => {} };
  }
}

完整的 Vue 代码示例

结合 doAsyncWork 函数,以下是 Vue 组件中可能的实现:

import { watchEffect, ref } from 'vue';

export default {
  setup() {
    const id = ref(1);
    const data = ref(null);

    watchEffect(async (onCleanup) => {
      const { response, cancel } = doAsyncWork(id.value);
      onCleanup(cancel);
      data.value = await response;
    });

    return {
      id,
      data
    };
  }
}

在这个例子中,每次 id 更改时,都会取消前一个请求(如果尚未完成),然后基于新的 id 发起新的请求。这样可以避免无效请求的累积和潜在的内存泄漏。

onCleanup

在 Vue.js 中,onCleanup 不是 watchEffect 的直接参数,而是在 watchEffect 函数的回调中提供的一个函数,用于注册清理逻辑。这个机制是为了管理副作用的生命周期,确保在副作用重新触发或组件销毁时能够进行适当的清理。

原理解释

  1. watchEffect 的作用watchEffect 用来自动追踪其函数体内部的响应式引用,并在这些响应式数据发生变化时重新执行。这种自动追踪使得 Vue 组件能够在数据更新时自动刷新相关的视图或执行相关的逻辑。

  2. 清理函数(onCleanup)

    • 在每次 watchEffect 函数体内的代码重新执行前,如果之前的执行中注册了清理函数,Vue 将调用这些清理函数。这是通过 onCleanup 完成的。
    • onCleanup 函数接收一个函数作为参数,该函数就是你希望在当前副作用停止之前执行的清理逻辑。

应用场景

示例

以下是一个使用 onCleanup 来取消网络请求的例子:

import { watchEffect, ref } from 'vue';

export default {
  setup() {
    const id = ref(0);
    const data = ref(null);

    watchEffect((onCleanup) => {
      const abortController = new AbortController();
      fetch(`https://api.example.com/resource/${id.value}`, {
        signal: abortController.signal
      })
        .then(response => response.json())
        .then(json => {
          data.value = json;
        })
        .catch(error => console.error('Fetch error:', error));

      // 注册清理函数
      onCleanup(() => {
        abortController.abort();
      });
    });

    return { id, data };
  }
};

在这个例子中,每次 id 值变化时,前一个请求(如果尚未完成)将通过 abortController.abort() 被取消,避免不必要的网络请求和可能的状态冲突。这种模式对于确保资源得到正确管理和应用保持响应性非常重要。

WangShuXian6 commented 5 months ago

轮播图

仅适配小程序

src\components\Carousel.vue


<template>
<view class="carousel-container">
<swiper
:indicator-dots="true"
:autoplay="true"
:interval="3000"
:duration="500"
@change="onCarouselChange"

<swiper-item
v-for="(item, index) in images"
:key="index"
class="swiper-item"

<view class="image-container">
<image :src="item.url" mode="aspectFill" class="image" />
</view>
</swiper-item>
</swiper>
</view>
</template>

>`src\components\useCarousel.ts`
```ts
import { ref } from 'vue';

export default function useCarousel() {
  const current = ref(0);

  const onCarouselChange = (event: any) => {
    current.value = event.detail.current;
  };

  return {
    current,
    onCarouselChange,
  };
}

使用组件

src\pages\tabbar\home.vue


<template>
<view class="content">
<view class="carousel-container">
<image class="carousel-background" />
<view class="top-margin"></view>
<carousel :images="images"></carousel>
</view>
</view>
</template>
WangShuXian6 commented 5 months ago

process 识别

pnpm i --save-dev @types/node

tsconfig.json 添加 "types": ["node"]

{
  "extends": "@vue/tsconfig/tsconfig.json",
  "compilerOptions": {
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "lib": ["esnext", "dom"],
    "types": ["@dcloudio/types","node"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}