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

灬都是個謎發表於2023-04-27

? 前言

眾所周知,在 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 編輯


? 點個贊吧 ✨ ?

相關文章