VueJS:`v-for`不渲染元素

Posted

技术标签:

【中文标题】VueJS:`v-for`不渲染元素【英文标题】:VueJS: `v-for` not rendering elements 【发布时间】:2019-12-19 06:57:21 【问题描述】:

我想分享的只是简化版本的相关代码,但我不能。我有一个用 Vue 制作的稍微过度的 todo 应用程序。这是回购的链接:https://github.com/jaiko86/subtasks

待办事项在商店中管理:

export default 
  state: 
    workspaceIds: [], // IDs of workspaces
    tasksById: , // <--- this is the tasks I have
    detachedTask: null,
    focusedTaskId: null,
    currentWorkspaceId: null,
  ,
  ...

在 App.vue 文件中,我有以下 v-for 将运行的计算属性:

  computed: 
    taskIds() 
      const  currentWorkspaceId, tasksById  = this.$store.state;
      if (this.showOnlyLeafSubTasks) 
        return Object.values(tasksById)
          .filter(task => !task.subTaskIds.length)
          .map(task => task.id);
       else if (currentWorkspaceId) 
        return tasksById[currentWorkspaceId].subTaskIds;
      
    ,
  ,

基本上,计算属性只会返回与某些条件相关的任务列表,例如我所在的工作区。每个任务都有一个唯一的 ID,但为了调试,我做了这样每个任务都有task-#格式的ID,并且任务的输入将有它的任务ID作为占位符。

这是App.vue中的模板:

<template>
  <div id="app">
    <!-- This is the top part -->
    <WorkspaceNav /> 

    <!-- this is the for-loop in question -->
    <TaskWrapper v-for="id in taskIds" :key="id" :id="id" :depth="0" />

    <!-- this is the filter that's on the right side -->
    <TaskFilters />
  </div>
</template>

问题是它不会渲染计算属性返回的项目。

我很难理解为什么 vue devtool 和控制台中显示的内容与视图之间存在差异。

这是渲染的视图:

以下是 vue 开发工具中的内容:

这是我在开发工具中选择&lt;App&gt; 组件时控制台中打印的内容,从而可以通过$vm0.taskIds 访问它:

["task-1", "task-2"]

这是我分层打印任务的自定义函数:

> printTree()
task-0
  task-1

  task-2

这里是当前代码相关部分的 DOM:


    <div id="app">
      <div class="workspace-nav">
        ...
      </div>
      <div data-v-76850a4a="" data-v-7ba5bd90="" class="leaf">
        <div data-v-76850a4a="" class="main-task depth-0">
          <!---->
          <div class="progress-indicator">
            <div class="checkmark gray-checkmark"></div>
          </div>
          <input placeholder="task-1" />
        </div>
        <div class="sub-tasks"></div>
      </div>
      <div class="filters">
        ...
      </div>
    </div>

所以很明显,无论我在哪里看,taskIds 都会返回一个包含两个项目的列表,但它只呈现第一个。

【问题讨论】:

计算属性总是应该返回一些值,你在做有条件的,在某些情况下不能返回任何东西 【参考方案1】:

这是一种可能的解释...

在计算属性返回其数组时,该数组仅包含一项。您可以通过多种方式确认这一点。例如尝试将其放入您的模板中:

 taskIds 

该数组随后可能会更改,使其包含两个项目,但如果更改未触发反应系统,则不会发生重新渲染。

最好的猜测是tasksIds 正在返回tasksById[currentWorkspaceId].subTaskIds。这留下了两种可能的可能性。 subTasksIds 不是反应性的,或者它正在以不触发反应性的方式进行修改(例如,通过索引直接修改)。

查看您的商店代码,我没有看到任何明显的后者示例。但是,createTask 中的 this line 看起来确实像前者:

state.tasksById[task.id] = task;

这是将task 添加到(可能)新键下的现有对象。这是反应性警告之一,您不能直接向对象添加新属性:

https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

您需要使用 Vue.set:

Vue.set(state.tasksById, task.id, task);

为了更好地了解发生了什么,请尝试将以下日志添加到 createTask 的末尾:

console.log(state.tasksById);

如果您在控制台中深入研究对象/数组,您应该会看到 Vue 反应性系统的证据。您可能会看到对Observer 的引用。属性将具有 getter 和 setter,您需要单击才能查看属性值。但是,这只会在对象/数组是反应性的情况下发生。您直接添加的任务,没有Vue.set,将在控制台中显示为普通对象/数组。值得花一些时间来了解其中的差异,因为如果您知道要查找什么,它会使调试这些类型的问题变得更加容易。

【讨论】:

使用Vue.set而不是直接修改状态解决了这个问题。

以上是关于VueJS:`v-for`不渲染元素的主要内容,如果未能解决你的问题,请参考以下文章

VueJS - V-for 在数据更新后不会重新渲染,需要刷新页面才能看到更改

更改特定索引而不在 Vuejs 中重新渲染整个数组

Vue3Cli-列表渲染(v-for使用)

为啥条件渲染不适用于 vuejs 中的表单输入

VueJS 不会从组件中重新渲染列表

Vue中使用v-for渲染数据为何要添加key属性?(原理及作用)