博客 / 詳情

返回

vue3 模板編譯 —— 我竟把 v-if 和 v-for 的優先級改回來了,不信你看 🤣

📰 前言

眾所周知,在 vue3v-if 總是優先於 v-for 生效。

然而,在某些情況下,我們可能更希望 v-for 的優先級更高,
雖然 vue3 並沒有提供直接修改指令優先級的方法,但是我們可以使用 AST(抽象語法樹) 轉換來實現這一點。

🌈 在線演示


📄 vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { transformForIf } from './transformForIf'

export default defineConfig({
  plugins: [
    vue({
      template: { compilerOptions: { nodeTransforms: [transformForIf] } }
    })
  ]
})

📄 transformForIf.ts

import { remove } from '@vue/shared'
import { NodeTransform, findDir, findProp } from '@vue/compiler-core'

const ELEMENT = 1

// 創建 template 節點
export const createTemplateNode = (props: BaseElementNode['props'], children: BaseElementNode['children'], loc: BaseElementNode['loc']): TemplateNode => ({
  type: ELEMENT,
  tagType: TEMPLATE,
  tag: 'template',
  props: props.filter(e => e),
  children,
  codegenNode: undefined,
  ns: 0,
  isSelfClosing: false,
  loc
})

export const transformForIf: NodeTransform = node => {
  if (node.type != ELEMENT) return

  node.children.forEach((child, i) => {
    if (child.type != ELEMENT) return

    const VFor = findDir(child, 'for')
    if (!VFor) return

    const VIf = findDir(child, 'if')
    if (!VIf) return

    const key = findProp(child, 'key')

    remove(child.props, VFor)
    remove(child.props, VIf)
    remove(child.props, key)

    const templateIf = createTemplateNode([VIf], [child], VIf.loc)
    const templateFor = createTemplateNode([VFor, key], [templateIf], VFor.loc)

    node.children[i] = templateFor
  })
}

🔺 以上就是完整代碼了


🎃 讓我們來試試效果

<template>
  <div>
    <span v-for="i in 10" v-if="i % 2">{{ i }}</span>
  </div>
</template>

🚀 運行成功 😆

🚀 在線 StackBlitz 編輯


👍 點個贊吧 ✨ 👈

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.