vue源码解析——v-if和v-for哪个优先级高,如何避免两者同时使用

首先,官方不推荐v-if和v-for在同一个元素上使用。其次,如果两者同时使用,v-if和v-for的优先级怎么确定?在vue2和vue3中这两者的优先级顺序不一样。vue2是v-for优先,条件不存在时也会渲染多个注释节点。在vue3中进行了改进,v-if优先级高。在vue3中,v-if在编译阶段进行了静态节点提升,所以在v-for遍历每个节点,v-if对单个节点判断,这种情况会报错。不管是vue2还是vue3,都推荐,将v-for遍历的数组用计算属性改写,根据v-if依赖的条件返回过滤后的数组。

在介绍v-if和v-for的时候,最直观的方式就是去官方提供的模板编译网站,看v-if和v-for同时使用后编译成的结果。

vue2的模板地址:Vue Template Explorer

vue3的模板编译地址:Vue Template Explorer

 vue2测试

在li标签上同时使用v-for和v-if

<template>
  <div>
    <li v-for="item in arr" :key="item" v-if="exists"></li>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: [1, 2, 3, 4],
      exists: false,
    };
  },
};
</script>

<style></style>

 编译就会报错,让你把v-if移到上面标签

如果v-if使用了v-for遍历的item。编译器会提示你使用计算属性过滤满足条件的数组

vue2模板编译

v-if和v-for同时存在

OK,借用vue2的模板编译,看下代码编译后的结果。

function render() {
  with(this) {
    return _c('div', _l((arr), function (item) {
      return (exists) ? _c('li', {
        key: item
      }) : _e()
    }), 0)
  }
}

根据 arr 数组的长度和 exists 的值,渲染一个由 <li> 元素组成的列表。如果 exists 的值为假,则不渲染任何列表元素。因此是先遍历数组,在判断每项。即使不存在,也会创建一个空的注释节点。注释没有内容。

v-if引用了v-for遍历的item内容

<div>
    <li v-for="item in arr" :key="item" v-if="item % 2">item</li>
  </div>

 得到如下结果。可以看到,在vue2中是支持v-if和v-for的同时存在。先循环,在对item%2进行逻辑判断。

function render() {
  with(this) {
    return _c('div', _l((arr), function (item) {
      return (item % 2) ? _c('li', {
        key: item
      }, [_v("item")]) : _e()
    }), 0)
  }
}

  • with(this) { ... }:这段代码用于在渲染函数中使用 this 关键字,可以简化对组件实例属性的访问。
  • _c('div'):这段代码用于创建一个 div 元素,返回一个虚拟 DOM 节点。
  • _l((arr), function (item) { ... }):这段代码用于创建一个包含多个 li 元素的数组,每个 li 元素对应 arr 数组的一个元素。其中 arr 是一个组件实例的属性,表示要渲染的数组。
  • (item % 2):这段代码用于判断当前 item 的值是否能被 2 整除,返回一个布尔值。
  • _c('li', { key: item }):这段代码用于创建一个 li 元素,并设置 key 属性为当前 item 的值。
  • _v("item"):这段代码用于创建一个文本节点,其值为字符串 "item"。
  • _e():这段代码用于创建一个空的虚拟 DOM 节点,表示当前 item 不需要渲染为 li 元素。
  • 0:这个数字表示在 div 元素中渲染 li 元素的位置,这里表示在第一个位置。

vue3测试

v-if引用了v-for遍历的item内容

直接举例v-if和v-for同时存在,并且v-if引用了v-for的遍历结果。可以看到控制台报错,item未定义。这是因为item在编译为渲染函数的时候提到v-for的上面一层了。使用的时候还没在定义。

<template>
  <div>
    <li v-for="item in arr" :key="item" v-if="item % 2">item</li>
  </div>
</template>

<script lang="ts" setup>
import { ref } from "vue";
const exists = ref(false);
let arr = ref([1, 2, 3, 4]);
</script>

vue3模板编译

可以看到vue3编译后v-if被提到外面。首先会判断 (_ctx.item % 2),这里item未定义,因为item是在v-for定义的,所以会报错。判断完v-if的条件,假设条件是对的,会执行第一个渲染列表每项。如果条件不满足,创建一个注释节点,与vue2不同,这里注释的内容有一个v-if标识。

在 Vue 中很多地方都运用了注释节点来作为占位节点,其目的是在不展示该元素的时候,标识其在页面中的位置,以便在 patch 的时候将该元素放回该位置。

import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    (_ctx.item % 2)
      ? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(_ctx.arr, (item) => {
          return (_openBlock(), _createElementBlock("li", { key: item }, "item"))
        }), 128 /* KEYED_FRAGMENT */))
      : _createCommentVNode("v-if", true)
  ]))
}
  • (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(_ctx.arr, (item) => { ... })这一行的作用是渲染一个列表,它使用 _renderList 函数来渲染 _ctx.arr 数组中的每个元素。如果当前 item 是偶数,则渲染一个 li 元素,并将其作为子节点插入到列表中。这里使用了 _Fragment 函数,用于将多个子节点合并为一个单一的虚拟节点。
  • _createCommentVNode("v-if", true) 这一行创建一个注释节点,表示在条件不满足的情况下不渲染任何内容。

vue2源码分析

v-if和v-for是不是写在模板template里,那么它们的源码就去模板编译过程去找。编译有三个过程,parse将模板解析为AST语法树->optimize优化AST语法树->codegen生成编译后的code。在最后codegen过程中,会先解析AST树中的与v-for相关的属性,再解析与v-if相关的属性。

genElement函数

在源码 vue-main\src\compiler\codegen\index.ts文件中

其实从此处可以初步知道为什么v-for优先级比v-if高,因为解析ast树生成渲染函数代码时,会先解析ast树中涉及到v-for的属性。然后再解析ast树中涉及到v-if的属性。而且genFor在会把el.forProcessed置为true,防止重复解析v-for相关属性。

genFor\genIf函数

vue-main\src\compiler\codegen\index.ts

 

以之前例子为例,处理liast树时,会先调用genElement,处理到for属性时,此时forProcessed为虚值,此时调用genFor处理li树中的v-for相关的属性。然后再调用genElement处理li树,此时因为forProcessedgenFor中已被标记为true。因此genFor不会被执行,继而执行genIf处理与v-if相关的属性。

vue3

在vue3中没有那个代码能够明显看出v-if和v-for的优先级

只有这个文件稍微体现了某个处理过程中对v-if和v-for同时存在的处理

在core-main\packages\compiler-core\src\transforms\vIf.ts文件中

 createIfBranch函数

在这个函数中,可以看出当v-ifv-for同时使用时,Vue 3会根据条件判断是否为<template>元素以及是否存在v-for指令来决定v-if的条件判断应用在哪个节点上。具体来说,如果节点是<template>元素且没有v-for指令,那么v-if的条件判断会被应用在<template>元素的子节点上;否则,v-if的条件判断会被应用在当前节点上。

 虽然这段代码没有直接提到“静态提升”,但根据Vue 3的设计,Vue 3会在编译阶段对模板进行静态分析,并对v-if进行静态提升,以提高性能。因此,可以理解为在这个函数中,Vue 3会对v-if进行静态提升,以确保条件判断的准确性和性能优化。

vue2 VS vue3

  • 在Vue 2中,由于v-for的优先级高于v-if,当v-if使用了v-for的遍历结果时,Vue 2会对每个元素都执行v-if条件判断。这可能导致性能问题,特别是在数据量较大时。
  • 而在Vue 3中,由于v-if的优先级高于v-for,Vue 3会在编译阶段对v-if进行静态提升(static hoisting),只对整个元素进行一次条件判断,而不会对每个元素都执行条件判断。这样可以提高性能,特别是在大型列表渲染时

v-ifv-for同时作用在同一个元素上,并且v-if使用了v-for的遍历结果时,两个版本的处理方式有所不同:

vue2会正常渲染。因为vue2先对for展开,再对v-if使用的item进行判断。

而vue3会发出警告。控制台会警告,item未定义。因为vue3先使用了v-if,在使用v-if的时候找不到item。所以尽量不要用v-if分析v-for里的内容。

 如何避免同时使用v-if和v-for

为了避免同时使用v-ifv-for,可以考虑以下几种方法:

  1. 使用计算属性或方法:将需要根据条件筛选的数据在组件中提前处理好,然后在模板中只使用v-for进行循环展示。
  2. 使用过滤器:通过过滤器对数据进行筛选,然后在模板中只使用v-for进行循环展示。
  3. 使用嵌套元素:将需要条件判断的元素放置在另一个包裹元素内,然后在外层元素上使用v-for,在内层元素上使用v-if。目的就是让v-if和v-for分开

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/535718.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM 垃圾收集器

JVM 垃圾收集器 垃圾收集器 垃圾收集器 Serial (串行)&#xff1a;单线程垃圾回收器&#xff1b;采用复制算法 Serial Old&#xff1a;Serial 收集器的老年代版本&#xff0c;采用标记-整理算法。 ParNew&#xff1a;多线程的垃圾回收器&#xff08;Serial 的多线程版本&#x…

推荐一个大学生可以参加的榜单赛事|人工智能赛道

【榜单赛事】第十四届全国大学生计算机应用能力与数字素养大赛 - 人工智能产业应用赛道人工智能编程赛项 正在火热报名中 本赛道定位于人工智能产业应用和实践&#xff0c;把人工智能产业真实的技能要求、能力要求体现在竞赛内容设计当中&#xff0c;并在竞赛环节融入实战项目…

SQLite Android 绑定(十八)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 在Android安装与定制方案&#xff08;十七&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 ​ 应用程序编程 加载共享库 在使用任何与 SQLite 相关的方法或对象之前&#xff0c;本机 SQLite 必…

H5:canvas刮刮乐

今日无事&#xff0c;写一个刮刮乐用于收割亲弟弟零花钱 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>Title</title><style>body {height: 100vh;background-color: #fff;}.textDiv {…

数学之光照亮AI之路:探究数学背景在人工智能学习中的优势

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已成为引领未来发展的重要力量。然而&#xff0c;对于许多初涉此领域的学习者来说&#xff0c;AI的复杂性和深度常常让他们望而却步。有趣的是&#xff0c;那些数学基础扎实的人在学习AI时&#xff0c;往往…

2024 Android Studio安装及配置gradle快速省心搭建,不放C盘,前置搭建

题外话&#xff1a;要做安卓项目然后安装过Android Studio的朋友都知道&#xff0c;下载安装完成之后并不能直接开始你的第一个安卓项目的“ Hello World”&#xff0c;其中有要配置好gradle&#xff0c;在你测试好环境之前你会遇到很多问题&#xff0c;同时默认下使用中所需依…

Redis从入门到精通(十二)Redis实战(九)GEO查询附近商户、BitMap用户签到和统计、HLL的UV统计

↑↑↑请在文章开头处下载测试项目源代码↑↑↑ 文章目录 前言4.10 附近商户4.10.1 GEO介绍4.10.2 附近商户需求分析4.10.3 实现新增商户功能4.10.4 实现查询附近商户功能 4.11 用户签到4.11.1 用户签到需求分析4.11.2 BitMap介绍4.11.3 实现用户签到4.11.4 实现用户签到统计4.…

备战蓝桥杯---数学刷题3

话不多说&#xff0c;直接看题&#xff1a; 1. 我们可以得到大致一个思路&#xff0c;就是先枚举1-1e6的质数&#xff0c;然后看看有几个即可。 我们怎么知道个数呢&#xff1f; 首先我们知道1---n中有n/p的下取整个为p的倍数。 因此&#xff0c;p的个数至少是n/p的下取整个…

损失函数-交叉熵 梯度下降

文章目录 1、交叉熵的简单例子1.2、Classification Error&#xff08;分类错误率&#xff09;1.3、Mean Squared Error (均方误差)1.4、交叉熵损失函数1.5、二分类 2、什么是梯度下降法&#xff1f;2.2、梯度下降法的运行过程2.3、二元函数的梯度下降 1、交叉熵的简单例子 参考…

多模态小记:CLIP、BLIP与BLIP2

CLIP 使用网络上爬取得到的大量图文对进行对比学习&#xff0c;图文匹配的是正样本&#xff0c;图文不匹配的是负样本&#xff0c;使匹配样本的embedding之间的距离尽可能小&#xff0c;不匹配样本间的距离尽可能大。 缺点&#xff1a;网上爬的数据质量差&#xff0c;不能进行…

SOCKS代理是如何提高网络性能和兼容性的?

SOCKS代理作为一种网络协议中间件&#xff0c;不仅在提升网络隐私和安全性方面发挥着重要作用&#xff0c;也在提高网络性能和兼容性方面有着不容忽视的影响&#x1f680;。本文将深入探讨SOCKS代理如何通过减少网络延迟&#x1f680;、优化数据传输&#x1f504;、提高跨平台兼…

十进制,二进制,八进制,十六进制之间转换

一. 十进制转二进制 二. 二进制转十进制 三. 十进制转八进制 四. 八进制转十进制 五. 十进制转十六进制

数字档案馆升级改造的意义

数字档案馆升级改造的意义在于提升档案管理的效率和质量&#xff0c;更好地满足各方面的需求&#xff0c;并为数字时代的档案管理提供更好的支持和保障。具体意义包括&#xff1a; 1. 提高档案存储、检索和利用效率&#xff1a;玖拓智能数字化档案馆可以实现电子存储和快速检索…

el-tree如何修改节点点击颜色

el-tree修改点击节点颜色三大步 使用elementui库时&#xff0c;有时候我们会对里面提供的组件做一些样式修改。如果我们想要修改el-tree组件点击节点时的颜色&#xff0c;可以使用下面这种方式实现&#xff1a;

最新国产中文版官网chatGPT镜像网站

分享5个国产中文版chatGPT镜像网站&#xff0c;希望可以帮助到您&#xff01; 1️⃣ HiClaude3基于国外原版GPT模型、Claude模型开发&#xff0c;是资源丰富的全能镜像&#xff0c;适合各行各业的工作者。不仅有gpt&#xff0c;而且还支持图片对话、文件对话&#xff0c;轻松解…

项目存放在git上,在jenkins使用docker打包并推送到Ubuntu上运行

项目添加dockerfile 在需要打包的工程的根目录添加Dockerfile文件&#xff0c;文件内容&#xff1a; # 设置JAVA版本 FROM openjdk:8 # 指定存储卷&#xff0c;任何向/tmp写入的信息都不会记录到容器存储层 VOLUME /tmp# 拷贝运行JAR包 ARG JAR_FILE COPY ${JAR_FILE} app.jar…

08 - 镜像管理之:镜像仓库harbor介绍

本文参考&#xff1a;原文1 1 Harbor仓库介绍 Docker容器应用的开发和运行离不开可靠的镜像管理&#xff0c;虽然Docker官方也提供了公共的镜像仓库&#xff0c;但是从安全和效率等方面考虑&#xff0c;部署我们私有环境内的Registry 也是非常必要的。 之前介绍了Docker私有仓…

适用于W波段GaAs开关设计的可扩展p-i-n二极管建模与参数提取技术

来源&#xff1a;Scalable p-i-n Diode Modeling and Parameter Extraction for Use in the Design of W-Band GaAs Switch&#xff08;TIE 21年&#xff09; 摘要 本文介绍了一种针对W波段开关设计的基于毫米波GaAs的p-i-n二极管的可扩展建模与参数提取方法。采用基于晶圆上…

创新指南|战略衡量的增长组织:用人工智能增强关键绩效指标(KPI)

传统的关键绩效指标 (KPI)越来越无法提供领导者取得成功所需的信息和见解。他们在跟踪进展、协调人员和流程、确定资源优先级以及推进问责制方面存在不足。本文是 2024 年第一份麻省理工学院 SMR - BCG 人工智能和商业战略全球高管学习和研究项目的调查结果——人工智能和业务战…

鸿蒙开发学习笔记第一篇--TypeScript基础语法

目录 前言 一、ArkTS 二、基础语法 1.基础类型 1.布尔值 2.数字 3.字符串 4.数组 5.元组 6.枚举 7.unkown 8.void 9.null和undefined 10.联合类型 2.条件语句 1.if语句 1.最简单的if语句 2.if...else语句 3.if...else if....else 语句 2.switch语句 5.函数…