LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

常见的 Vue.js 开发错误

admin
2024年11月27日 19:54 本文热度 68

简介

Vue.js 为开发人员提供了丰富的功能,既能加快开发速度,又能构建健壮且高性能的应用程序。

尽管这些功能有其优势,但如果使用不当,也可能成为错误的根源,导致开发人员花费大量时间进行调试。错误不仅影响开发效率,还可能导致应用程序性能下降,最终影响 Vue 应用的整体表现。

我们可以从他人的错误中汲取教训,在保证应用程序功能和性能的同时,编写更加简洁的代码。


本文中,我使用 Vite 创建了一个最小化的 Vue 应用程序。你可以从这个仓库克隆该项目。在本地安装依赖后,运行 pnpm i 安装依赖,并启动开发服务器。


场景 1:在 v-for 循环中使用非唯一的 ID

该错误通常在以下两种情况中出现:

  1. 对数组中的元素进行排序。
  2. 循环中的组件具有内部状态。

为便于演示,以下是一个代码片段:

async function fetchData({
  try {
    const dataFromApi = await axios.get(
      "https://dummyjson.com/recipes?page=1&limit=10&skip=10&select=name,image"
    );
    const recipes = dataFromApi.data.recipes as Recipe[];

    favoriteRecipeList.value = [...favoriteRecipeList.value, ...recipes];
    isLoading.value = false;
  } catch (e) {
    isLoading.value = false;
    console.log(e);
  }
}

该函数从源数据获取信息,并填充到本地变量中,然后使用 v-for 循环渲染配方列表,同时考虑到 SingleRecipe 组件有自己的内部状态。


<template>
  <main class="md:min-h-screen md:p-5 p-2">
    <h1 class="text-5xl">Ouch, Mistakes.</h1>

    <section
      v-if="isLoading"
      class="w-full h-72 flex flex-col items-center justify-center"
    >

      <p class="text-3xl">Loading...</p>
    </section>

    <section
      v-auto-animate
      v-else
      class="w-full grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-3 mt-16 relative mb-14"
    >

      <button
        :disabled="!haveRecipes"
        @click="shuffleRecipe"
        class="px-4 py-1.5 absolute -top-16 right-5 bg-green-700 text-white"
      >

        Shuffle
      </button>
      <SingleRecipe
        v-for="(item, index) in favoriteRecipeList"
        :key="index"
        :recipe="item"
      />

    </section>
  </main>
</template>

以下是该示例的结果:

由于我们将数组的索引作为循环的 key,一切看起来正常。当我们点击“洗牌”按钮时,虽然配方的顺序发生了变化,但预期的过渡效果却没有显示。

原因在于,每当 key 值变化时,「Vue 会使用这些 key 来强制重新渲染」。然而,由于我们使用的是数组索引作为 key,即使列表发生变化,索引也不会改变,因此 Vue 没有重新渲染元素,过渡效果也就没有触发。

为了解决这个问题,我们可以使用一个更具唯一性的值作为 key,帮助 Vue 跟踪列表中元素的变化:

 <SingleRecipe
   v-for="item in favoriteRecipeList"
   :key="item.name"
   :recipe="item"
 />

如图所示,过渡效果现在已按预期正常工作。

场景 2:依赖非响应式值

在使用浏览器 API(如本地存储和地理位置)时,开发人员往往需要响应式的功能。但传统的浏览器 API 本身并不具备响应式,因此开发人员可能会误用它们作为计算属性的值。

以下是一个代码示例,演示如何使用 ref 访问视频元素的属性。

<script setup lang="ts">
import { ref, computed } from "vue";
import PlayButton from "@/components/icons/PlayButton.vue";
import PauseButton from "@/components/icons/PauseButton.vue";

const videoPlayer = ref<HTMLVideoElement>();
const playing = computed(() => !videoPlayer.value?.paused);

</script>

我们使用计算属性来跟踪视频的播放状态,并在模板中显示对应的播放/暂停状态。

<template>
  <main class="md:min-h-screen md:p-5 p-2">
    <h1 class="text-5xl">Ouch, Mistakes. - Non reactive dependency.</h1>

    <section class="mt-16 relative">
      <video src="/shrek_meets_donkey.mp4" ref="videoPlayer" class="mx-auto h-96" />
      <div
        v-auto-animate
        class="inline-flex gap-3 absolute top-[48%] right-[46%]"
      >

        <button
          @click="videoPlayer?.play()"
          v-if="playing"
          class="p-2 rounded-md bg-black"
        >

          <PlayButton />
        </button>
        <button
          v-else
          @click="videoPlayer?.pause()"
          class="p-2 rounded-md bg-red-700"
        >

          <PauseButton />
        </button>
      </div>
    </section>
  </main>
</template>

然而,在这种情况下,控制按钮的状态并不是响应式的:

这是因为计算属性依赖了一个非响应式的值。

为了解决这个问题,我们可以使用 Vueuse 库。这个库提供了一系列组合式 API,使浏览器 API 具备响应式特性,避免了重复造轮子的麻烦。

例如,我们可以使用 useMediaControls 这个组合式 API,轻松为媒体控制添加响应式支持:

<template>
  <main class="md:min-h-screen md:p-5 p-2">
    <h1 class="text-5xl">Ouch, Mistakes. - Non reactive dependency.</h1>

    <section class="mt-16 relative">
      <video ref="videoRef" class="mx-auto h-96" />
      <div
        v-auto-animate
        class="inline-flex gap-3 absolute top-[48%] right-[46%]"
      >

        <button
          @click="videoRef?.play()"
          v-if="!videoPlaying"
          class="p-2 rounded-md bg-black"
        >

          <PlayButton />
        </button>
        <button
          v-else
          @click="videoRef?.pause()"
          class="p-2 rounded-md bg-red-700"
        >

          <PauseButton />
        </button>
      </div>
    </section>
  </main>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useMediaControls } from "@vueuse/core";
import PlayButton from "@/components/icons/PlayButton.vue";
import PauseButton from "@/components/icons/PauseButton.vue";

const videoRef = ref();
const { playing: videoPlaying} = useMediaControls(videoRef, {
  src"/shrek_meets_donkey.mp4",
});
</script>

如预期一样,它正常工作,因为 useMediaControls 提供了一个响应式的 ref,可以在模板中用于显示视频的播放状态。

此外,useMediaControls 还提供了其他有用的属性,以便开发者对媒体进行更多控制。

场景 3:替换响应式值

使用 Vue 的响应式 API 时,需要特别小心,避免错误地替换整个对象,从而失去响应性。

以下是一个代码示例,

<template>
  <main class="md:min-h-screen md:p-5 p-2">
    <h1 class="text-5xl">Ouch, Mistakes - Replacing reactive value</h1>

    <section class="mt-16 relative">
      <button
        @click="loadMoreBirds"
        class="px-4 py-1.5 absolute -top-16 right-5 bg-green-700 text-white"
      >

        Add more bird
      </button>
      <h1 class="text-3xl my-3">Swift birds in Europe</h1>
      <pre>{{ arrLength }}</pre>

      <h1 class="text-3xl my-3" v-if="isLoading">Loading...</h1>
      <ul v-else class="list-disc pl-3">
        <li v-for="item in swiftBirdsInEurope" :key="item">{{ item }}</li>
      </ul>
    </section>
  </main>
</template>

<script setup lang="ts">
import { reactive, ref, computed } from "vue";

const isLoading = ref(false);

let swiftBirdsInEurope = reactive([
  "Alpine swift",
  "Chimney swift",
  "Pacific swift",
]);

const arrLength = computed(() => swiftBirdsInEurope.length)

function loadMoreBirds({
  isLoading.value = true;
  swiftBirdsInEurope = [
    "Common swift",
    "Little swift",
    "Pallid swift",
    "White-rumped swift",
  ];
  setTimeout(() => (isLoading.value = false), 2000);
}
</script>

在 loadMoreBirds 函数中更新响应式值为一个新的鸟类列表。使用 Vue 开发工具检查时,虽然值确实更新了,但计算属性似乎没有重新计算。

出现这个问题的原因是我们在用新数组替换响应式值时,断开了与响应式系统的连接。

这是 Vue 响应式 API 的已知限制。响应式 API 无法追踪已替换的对象,导致视图未更新。

为了解决这个问题,我们建议使用 ref 来存储数据。ref 允许数据的可变性,同时保留响应性。它还能正确存储原始值,这是它的一个优势。

总结

不当使用 Vue API 可能会导致意想不到的错误。开发人员需要在特定情况下遵循适当的 API 使用规范,确保代码的响应性和应用的性能。


原文地址:https://medium.com/@dimeji.ogunleye20/common-vuejs-development-mistakes-10877bdc591d


该文章在 2024/11/28 17:41:21 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved