@trans/components
一个强大的组件转换库,支持将 React 和 Vue 组件转换为 Web Components,实现真正的跨框架组件共享。
✨ 特性
- 🚀 跨框架支持: 支持 React 和 Vue 组件转换
- 🎯 零配置: 开箱即用,简单易用
- 🔧 TypeScript 支持: 完整的类型定义
- 🎨 样式隔离: 支持 Shadow DOM 样式隔离
- 📦 体积小巧: 基于 Lit 构建,体积轻量
- 🔄 双向通信: 支持 props 传递和事件监听
- 🛠 插件化架构: 支持自定义转换器
📦 安装
npm install @trans/components
Peer Dependencies
npm install react react-dom
npm install vue
🚀 快速开始
React 组件转换
import React from 'react';
import { transformAndRegisterReactComponent } from '@trans/components';
const MyButton = ({ text, onClick }) => (
<button onClick={onClick}>{text}</button>
);
const config = {
tagName: 'my-button',
props: {
text: 'Click me'
},
events: ['click']
};
transformAndRegisterReactComponent(MyButton, config);
Vue 组件转换
import { defineComponent } from 'vue';
import { transformAndRegisterVueComponent } from '@trans/components';
const MyCounter = defineComponent({
props: ['initialValue'],
data() {
return { count: this.initialValue || 0 };
},
template: '<div>{{ count }}</div>'
});
const config = {
tagName: 'my-counter',
props: {
initialValue: 0
},
events: ['change']
};
transformAndRegisterVueComponent(MyCounter, config);
在 HTML 中使用
<!DOCTYPE html>
<html>
<head>
<script type="module" src="your-components.js"></script>
</head>
<body>
<my-button text="Hello World"></my-button>
<my-counter initial-value="10"></my-counter>
<script>
document.querySelector('my-button').addEventListener('click', () => {
console.log('Button clicked!');
});
document.querySelector('my-counter').addEventListener('change', (e) => {
console.log('Counter changed:', e.detail);
});
</script>
</body>
</html>
📚 API 文档
统一 API
transformComponent(component, config, framework)
转换组件为 Web Component 类。
import { transformComponent } from '@trans/components';
const WebComponent = transformComponent(MyComponent, config, 'react');
customElements.define('my-component', WebComponent);
transformAndRegister(component, config, framework)
转换组件并自动注册为 Web Component。
import { transformAndRegister } from '@trans/components';
transformAndRegister(MyComponent, config, 'react');
autoRegister(components)
批量转换和注册多个组件。
import { autoRegister } from '@trans/components';
autoRegister([
{ component: ReactButton, config: buttonConfig, framework: 'react' },
{ component: VueCounter, config: counterConfig, framework: 'vue' }
]);
React 专用 API
import {
transformReactComponent,
transformAndRegisterReactComponent
} from '@trans/components';
const WebComponent = transformReactComponent(MyComponent, config);
transformAndRegisterReactComponent(MyComponent, config);
Vue 专用 API
import {
transformVueComponent,
transformAndRegisterVueComponent
} from '@trans/components';
const WebComponent = transformVueComponent(MyComponent, config);
transformAndRegisterVueComponent(MyComponent, config);
⚙️ 配置选项
ComponentConfig
interface ComponentConfig {
tagName: string;
props?: Record<string, any>;
events?: string[];
styles?: string;
shadow?: boolean;
attributes?: Record<string, string>;
}
完整示例
const config = {
tagName: 'my-component',
props: {
title: 'Default Title',
count: 0,
disabled: false
},
events: ['click', 'change', 'custom-event'],
styles: `
:host {
display: block;
padding: 16px;
}
.container {
border: 1px solid #ccc;
border-radius: 4px;
}
`,
shadow: true,
attributes: {
'aria-label': 'My Component'
}
};
🎯 在不同框架中使用
在 React 中使用
function App() {
const handleClick = () => {
console.log('Clicked!');
};
return (
<div>
<my-button text="React App" onCustomEvent={handleClick} />
</div>
);
}
在 Vue 中使用
<template>
<div>
<my-button text="Vue App" @custom-event="handleClick" />
</div>
</template>
<script>
export default {
methods: {
handleClick() {
console.log('Clicked!');
}
}
}
</script>
在 Angular 中使用
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
<my-button text="Angular App" (customEvent)="handleClick()"></my-button>
🔧 高级用法
自定义转换器
import { BaseTransformer, ComponentConfig } from '@trans/components';
class CustomTransformer extends BaseTransformer {
name = 'custom-transformer';
framework = 'custom' as const;
transform(component: any, config: ComponentConfig) {
return this.createWebComponent(component, config, (element) => {
});
}
}
import { getRegistry } from '@trans/components';
const registry = getRegistry();
registry.register(new CustomTransformer());
动态属性更新
const component = document.querySelector('my-component');
component.title = 'New Title';
component.count = 10;
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
console.log('Attribute changed:', mutation.attributeName);
}
});
});
observer.observe(component, { attributes: true });
📋 最佳实践
1. 命名规范
- Web Component 标签名必须包含连字符
- 建议使用命名空间前缀,如
my-app-button
- 事件名使用 kebab-case,如
custom-event
2. 样式管理
const config = {
tagName: 'my-component',
styles: `
/* 使用 :host 选择器设置组件容器样式 */
:host {
display: block;
--primary-color: #1890ff;
}
/* 使用 CSS 变量实现主题定制 */
.button {
background: var(--primary-color);
}
/* 响应式设计 */
@media (max-width: 768px) {
:host {
padding: 8px;
}
}
`
};
3. 事件处理
const handleClick = () => {
element.dispatchEvent(new CustomEvent('custom-click', {
detail: { value: 'some data' },
bubbles: true,
composed: true
}));
};
4. 性能优化
- 使用
shadow: false 如果不需要样式隔离
- 避免在 props 中传递大对象
- 合理使用事件冒泡
🔍 故障排除
常见问题
-
组件不显示
- 检查是否正确导入和注册
- 确认标签名包含连字符
- 检查浏览器控制台错误
-
样式不生效
- 确认使用了正确的 CSS 选择器
- 检查 Shadow DOM 设置
- 使用
:host 选择器
-
事件不触发
- 确认事件名在 config.events 中
- 检查事件监听器绑定
- 确认使用了
composed: true
-
TypeScript 类型错误
- 确保安装了对应的 @types 包
- 检查 tsconfig.json 配置
🤝 贡献指南
欢迎贡献代码!请阅读 CONTRIBUTING.md 了解详细信息。
📄 许可证
MIT License - 详见 LICENSE 文件。
🙏 致谢
- Lit - 高性能 Web Components 库
- React - 用户界面构建库
- Vue - 渐进式 JavaScript 框架