百科狗-知识改变命运!
--

列表渲染 - v-for - vue 基础

乐乐1年前 (2023-11-21)阅读数 45#技术干货
文章标签数组

列表渲染

v-for

遍历数组

我们可以用v-for指令基于一个数组来渲染一个列表。v-for指令需要使用iteminitems形式的特殊语法,其中items是源数据数组,而item是迭代项的别名。

// js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
// template
  • {{ item.message }}
  • v-for块中,我们可以访问所有父作用域的 property。v-for也支持使用可选的第二个参数,表示当前项的位置索引

    const parentMessage = ref('Parent')
    const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
    
  • {{ parentMessage }} - {{ index }} - {{ item.message }}
  • v-for变量的作用域和下面的 JavaScript 代码很类似:

    const parentMessage = 'Parent'
    const items = [
      /* ... */
    ]
    
    items.forEach((item, index) => {
      // 可以访问外层的 `parentMessage`
      // 而 `item` 和 `index` 只在这个作用域可用
      console.log(parentMessage, item.message, index)
    })
    

    注意v-for是如何对应forEach回调的函数签名的。


    实际上,你也可以在定义v-for的变量别名时,使用解构,和解构函数参数类似:

  • {{ message }}
  • {{ message }} {{ index }}
  • 列表渲染 - v-for - vue 基础


    对于嵌套多层的v-for,作用域的工作方式和函数的作用域很类似。每个v-for作用域都可以访问到父级作用域

  • {{ item.message }} {{ childItem }}

  • 你也可以用of替代in作为分隔符,这也和 JavaScript 的迭代器语法非常相似:


    遍历对象

    你也可以用v-for来遍历一个对象的 property。

    const myObject = reactive({
      title: '如何在 Vue 中渲染列表',
      author: '王小明',
      publishedAt: '2016-04-10'
    })
    
    • {{ value }}

    你也可以提供第二个的参数为property 名称(例如key):

  • {{ key }}: {{ value }}
  • 第三个参数表示位置索引

  • {{ index }}. {{ key }}: {{ value }}

  • 当遍历一个对象时,顺序是依据Object.keys()的枚举顺序,由于不同的 JavaScript 引擎可能会有不同的实现,所以可能会导致顺序不一致。


    遍历整数

    可以直接传给v-for一个整数值。在这种用例中,将会将该模板基于1...n的取值范围重复多次。

    {{ n }}

    渲染结果:

    12345678910

    注意此处n的初值是从1开始而非0


    上的 v-for

    与模板上的v-if类似,你也可以在标签上使用v-for来渲染包含多个元素的一个块。例如:

    • {{ item.msg }}


    v-for 与 v-if

    同时使用v-ifv-for是不推荐的,因为这样二者的优先级不明显。

    当它们同时存在于一个节点上时,v-ifv-for的优先级更高。这意味着v-if的条件将无法访问到v-for作用域内定义的变量别名:

  • {{ todo.name }}
  • 在外新包裹一层再在其上使用v-for可以解决这个问题(这也更加明显易读):

     
  • {{ todo.name }}

  • 通过 key 管理状态

    当 Vue 更新一个v-for渲染的列表时,默认情况下使用的是“原地修补”的策略。如果数据项的顺序发生了改变,Vue 不是通过移动 DOM 元素来匹配条目的顺序,而是在适当的位置对每个元素进行修补,确保它们在原本指定的索引位置上渲染。默认模式是高效的,但只适用于列表渲染输出不依赖子组件状态或者临时 DOM 状态,例如表单输入值。

    为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个项目提供一个唯一的key attribute:

    当你使用时,key应该被放置在这个容器上:

     
  • {{ todo.name }}
  • key在这里是一个通过v-bind绑定的特殊 attribute。请不要和在v-for中使用对象里所提到的对象属性的key相混淆了。

    推荐在任何可行的时候为v-for时提供key attribute,除非所迭代的 DOM 内容非常简单(例如:不包含组件或有状态的 DOM 元素),或者有意依赖默认行为来获得性能增益。

    key绑定的值期望是一个基础类型的值,例如字符串或number类型。不要用对象作为v-for的 key。


    组件上使用 v-for

    这一小节假设你已了解组件的相关知识,或者你也可以先跳过这里,之后再回来看。

    可以直接在组件上使用v-for,和其他任何一般的元素没有区别(别忘记提供一个key):

    但是,这不会自动将任何数据传递给组件,因为组件有自己独立的作用域。为了将迭代后的数据传递到组件中,我们还是应该使用props:

    不自动将item注入组件的原因是,这会使组件与v-for的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下可重用。


    数组变化侦测

    变更方法

    变更方法,会变更原始数组。Vue 能够侦听响应式数组的变更方法,并在它们被调用时,触发相关的视图更新。这些变更方法包括:

    • push():向数组的末尾添加一个或多个元素,并返回新的长度。
    • pop():删除数组的最后一个元素,并返回最后一个元素。
    • shift():删除数组的第一个元素,并返回第一个元素的值。
    • unshift():向数组的开头添加一个或更多元素,并返回新的长度。
    • sort():对数组的元素进行排序。
    • reverse():颠倒数组中元素的顺序。
    • splice():向/从数组中添加/删除项目,然后返回被删除的项目。
      1. 删除功能:array.splice(index,num)。
        • index:必需。数组元素的下标,必须是数字。使用负数可从数组结尾处规定位置。
        • num:可选。要删除的项目数量。如果设置为 0,则不会删除项目。如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。
      2. 插入功能:array.splice(index,0,item)。
        • index:必需。数组元素的下标,必须是数字。使用负数可从数组结尾处规定位置。
        • 0:必需是 0。表示插入功能。
        • item:必需。规定要添加到数组的新元素。从 index 所指的下标处开始插入。
      3. 替换功能:array.splice(index,num,item)。
        • index:必需。数组元素的下标,必须是数字。使用负数可从数组结尾处规定位置。
        • num:必需。规定应该替换多少元素。必须是正整数。
        • item:必需。规定要添加到数组的新元素。从 index 所指的下标处开始替换。



    非变更方法

    非变更方法,不变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组,触发相关的视图更新

    • filter():创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
    • concat():用于连接两个或多个数组。
    • slice():从已有的数组中返回选定的元素。
    • split():用于把一个字符串分割成字符串数组。
    // `items` 是一个数组的 ref
    items.value = items.value.filter((item) => item.message.match(/Foo/)) 

    你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。


    展示过滤或排序后的结果

    有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组

    const numbers = ref([1, 2, 3, 4, 5])
    
    const evenNumbers = computed(() => {
      return numbers.value.filter((n) => n % 2 === 0)
    })
    
  • {{ n }}
  • 在计算属性不适用的情况下(例如,在嵌套v-for循环中)你可以使用一个方法:

    const sets = ref([
      [1, 2, 3, 4, 5],
      [6, 7, 8, 9, 10]
    ])
    
    function even(numbers) {
      return numbers.filter((number) => number % 2 === 0)
    }
    
    • {{ n }}

    在计算属性中使用reverse()sort()请保持谨慎!这两个方法将改变原始数组,计算函数中不应该这么做。请在调用这些方法之前创建一个原数组的副本:

    // 慎用:
    return numbers.reverse()
    
    // 推荐:
    return [...numbers].reverse()
    

    鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

    免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

    图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)