🔴 v-bind 的
.sync
修饰符在 vue3 已移除🟢 但为了更深刻的理解
vue3
模板编译 和AST
,所以我尝试用AST
实现.sync
修饰符
📄 vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {transformSync} from './transformSync'
export default defineConfig({
plugins: [
vue({template: { compilerOptions: { nodeTransforms: [transformSync] } }
})
]
})
📄 transformSync.ts
import {createSimpleExpression, DirectiveNode, SimpleExpressionNode, TemplateChildNode} from '@vue/compiler-core'
import {remove} from '@vue/shared'
const ELEMENT = 1
const DIRECTIVE = 7
// 创立事件表达式
// e.g. @arg="exp"
const createEventExpression = (arg?: SimpleExpressionNode, exp?: SimpleExpressionNode) => ({type: DIRECTIVE, name: 'on', arg, exp, loc: undefined, modifiers: [] } as unknown as DirectiveNode)
/**
* 将 `.sync` 修饰符转换为 `@update:xxx`
*
* e.g.
*
* `<AAA :xxx.sync="value" />`
*
* ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
*
* `<AAA :xxx="value" @update:xxx="value = $event" />`
*/
export function transformSync(node: TemplateChildNode) {if (node.type === ELEMENT) {const { props} = node
for (let i = 0; i < props.length; i++) {const dir = props[i]
// 判断属性是否有 sync 修饰符
if (dir.type == DIRECTIVE && dir.modifiers.includes('sync')) {remove(dir.modifiers, 'sync')
const {arg, exp} = dir
// @update:xxxx
const name = createSimpleExpression('update:' + arg?.loc.source, true)
// value = $event
const val = createSimpleExpression(exp?.loc.source + '= $event')
// 为元素增加 @update:xxx="value = $event"
props.push(createEventExpression(name, val))
}
}
}
}
🔺 以上就是残缺代码了
transformSync.ts
文件去除正文后大略是 30 行代码
🎃 让咱们来试试成果
<!-- MyButton.vue -->
<template>
<button @click="$emit('update:count', count + 1)">count: {{count}}</button>
</template>
<script setup lang="ts">
defineProps<{count: number}>()
</script>
<!-- App.vue -->
<template>
<my-button :count.sync="value" />
</template>
<script setup lang="ts">
import {ref} from 'vue'
import MyButton from './MyButton.vue'
const value = ref(0)
</script>