? 前言
眾所周知,在 vue3
中 v-if
總是優先於 v-for
生效。
然而,在某些情況下,我們可能更希望 v-for
的優先順序更高,
雖然 vue3
並沒有提供直接修改指令優先順序的方法,但是我們可以使用 AST(抽象語法樹)
轉換來實現這一點。
? 線上演示
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { transformForIf } from './transformForIf'
export default defineConfig({
plugins: [
vue({
template: { compilerOptions: { nodeTransforms: [transformForIf] } }
})
]
})
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>