当前位置: 首页 > news >正文

【vue vapor jsx 未雨绸缪】

随着vue3.6.0 alpha的发布,vapor mode进入正式版本只是时间上的问题,可以预见的是各个组件库都将积极适配vapor,这篇文章主要侧重vue中使用jsx而非SFC,所以不涉及template相关。目前vue官方也是提供了vue-jsx-vapor这个仓库,处于v2.5.4-beta.1阶段,而vue3发布以来使用jsx的插件为 @vitejs/plugin-vue-jsx,依赖的是vue官方仓库的babel-plugin-jsx,不知道后面会不会直接用vapo jsx还是说两种jsx开发方式并行,ant-deisgn-vue仓库已经将适配vapor mode提上了日程,对于ant-design-vue这种全部由jsx构建的组件库,感觉适配的工作量会很大,对于参与开源有兴趣的朋友可以关注一下

一、变化1:组件定义

// 原
export default defineComponent({name: 'xx',setup(props, { attrs, slots, emit, expose }) {return () => <Comp />}
})// vapor jsx
export default defineVaporComponent((props) => {const attrs = useAttrs()const slots = useSlots()const model = defineModel()defineExpose({...})return <Comp />
})

vue-jsx-vapor 支持 Virtual DOM 和 Vapor DOM 混合使用。将 interop 设置为 true 后,在 defineVaporComponent 中定义的 JSX 会被编译为 Vapor DOM, 在 defineVaporComponent 外定义的 JSX 会被编译为 Virtual DOM

二、变化2:编译器宏

  1. 前置条件:需要手动开启marcos
// vite.config.ts
import { defineConfig } from 'vite'
import vueJsxVapor from 'vue-jsx-vapor/vite'
export default defineConfig({plugins: [vueJsxVapor({ macros: true })]
})// ts-macro.config.ts
import vueJsxVapor from 'vue-jsx-vapor/volar'
export default {plugins: [ vueJsxVapor({ macros: true })],
}
  1. defineModel
    手动挡和自动挡的区别,vapor中如果需要触发外层事件这种,按照相关issue来看应该是不会做defineEmits宏,所以需要通过props拿到事件,如onChange?.(data),就相当于emit(‘change’, data)这种触发形式了
// 假设
<comp v-model="data" />// 原export default defineComponent({emits: ['update:modelValue'],setup(props, { emit }) {emit('update:modelValue', xx)return ...}
})// vapor jsx, 与SFC使用一致
export default defineComponent(() => {const model = defineModel()model.value = xxreturn ...
})
  1. defineSlots
// 原
export default defineComponent({slots: Object as SlotsType<{default: any}>,setup(props, { slots }) {return () => (<div>{ slots.default?.() } </div>)}
})// vapor jsx,与SFC使用有一点差异
export default defineComponent(() => {const slots = defineSlots({default: () => <div>default</div>})return (<slots.default />)
})
  1. defineExpose
// 原
export default defineComponent({setup(props, { expose }) {expose({a: 'xx'})return ...}
})// vapor jsx, 与SFC使用一致
export default defineComponent(() => {defineExpose({a: 'xx'})return ...
})
  1. defineStyle
    这个比较厉害,支持 CSS 变量和 JS 变量绑定;支持在文件中定义多个样式宏;支持多个 CSS 预处理器:cssscsssasslessstyluspostcss;在函数内部定义则scope选项默认为true;支持css-modules
defineStyle(`.red {color: red;}  
`)
defineStyle.css({...})
defineStyle.scss({...})
defineStyle.less({...})
defineStyle.stylus({...})// css-modules
const styles = defineStyle.scss(`.foo { color: blue;.bar { background: red;}}
`)<div class={styles.foo} />

三、变化3:内置指令

  1. v-if、v-else-if、v-else
// 原
简单的条件可以用v-show,是的老版也提供了一些内置指令支持 <div v-show={isVisible} />
稍微复杂一点的可以用三元表达式 {isStatus ? <CompA /> : <CompB />},再稍微复杂点可以三元表达式套娃// vapor jsx,使用与SFC基本一致
export default defineComponent(({ count = 0! }) => {return (<fieldset><legend>If</legend><div v-if={count === 0}>eq {count}</div><div v-else-if={count > 0}>lg {count}</div><div v-else>lt {count}</div></fieldset>)
})
  1. v-for
// 原
<div>
{ data.map((item, index) => {return (<div key={index}>{item}</div>)}) 
}
</div>// vapor jsx,与SFC使用基本一致
export default () => (<div v-for={(item, index) in 4} key={index}>{item}</div>
)
  1. v-slot、v-slots
// 原
export default defineComponent({slots: Object as SlotsType<{default: any}>,setup(props, { slots }) {// 取插槽传递的值return () => (<Child v-slots={{ default: (data) => <div>{data}</div> }>)/ 向子组件传递插槽return () => (<Child v-slots={slots}>)// 或者return () => (<Child v-slots={{ default: slots.default }>)// 或者return () => (<Child>{ slots.default?.() }</Child>)// 亦或者return () => (<Child><Comp /></Child>)}
})// vapor jsx,新增了v-slot,
export default defineComponent(({ count = 0! }) => {return (<>// 取插槽传递出的值<ChildA v-slot={{ foo }}>{{ foo }}</ChildA>// 向子组件传递插槽<ChildB v-slots={{ title: xx }} /></>)
})
  1. v-model
    babel-plugin-jsx还提供过v-models,但1.1.0版本过后不推荐使用,这里就不再提,vapor jsx也不支持v-models,这个指令两个版本使用差别不大,vapor jsx拓展了动态属性与修饰符的用法
// 原
<input v-model={val} />
<input v-model:argument={val} />
<input v-model={[val, ['modifier']]} />
// 或者
<input v-model_modifier={val} />
<A v-model={[val, 'argument', ['modifier']]} />
// 或者
<input v-model:argument_modifier={val} />// vapor jsx
<imput v-model={val} />
<input v-model:argument={val} />
// 动态参数,因为jsx不支持数组表达式,所以用$代替
<input v-model:$name={foo} /> // 等同于SFC <input v-model['name']="foo" />
// 修饰符,因为jsx不支持.关键字,所以用下划线_代替
<input v-model_number={value} /> // 等同于SFC <input v-model.number="value" />

总结

vue之前的jsx的整体结构更偏向于options API,虽然在setup中用的都是composition API,这种算是承接了vue2到vue3的转变,开发体验也比较向react jsx的方向靠拢,新的vapor jsx则是减少了与 SFC 使用的割裂感,将编译器宏、内置指令也带到了jsx开发中,降低了上手难度,也许会吸引到更多的用户来体验在vue中使用jsx开发

特性JSX (babel-plugin-jsx)Vapor JSX (vue-jsx-vapor)
组件定义setup() 返回渲染函数直接返回JSX
编译器宏不支持defineXxx 系列
指令支持仅基础指令(v-show)常用指令(v-if/v-for等)
插槽系统v-slotsv-slotv-slots
样式处理传统CSS方案defineStyle
http://www.lryc.cn/news/599090.html

相关文章:

  • 篇五 网络通信硬件之PHY,MAC, RJ45
  • 统一调度与编排:构建自动化数据驱动平台
  • 【Java、C、C++、Python】飞机订票系统---文件版本
  • Fluent自动化仿真(TUI命令脚本教程)
  • RCE真实漏洞初体验
  • 制造业低代码平台实战评测:简道云、钉钉宜搭、华为云Astro、金蝶云·苍穹、斑斑低代码,谁更值得选?
  • NBIOT模块 BC28通过MQTT协议连接到EMQX
  • 栈与队列:数据结构核心解密
  • 《Uniapp-Vue 3-TS 实战开发》自定义环形进度条组件
  • 数据结构 二叉树(1)
  • 《Uniapp-Vue 3-TS 实战开发》自定义年月日时分秒picker组件
  • uniapp创建vue3+ts+pinia+sass项目
  • Linux 桌面市场份额突破 5%:开源生态的里程碑与未来启示
  • 【数据结构与算法】数据结构初阶:详解二叉树(六)——二叉树应用:二叉树选择题
  • 数据结构3-单双链表的泛型实现及ArrayList与LinkedList的区别
  • SpringBoot(黑马)
  • 【Unity笔记】OpenXR 之VR串流开发笔记:通过RenderTexture实现仅在PC端展示UI,在VR眼镜端隐藏UI
  • Java数组详解
  • S7-1500 与 ET200MP 的组态控制通信(Configuration Control)功能实现详解(下)
  • 【C++进阶】第7课—红黑树
  • SQLFluff
  • Microsoft-DNN NTLM暴露漏洞复现(CVE-2025-52488)
  • RWA的法律合规性如何保证?KYC/AML在RWA项目中的作用是什么?
  • 融合与智能:AI 浪潮驱动下数据库的多维度进化与产业格局重塑新范式
  • 【Java学习】匿名内部类的向外访问机制
  • Android Camera setRepeatingRequest
  • 星慈光编程虫2号小车讲解第三篇--附件概述
  • 星慈光编程虫2号小车讲解第四篇--触摸按键
  • 星慈光编程虫2号小车讲解第一篇--向前向后
  • 【Web APIs】JavaScript 节点操作 ⑧ ( 删除节点 - removeChild 函数 | 删除节点 - 代码示例 | 删除网页评论案例 )