前言
上一篇介绍了如何操作 templateAst 来实现生成 template 代码,那么今天我们就来讲一下如何操作单文件组件中的 script 代码。
功能特点
- 支持 Options API 和 Composition API 两种风格
- 支持 TypeScript 和 JSX 语法
- 提供统一的 API 来操作组件的各个部分
- 返回标准的 AST,方便进一步处理
基本用法
typescript
import { parseSfcScript } from 'sfc-generator'
// Options API 模式
const optionsApiCode = `
export default {
name: 'AInput',
data() {
return {
value: '1'
}
}
}
`
const { api: optionsApi, ast } = parseSfcScript(optionsApiCode)
// Composition API 模式
const setupApiCode = `
const checked = ref('')
const str = ref('')
`
const { api: setupApi, ast } = parseSfcScript(setupApiCode, { setup: true })
API 详解
1. Options API 模式
Data 操作
typescript
// 添加数据
api.data().add('number', t.numericLiteral(1))
// 结果:
// export default {
// name: 'AInput',
// data() {
// return {
// value: '1',
// number: 1
// }
// }
// }
// 更新数据
api.data().update('value', t.booleanLiteral(true))
// 结果:
// export default {
// name: 'AInput',
// data() {
// return {
// value: true,
// number: 1
// }
// }
// }
// 删除数据
api.data().remove('value')
// 结果:
// export default {
// name: 'AInput',
// data() {
// return {
// number: 1
// }
// }
// }
Methods 操作
typescript
// 添加方法
api.methods().add(
t.objectMethod(
'method',
t.identifier('handleInput'),
[t.identifier('val')],
t.blockStatement([
template.statement('this.value = val')(),
]),
),
)
// 结果:
// export default {
// name: 'AInput',
// methods: {
// handleChange(val) {
// this.value = val
// },
// handleInput(val) {
// this.value = val
// }
// }
// }
// 更新方法
api.methods().update(
t.objectMethod(
'method',
t.identifier('handleChange'),
[t.identifier('val')],
t.blockStatement([
template.statement('this.data = val')(),
]),
),
)
// 删除方法
api.methods().remove('handleChange')
Props 操作
typescript
// 添加 props
api.props().add(
t.objectProperty(
t.identifier('checked'),
t.identifier('Boolean'),
),
)
// 结果:
// export default {
// name: 'Switch',
// props: {
// checked: Boolean
// }
// }
// 更新 props
api.props().update(
t.objectProperty(
t.identifier('checked'),
t.objectExpression([
t.objectProperty(
t.identifier('type'),
t.identifier('String'),
),
t.objectProperty(
t.identifier('default'),
t.booleanLiteral(false),
),
]),
),
)
// 删除 props
api.props().remove('checked')
2. Composition API 模式
Ref 操作
typescript
// 添加 ref
api.data().add(
'value',
t.stringLiteral(''),
)
// 结果:
// const checked = ref('');
// const value = ref("");
// 更新 ref
api.data().update('checked', t.booleanLiteral(false))
// 结果:
// const checked = ref(false);
// const value = ref("");
// 删除 ref
api.data().remove('checked')
// 结果:
// const value = ref("");
Computed 操作
typescript
// 添加 computed
api.computed().add(
'reverseName',
template.expression('() => lastName.value + \' \' + firstName.value')(),
)
// 结果:
// const firstName = ref('Davide');
// const lastName = ref('Li')
// const fullName = computed(() => firstName.value + lastName.value)
// const reverseName = () => lastName.value + ' ' + firstName.value
// 更新 computed
api.computed().update(
'fullName',
template.expression('() => firstName.value + \' \' + lastName.value')(),
)
// 删除 computed
api.computed().remove('fullName')
Methods 操作
typescript
// 添加方法
api.methods().add(
template.statement(`function handleChange(val){
checked.value = val
}`)() as t.FunctionDeclaration,
)
// 结果:
// const inputValue = ref('')
// const checked = ref(false)
// function handleInput(val) {
// inputValue.value = val
// }
// function handleChange(val){
// checked.value = val
// }
// 更新方法
api.methods().update(
template.statement(`function handleInput(value) {
inputValue.value = value
}`)() as t.FunctionDeclaration,
)
// 删除方法
api.methods().remove('handleInput')
Watch 操作
typescript
// 添加 watch
api.watch().add(
template.statement('watch(x, (newX) => {\nconsole.log(`x is ${newX}`)\n})')() as t.ExpressionStatement
)
// 结果:
// const x = ref(0)
// watch(x, (newX) => {
// console.log(`x is ${newX}`)
// })
实际应用场景
1. 组件代码生成器
typescript
function generateComponent(options) {
const { api } = parseSfcScript('')
// 添加数据
api.data().add('formData', t.objectExpression([]))
// 添加方法
api.methods().add(
t.objectMethod(
'method',
t.identifier('submit'),
[],
t.blockStatement([]),
),
)
return generate(api.ast)
}
注意事项
- 在使用 TypeScript 时,需要设置 lang: 'ts' 选项
- 使用 JSX 语法时,需要设置 jsx: true 选项
- 操作 API 时注意返回值的类型检查
- 修改 AST 后需要使用 @babel/generator 生成代码
总结
parseSfcScript 是一个功能强大的工具函数,它可以帮助我们:
- 解析 Vue 组件代码
- 操作组件的各个部分
- 生成新的组件代码
- 转换组件代码风格
- 分析组件结构
通过合理使用这个工具,我们可以大大提高组件开发效率,实现更多自动化的工作。