0

0

vue优先级比较:为什么v-for比v-if高

青灯夜游

青灯夜游

发布时间:2023-03-14 19:44:19

|

1761人浏览过

|

来源于掘金社区

转载

vue为什么v-for的优先级比v-if的高?下面本篇文章就通过分析源码去解答一下这个问题,希望对大家有所帮助!

vue优先级比较:为什么v-for比v-if高

有时候有些面试中经常会问到v-forv-if谁的优先级高,这里就通过分析源码去解答一下这个问题。

下面的内容是在 当我们谈及v-model,我们在讨论什么?的基础上分析的,所以阅读下面内容之前可先看这篇文章。

继续从编译出发

以下面的例子出发分析:

立即学习前端免费学习笔记(深入)”;

new Vue({
    el:'#app',
    template:`
        
  • {{item}}
` })

从上篇文章可以知道,编译有三个步骤

  • parse : 解析模板字符串生成 AST语法树
  • optimize : 优化语法树,主要时标记静态节点,提高更新页面的性能 【相关推荐:vuejs视频教程web前端开发
  • codegen : 生成js代码,主要是render函数和staticRenderFns函数

我们再次顺着这三个步骤对上述例子进行分析。

parse

parse过程中,会对模板使用大量的正则表达式去进行解析。开头的例子会被解析成以下AST节点:

// 其实ast有很多属性,我这里只展示涉及到分析的属性
ast = {
  'type': 1,
  'tag': 'ul',
  'attrsList': [],
  attrsMap: {},
  'children': [{
    'type': 1,
    'tag': 'li',
    'attrsList': [],
    'attrsMap': {
      'v-for': '(item,index) in data',
      'v-if': 'index!==0'
     },
     // v-if解析出来的属性
    'if': 'index!==0',
    'ifConditions': [{
      'exp': 'index!==0',
      'block': // 指向el自身
    }],
    // v-for解析出来的属性
    'for': 'items',
    'alias': 'item',
    'iterator1': 'index',

    'parent': // 指向其父节点
    'children': [
      'type': 2,
      'expression': '_s(item)'
      'text': '{{item}}',
      'tokens': [
        {'@binding':'item'},
      ]
    ]
  }]
}

对于v-for指令,除了记录在attrsMapattrsList,还会新增for(对应要遍历的对象或数组),aliasiterator1,iterator2对应v-for指令绑定内容中的第一,第二,第三个参数,开头的例子没有第三个参数,因此没有iterator2属性。

对于v-if指令,把v-if指令中绑定的内容取出放在if中,与此同时初始化ifConditions属性为数组,然后往里面存放对象:{exp,block},其中exp存放v-if指令中绑定的内容,block指向el

optimize 过程在此不做分析,因为本例子没有静态节点。

codegen

上一篇文章从const code = generate(ast, options)开始分析过其生成代码的过程,generate内部会调用genElement用来解析el,也就是AST语法树。我们来看一下genElement的源码:

Onu
Onu

将脚本转换为内部工具,不需要前端代码。

下载
export function genElement (el: ASTElement, state: CodegenState): string {
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }

  if (el.staticRoot && !el.staticProcessed) {
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    return genOnce(el, state)
  // 其实从此处可以初步知道为什么v-for优先级比v-if高,
  // 因为解析ast树生成渲染函数代码时,会先解析ast树中涉及到v-for的属性
  // 然后再解析ast树中涉及到v-if的属性
  // 而且genFor在会把el.forProcessed置为true,防止重复解析v-for相关属性
  } else if (el.for && !el.forProcessed) {
    return genFor(el, state)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state)

  } else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
    return genChildren(el, state) || 'void 0'
  } else if (el.tag === 'slot') {
    return genSlot(el, state)
  } else {
    // component or element
    let code
    if (el.component) {
      code = genComponent(el.component, el, state)
    } else {
      let data
      if (!el.plain || (el.pre && state.maybeComponent(el))) {
        data = genData(el, state)
      }

      const children = el.inlineTemplate ? null : genChildren(el, state, true)
      code = `_c('${el.tag}'${        data ? `,${data}` : '' // data      }${        children ? `,${children}` : '' // children      })`
    }
    // module transforms
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }
    return code
  }
}

接下来依次看看genForgenIf的函数源码:

export function genFor (el, state , altGen, altHelper) {
  const exp = el.for
  const alias = el.alias
  const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''

  el.forProcessed = true // avoid recursion
  return `${altHelper || '_l'}((${exp}),` + 
    `function(${alias}${iterator1}${iterator2}){` +
      `return ${(altGen || genElement)(el, state)}` + //递归调用genElement
    '})'
}

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

export function genIf (el,state,altGen,altEmpty) {
  el.ifProcessed = true // avoid recursion
  // 调用genIfConditions主要处理el.ifConditions属性
  return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)
}

function genIfConditions (conditions, state, altGen, altEmpty) {
  if (!conditions.length) {
    return altEmpty || '_e()' // _e用于生成空VNode
  }

  const condition = conditions.shift()
  if (condition.exp) { //condition.exp即v-if绑定值,例子中则为'index!==0'
    // 生成一段带三目运算符的js代码字符串
    return `(${condition.exp})?${       genTernaryExp(condition.block)    }:${      genIfConditions(conditions, state, altGen, altEmpty)    }`
  } else {
    return `${genTernaryExp(condition.block)}`
  }

  // v-if with v-once should generate code like (a)?_m(0):_m(1)
  function genTernaryExp (el) {
    return altGen
      ? altGen(el, state)
      : el.once
        ? genOnce(el, state)
        : genElement(el, state)
  }
}

参考 前端进阶面试题详细解答

最后,经过codegen生成的js代码如下:

function render() {
  with(this) {
    return _c('ul', _l((items), function (item, index) {
      return (index !== 0) ? _c('li') : _e()
    }), 0)
  }
}

其中:

  • _c: 调用 createElement 去创建 VNode

  • _l: renderList函数,主要用来渲染列表

  • _e: createEmptyVNode函数,主要用来创建空VNode

总结

为什么v-for的优先级比v-if的高?总结来说是编译有三个过程,parse->optimize->codegen。在codegen过程中,会先解析AST树中的与v-for相关的属性,再解析与v-if相关的属性。除此之外,也可以知道Vuev-forv-if是怎么处理的。

(学习视频分享:vuejs入门教程编程基础视频

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

28

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

8

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

31

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

3

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

5

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

35

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

12

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

40

2026.01.26

抖币充值官方网站 抖币性价比充值链接地址
抖币充值官方网站 抖币性价比充值链接地址

网页端充值步骤:打开浏览器,输入https://www.douyin.com,登录账号;点击右上角头像,选择“钱包”;进入“充值中心”,操作和APP端一致。注意:切勿通过第三方链接、二维码充值,谨防受骗

7

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 9.4万人学习

CSS3 教程
CSS3 教程

共18课时 | 4.9万人学习

Vue 教程
Vue 教程

共42课时 | 7.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号