Code前端首页关于Code前端联系我们

1.最基础的数组遍历,v for咋写?

terry 2周前 (06-23) 阅读数 47 #Vue
文章标签 for 数组遍历

p>前端开发中,列表渲染是再常见不过的需求了——从商品列表到评论区,从导航菜单到表格数据,都得把一组数据循环展示出来,Vue2里的v - for就是干这个事儿的“大杀器”,但刚接触的时候,不少同学会纠结“咋遍历数组和对象?key到底有啥用?和v - if一起用咋报错?”这些问题,今天咱就用问答形式,把v - for的常见用法、坑点、优化思路一次性讲明白~

Vue2里用v - for遍历数组,语法是v - for="(item, index) in 数组数据" ,item对应数组里每个元素,index是从0开始的下标,举个简单例子,渲染待办事项列表:

<ul>
  <li v - for="(todo, index) in todoList" :key="index">
    {{ index + 1 }}. {{ todo.title }}
  </li>
</ul>
<script>
export default {
  data() {
    return {
      todoList: [
        { title: '买咖啡' },
        { title: '写代码' },
        { title: '遛狗' }
      ]
    }
  }
}
</script>

这里只要todoList的数据变了(比如用push新增一项),Vue会自动更新DOM,不过得记着,v - for要配合:key用(后面专门讲key的作用),先把基础写法逻辑吃透~

遍历对象的时候,v - for咋处理?

遍历对象时,v - for语法是v - for="(value, key, index) in 对象数据" ,value是对象的属性值,key是属性名,index是遍历顺序(按Object.keys的顺序来,Vue2里是这么处理的),比如展示用户信息:

<div v - for="(val, k, i) in userInfo" :key="k">
  第{{ i + 1 }}个属性:{{ k }} → {{ val }}
</div>
<script>
export default {
  data() {
    return {
      userInfo: {
        name: '小明',
        age: 25,
        job: '前端开发'
      }
    }
  }
}
</script>

渲染后会生成三行,分别对应name、age、job的键值对,但要注意,对象新增属性时,Vue默认监听不到变化(后面讲响应式更新问题),得用Vue.set才能让视图跟着变~

v - for和v - if一起用,为啥容易踩坑?

Vue2里v - for的优先级比v - if高!也就是说,同一个元素同时写这俩指令时,会先循环每个元素,再对每个元素做v - if判断,比如想“只显示已完成的todo”,要是这么写:

<li v - for="todo in todoList" v - if="todo.done" :key="todo.id">
  {{ todo.title }}
</li>

假设todoList有10条数据,就会先循环10次,再逐个判断是否“done”,性能浪费特别严重(列表长的时候更明显)。

正确做法是把v - if提到循环外面,比如用<template>包一层,或者先在JS里过滤数组:

<!-- 用template包一层,先判断再循环 -->
<template v - if="todoList.length">
  <li v - for="todo in todoList" v - if="todo.done" :key="todo.id">
    {{ todo.title }}
  </li>
</template>
<!-- 更高效:用计算属性先过滤 -->
<script>
export default {
  computed: {
    doneTodos() {
      return this.todoList.filter(todo => todo.done)
    }
  }
}
</script>
<template>
  <li v - for="todo in doneTodos" :key="todo.id">
    {{ todo.title }}
  </li>
</template>

这样就能避免不必要的循环,性能友好很多~

v - for里的key必须加吗?有啥用?

key必须加! 但很多新手爱用index当key,这其实埋了不少坑。

key的作用是给Vue的虚拟DOM做“身份标识”,列表数据变化时,Vue靠key判断哪些元素是新增、删除、修改的,从而高效更新DOM(也就是diff算法里的“就地复用”逻辑)。

举个🌰:如果用index当key,列表增删时index会变,Vue就会认错元素,todoList是[{id:1, title:'a'}, {id:2, title:'b'}],用index当key渲染后,key是0、1,要是删除第一个元素,新列表变成[{id:2, title:'b'}],此时key变成0,Vue会误以为“原来key=1的元素被删了,key=0的元素是原来的id=2”,但其实内容没变化,这时候如果元素里有输入框这类可交互组件,就会出现“数据和视图不匹配”的bug(比如输入框内容被错误复用)。

所以正确做法是用数据里的唯一标识当key,比如todo的id:

<li v - for="todo in todoList" :key="todo.id">
  {{ todo.title }}
  <input type="text" placeholder="备注">
</li>

这样就算列表增删,每个元素的key唯一且稳定,Vue能准确识别,避免DOM复用出错~

想做嵌套循环,v - for咋嵌套?

嵌套循环在表格、多级菜单里很常见,思路是外层v - for循环父数据,内层v - for循环子数据,比如渲染“周课程表”,外层是星期,内层是每天的课程:

<table>
  <tr v - for="(week, weekIndex) in weekCourses" :key="weekIndex">
    <td>{{ week.name }}</td>
    <td v - for="(course, courseIndex) in week.courses" :key="courseIndex">
      {{ course.name }}({{ course.time }})
    </td>
  </tr>
</table>
<script>
export default {
  data() {
    return {
      weekCourses: [
        {
          name: '周一',
          courses: [
            { name: '数学', time: '09:00' },
            { name: '英语', time: '14:00' }
          ]
        },
        {
          name: '周二',
          courses: [
            { name: '语文', time: '10:00' },
            { name: '体育', time: '15:00' }
          ]
        }
      ]
    }
  }
}
</script>

外层循环weekCourses数组(每个元素是某天的课程包),内层循环每个week里的courses数组,注意每层循环都得加key,而且key要保证当前层级唯一~

列表数据更新了,v - for咋没自动渲染?

这是因为Vue2的响应式原理有“限制”,数组和对象的更新,不是所有操作都会触发视图更新:

  • 数组:只有调用变异方法(push/pop/shift/unshift/splice/sort/reverse)才会触发更新,如果直接改索引(比如todoList[0] = {title: '新内容'}),Vue监听不到,视图也不会变,这时候得用Vue.set(todoList, 0, {title: '新内容'}) 或者 todoList.splice(0, 1, {title: '新内容'})

  • 对象:直接给对象新增属性(比如userInfo.gender = '男'),Vue也监听不到,得用Vue.set(userInfo, 'gender', '男') 或者替换整个对象(this.userInfo = { ...this.userInfo, gender: '男' })。

举个🌰:想给todoList第一个元素改标题,正确操作得这么写:

// 错误写法:直接改索引,视图不更新
this.todoList[0].title = '买奶茶' 
// 正确写法1:用Vue.set
import Vue from 'vue'
Vue.set(this.todoList, 0, { title: '买奶茶' })
// 正确写法2:用splice
this.todoList.splice(0, 1, { title: '买奶茶' })

理解了Vue2的响应式机制,才能避免“数据改了视图没反应”的尴尬~

v - for能循环渲染组件吗?咋传数据?

必须能!很多场景下,列表里的每个项都是独立组件(比如商品卡片、用户卡片),做法是在父组件用v - for循环数据,把每个数据项传给子组件的props

比如做一个“用户卡片列表”,子组件叫UserCard

<!-- 父组件模板 -->
<user - card 
  v - for="user in userList" 
  :key="user.id" 
  :user - info="user"
></user - card>
<!-- 子组件UserCard -->
<template>
  <div class="card">
    <h3>{{ userInfo.name }}</h3>
    <p>年龄:{{ userInfo.age }}</p>
    <p>职业:{{ userInfo.job }}</p>
  </div>
</template>
<script>
export default {
  props: {
    userInfo: {
      type: Object,
      required: true
    }
  }
}
</script>

父组件里userList是用户数据数组,每个user传给子组件的userInfo props,这样每个子组件都能独立展示数据,还能在子组件里处理点击事件等交互,实现组件化的列表渲染~

说到底,v - for是Vue2列表渲染的核心,把数组/对象遍历、key的作用、和v - if的配合、响应式更新这些知识点吃透,实际项目里才能少踩坑,要是你还有其他细节问题,评论区随时喊我唠~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门