vfojs:Vue 超集架构,外壳React灵魂Vue

vfojs

  • React 体验:使用 TSX/JSX 构建 UI,支持同文件多组件组合。
  • Vue 性能:逻辑层直接复用 Vue 3 Composition API 响应式系统。
  • 非侵入式 :通过 Vite 插件精准拦截 .vfo 文件,不干扰现有 Vue 代码,完美兼容所有 Vue 插件与 UI 库。

主要特性

  • Vue 超集架构 :完全支持 Vue 生态(Router, Pinia, Element Plus),.vfo 组件可直接在 .vue 中引用,反之亦然。
  • Scoped CSS/SCSS/Less :支持在 .vfo 中直接声明样式变量,编译期自动实现作用域隔离。
  • 智能属性透传class/style/id 等 attrs 自动合并至根节点,保持与 Vue 一致的行为。
  • 响应式解构 (Writeable Ref)const { count } = props 自动转换为 toRef,支持跨组件双向绑定。
  • 指令语法糖<input $value={state.name} /> 自动展开为高性能的双向绑定逻辑。
  • 内置轻量状态管理useFoStore(key, init) 实现跨组件、跨文件的状态共享。

在 Vue 项目中使用

vfojs 的设计初衷是非侵入式。你可以在现有的 Vue 项目中开启"魔法模式"。

安装 vfojs

bash 复制代码
npm install @fo4/vfojs

1).vfo 组件的基本写法

.vfo 的默认导出是一个函数。你可以把它理解成 Vue 组件的 setup():写逻辑、返回 JSX 作为渲染内容。

tsx 复制代码
export default () => {
  const count = ref(0)
  const inc = () => count.value++

  return (
    <div>
      <h2>计数</h2>
      <p>count:{count.value}</p>
      <button onClick={inc}>加 1</button>
    </div>
  )
}

2)自动注入的 API(无需 import)

.vfo 里可以直接使用(编译时自动注入):

  • Vue:ref/reactive/computed/watch/watchEffect/onMounted/onUnmounted/onUpdated/defineComponent/h/Fragment/Transition/useAttrs/useSlots/toRef
  • vfojs:useFoStore/useFoEffect/useVModel

3)子组件写法(同文件组件 / 组合组件)

你可以在同一个 .vfo 文件里用函数声明子组件,然后像 React 一样在 JSX 里使用:

tsx 复制代码
const myComponent = (props) => {
  return <div>你好,{props.name}</div>
}

export default () => {
  return (
    <div>
      <myComponent name="vfojs" />
    </div>
  )
}

说明:

  • 只要某个函数变量被当成 <myComponent name="vfojs" /> 使用,vfojs 会把它自动包装成真正的 Vue 组件实例(支持生命周期)
  • props 里能直接拿到传入的属性(包含常规 props 和 attrs)
  • 也支持第二个参数 ctx,用于 ctx.slots(slot)等能力

4)插槽(slots)

tsx 复制代码
const myCard = (props, ctx) => {
  const body = ctx?.slots?.default ? ctx.slots.default() : null
  return (
    <div style="border: 1px solid #e5e7eb; border-radius: 12px; padding: 12px;">
      <h3>{props.title}</h3>
      <div>{body}</div>
    </div>
  )
}

export default () => {
  return (
    <myCard title="标题">
      <div>这里是 slot 内容</div>
    </myCard>
  )
}

5)Scoped CSS / SCSS / Less

三种写法都支持:

  • CSS:export const css = \...``
  • SCSS:export const scss = \...``
  • Less:export const less = \...``

也支持在 .vfo 中直接引入样式文件:

ts 复制代码
import './app.scss'
import './app.less'

6)属性透传(Attribute Fallthrough)

像 Vue 一样,传给组件的 class/style/id 等 attrs 会自动合并到根节点:

tsx 复制代码
const myComponent = () => <div class="box">子组件</div>

export default () => {
  return <myComponent class="外部class" style="background: #f8fafc;" />
}

7)响应式解构(可写 ref)与跨组件双向绑定

子组件:

tsx 复制代码
const myComponent = (props) => {
  const { count } = props
  return <button onClick={() => (count.value = count.value + 1)}>count:{count.value}</button>
}

父组件用 onUpdate:count 接收回写:

tsx 复制代码
export default () => {
  const state = reactive({ count: 1 })
  return (
    <div>
      <p>父:{state.count}</p>
      <myComponent count={state.count} onUpdate:count={(v) => (state.count = v)} />
    </div>
  )
}

7.1)编译期宏:$ref(极致"去 .value")

你可以写:

tsx 复制代码
export default () => {
  let count = $ref(0)
  const inc = () => count++
  return <button onClick={inc}>count:{count}</button>
}

vfojs 会在编译时自动把它变成 ref(...),并在使用 count 的地方自动补全 .value

如果你需要拿到"原始 ref 对象"(例如传给子组件做双向绑定),可以写 $$(count),它会在编译时被还原成 count(不会自动解包)。

8)指令语法糖:$value

你可以写:

tsx 复制代码
<input $value={state.name} />

vfojs 会自动把它展开为双向绑定:

  • 原生表单元素(input/textarea/select):value/checked + onInput/onChange
  • 自定义组件:modelValue + onUpdate:modelValue

9)内置全局状态:useFoStore

同一个 key 在多个组件里拿到的是同一份状态(基于 reactive):

tsx 复制代码
const A = () => {
  const store = useFoStore('demo', () => ({ count: 0 }))
  return <button onClick={() => store.count++}>A:{store.count}</button>
}

const B = () => {
  const store = useFoStore('demo', () => ({ count: 0 }))
  return <button onClick={() => store.count--}>B:{store.count}</button>
}

10)便捷 Hook:useFoEffect / useVModel

useFoEffect:更接近 React effect 的心智,组件卸载时自动停止监听并清理副作用:

ts 复制代码
useFoEffect(() => {
  console.log(count.value)
  return () => console.log('cleanup')
}, [count])

useVModel:复杂组件里快速创建一个双向绑定 ref(修改会触发 onUpdate:name):

ts 复制代码
const name = useVModel(props, 'name')
name.value = 'next'

11)显式 Props/Emits:defineProps / defineEmits

definePropsdefineEmits 由编译器自动注入(无需手动 import),用于在 .vfo 中显式声明组件的 props 与事件。

tsx 复制代码
// defineProps 和 defineEmits 将由编译器自动注入,无需手动 import
export default (context) => {
  // 1. 定义 Props(带类型和默认值)
  const props = defineProps<{
    title: string;
    count?: number;
  }>({
    count: 0, // 默认值
  });

  // 2. 定义 Emits
  const emit = defineEmits<{
    (e: 'change', value: number): void;
    (e: 'update:count', value: number): void;
  }>();

  return (
    <div onClick={() => emit('change', props.count)}>
      {props.title}: {props.count}
    </div>
  );
}

事件映射规则:

  • emit('change', x) 会尝试调用 props.onChange(x)
  • emit('update:count', x) 会尝试调用 props['onUpdate:count'](x)

安装 vfojs

bash 复制代码
npm install @fo4/vfojs

1. 配置 Vite

vite.config.ts 中,将 vfojs 插件置于 vue 插件之前:

ts 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vfojs from '@fo4/vfojs'

export default defineConfig({
  plugins: [
    vfojs(), // 拦截并处理 .vfo 文件
    vue(),  // 处理标准 .vue 文件
  ],
})

2. 混合开发模式

App.vue 中调用 .vfo 组件:

vue 复制代码
<script setup>
import MyFoCard from './components/Card.vfo'
</script>
<template>
  <MyFoCard title="来自 vfojs 的组件" class="custom-style" />
</template>


快速上手 (CLI)

bash 复制代码
npx create-vfojs@latest my-app

创建完成后,你可以立即体验。

bash 复制代码
cd my-app
npm i
npm run dev

工具链

模块 说明
create-vfojs 快速创建项目的 CLI 脚手架
@fo4/vfojs-language-plugin 提供 IDE 类型检查与 JSX 属性提示
vscode-vfo 提供 IDE 插件,支持 vfojs 语法 (暂未上架)
fo-ui 基于 vfojs 构建的组件库(开发中)

相关推荐
编程老船长1 小时前
解决不同项目需要不同 Node.js 版本的问题
前端·vue.js
Wect1 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·算法·typescript
漫游的渔夫1 小时前
前端开发者做 Agent:别写成一次请求,用 5 步受控循环防止 AI 乱跑
前端·人工智能·typescript
kyriewen3 小时前
Webpack vs Vite:一个是“老黄牛”,一个是“猎豹”,你选谁?
前端·webpack·vite
打小就很皮...3 小时前
html2canvas + jsPDF 生成 PDF 的踩坑与解决方案总结
前端·pdf
全栈前端老曹3 小时前
【前端地图】多地图平台适配方案——高德、百度、腾讯、Google Maps SDK 差异对比、封装统一地图接口
前端·javascript·百度·dubbo·wgs84·gcj-02·bd09
雾岛听风6913 小时前
JavaScript基础语法速查手册
开发语言·前端·javascript
遇见~未来3 小时前
第三篇_现代布局_从弹性到网格
前端·css3
前端那点事3 小时前
Vue前端SEO优化全攻略(实操落地版,新手也能上手)
前端·vue.js