首页 > 其他分享 >前端跨框架组件解决方案

前端跨框架组件解决方案

时间:2024-12-10 12:32:47浏览次数:4  
标签:const 框架 解决方案 前端 React 组件 import button

跨框架组件的开发,是一个兼顾用户体验(UX)开发者体验(DX)的重要问题。随着前端技术生态的快速发展,如何开发能够适配不同框架的组件已成为UI一致性、业务多技术栈需求以及渐进式重构中的重要挑战。

一、跨框架组件的使用场景

1. 大型业务的多技术栈需求

大型业务企业的前端团队可能使用不同的技术栈(如 React 和 Vue)。通过跨框架组件库,可以实现组件复用,减少重复开发的成本,同时保持设计一致性。

2.UI交互的一致性

一个成功的设计系统需要在不同框架和平台中提供一致的用户体验。跨框架组件能确保设计一致性和交互统一,从而提高用户满意度。

3.第三方库或插件

第三方组件库(如日期选择器、图表库等)需要适配多种框架以覆盖更广泛的用户群体,提升组件的可复用性。

4.渐进式重构

在技术栈迁移过程中(如从 AngularJS 迁移到 React),跨框架组件可以帮助团队在不同框架之间平滑过渡,同时兼容旧框架和新框架。

二、解决方案

在实际开发中,有以下四种常见方案可以帮助我们实现跨框架组件的目标:

1. Web Components

Web Components 是浏览器原生支持的技术,它由 Shadow DOM、Custom Elements 和 HTML Templates 组成,可以在任何框架中使用。

优点

  • 原生支持,无需依赖框架。
  • 跨框架兼容性好。
  • 可封装复杂逻辑并隐藏实现细节。

缺点

  • 与框架的状态管理和事件机制集成较复杂。
  • 学习曲线较高,部分 API 浏览器兼容性有限。

代码示例

class MyButton extends HTMLElement {
  // 监听 label 属性变化
  static get observedAttributes() {
    return ['label'];
  }

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });

    // 创建样式
    const style = document.createElement('style');
    style.textContent = `
        button {
          background-color: var(--button-bg-color, #007bff);
          color: var(--button-text-color, white);
          border: none;
          border-radius: var(--button-border-radius, 4px);
          padding: var(--button-padding, 10px 20px);
          font-size: var(--button-font-size, 16px);
          cursor: pointer;
        }
        button:hover {
          background-color: var(--button-hover-bg-color, #0056b3);
        }
      `;

    // 创建按钮元素
    this.button = document.createElement('button');

    // 添加样式和按钮到 Shadow DOM
    this.shadowRoot.appendChild(style);
    this.shadowRoot.appendChild(this.button);
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'label') {
      this.button.textContent = newValue;
    }
  }

  set label(value) {
    this.setAttribute('label', value);
  }

  get label() {
    return this.getAttribute('label');
  }
}

customElements.define('my-button', MyButton);

在 React 中使用:

import { useEffect, useRef } from 'react';
import '../components/UserCard/index.js'

const Home = () => {
    const buttonRef = useRef();

    useEffect(() => {
        const handleClick = () => {
            alert('React handled click!');
        };

        const button = buttonRef.current;
        if (button) {
            button.addEventListener('click', handleClick);
            return () => {
                button.removeEventListener('click', handleClick);
            };
        }
    }, []);

    return <my-button ref={buttonRef} label="React Button"></my-button>;
};

export default Home;

2. Mitosis

官方Slogan:Write components once, run everywhere.

Mitosis 是一个开源工具,它能将 JSX 组件转换为适用于诸如 Angular、React、Qwik、Vue、Svelte、Solid 以及 React Native 等框架的全功能组件。开发者编写一次代码,可以生成多种框架的实现。

Mitosis 有点类似于 Taro 在小程序开发中的存在,一次React或Vue开发和编译后,可以在多个不同的小程序中运行。

优点

  • 一次开发,多框架生成。
  • 集成现有技术栈,降低维护成本。

缺点

  • 生成的代码可能较复杂,不适合高度定制化场景。
  • 需要依赖 Mitosis 的生态, 有自身的语法,有一定的学习成本。

代码示例

编写一个 Mitosis 组件:

import { useState } from "@builder.io/mitosis";

export default function MyComponent(props) {
  const [name, setName] = useState("Steve");

  return (
    <div>
      <input
        css={{
          color: "red",
        }}
        value={name}
        onChange={(event) => setName(event.target.value)}
      />
      Hello! I can run natively in React, Vue, Svelte, Qwik, and many more frameworks!
    </div>
  );
}

可以编译成Vue组件代码:

<template>
  <div>
    <input
      class="input"
      :value="name"
      @change="async (event) => (name = event.target.value)"
    />
    Hello! I can run natively in React, Vue, Svelte, Qwik, and many more
    frameworks!
  </div>
</template>

<script setup>
import { ref } from "vue";

const name = ref("Steve");
</script>

<style scoped>
.input {
  color: red;
}
</style>

编译成 Angular 组件代码:

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";

import { Component } from "@angular/core";

@Component({
  selector: "my-component",
  template: `
    <div>
      <input
        class="input"
        [attr.value]="name"
        (change)="name = $event.target.value"
      />

      Hello! I can run natively in React, Vue, Svelte, Qwik, and many more
      frameworks!
    </div>
  `,
  styles: [
    `
      :host {
        display: contents;
      }
      .input {
        color: red;
      }
    `,
  ],
})
export default class MyComponent {
  name = "Steve";
}

@NgModule({
  declarations: [MyComponent],
  imports: [CommonModule],
  exports: [MyComponent],
})
export class MyComponentModule {}

3. Ark UI

Ark UI 是一个无框架依赖的组件库,提供框架无关的核心逻辑和 API,开发者可以将它使用到 React、Vue 或 Solid 开发中。

优点

  • 提供基础逻辑,适配各框架。
  • 社区支持活跃,文档完善。

缺点

  • 需要手动适配 UI 层。
  • 对新手开发者不够友好。

比较类似的一个UI组件库是 Park UI

官方介绍:Beautifully designed components built with  Ark UI and  Panda CSS that work with a variety of JS frameworks.

4. Zag.js

Slogan:UI components powered by Finite State Machines.

Zag.js 是一个声明式的 UI 组件逻辑框架,专注于逻辑与 UI 分离。它提供了框架无关的状态管理和交互逻辑,开发者可以通过适配器将逻辑集成到 React、Vue、Solid 和 Svelte中。

优点

  • 将复杂组件的逻辑抽象为状态机(State Machines),提供清晰的状态管理和事件处理流程,更易于调试和维护复杂的组件交互。

缺点

  • 有特定的语法,有一定学习成本

代码示例

实现一个跨框架的数字输入组件:

React代码示例:

import * as numberInput from "@zag-js/number-input"
import { useMachine, normalizeProps } from "@zag-js/react"

export function NumberInput() {
    const [state, send] = useMachine(numberInput.machine({ id: "1" }))  
    const api = numberInput.connect(state, send, normalizeProps)
    return (
        <div {...api.getRootProps()}>
            <label {...api.getLabelProps()}>Enter number:</label>
            <div>
                <button {...api.getDecrementTriggerProps()}>DEC</button>
                <input {...api.getInputProps()} />
                <button {...api.getIncrementTriggerProps()}>INC</button>
            </div>
        </div>
    )
}

Solid代码示例:

import * as numberInput from "@zag-js/number-input"
import { normalizeProps, useMachine } from "@zag-js/solid"
import { createMemo, createUniqueId } from "solid-js"

export function NumberInput() {
    const [state, send] = useMachine(numberInput.machine({ id: createUniqueId() }))
    const api = createMemo(() => numberInput.connect(state, send, normalizeProps))
    
    return (
        <div {...api().getRootProps()}>
          <label {...api().getLabelProps()}>Enter number:</label>
          <div>
            <button {...api().getDecrementTriggerProps()}>DEC</button>
            <input {...api().getInputProps()} />
            <button {...api().getIncrementTriggerProps()}>INC</button>
          </div>
        </div>
    )
}

Vue 代码示例:

<script setup>
import * as numberInput from "@zag-js/number-input";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed } from "vue";

const [state, send] = useMachine(numberInput.machine({ id: "1" }));
const api = computed(() =>
  numberInput.connect(state.value, send, normalizeProps)
);
</script>

<template>
  <div ref="ref" v-bind="api.getRootProps()">
    <label v-bind="api.getLabelProps()">Enter number</label>
    <div>
      <button v-bind="api.getDecrementTriggerProps()">DEC</button>
      <input v-bind="api.getInputProps()" />
      <button v-bind="api.getIncrementTriggerProps()">INC</button>
    </div>
  </div>
</template>

三、总结

在实际开发中,选择跨框架组件的实现方式需要根据项目业务特点、团队技术背景和未来的可维护性等方面来权衡。

希望这篇文章能帮助你更好地理解如何开发和使用跨框架组件,并为你的项目选择最优方案!

欢迎关注工种号【码界交流圈】好文第一时间分享不迷路!~

标签:const,框架,解决方案,前端,React,组件,import,button
From: https://blog.csdn.net/2401_87546826/article/details/144370385

相关文章

  • qiankun-新建一个微前端项目
    本地是vue环境,所以拿vue项目练习。1、创建一个父项目,两个子项目vuecreateparentvuecreatechildren-onevuecreatechildren-two2、打开主项目,引入qiankuncdparentnpmiqiankun-S这里我遇到了问题,PSC:\Users\admin\Desktop\qiankun\parent>npmiqiankun-Snpm......
  • 十六、JMeter测试报告可视化组件
    总体统计信息请求总数:直观地展示了测试过程中总共发送的请求数量。这可以帮助你了解测试的规模,例如,如果你计划发送1000个请求,通过这个指标可以快速确认是否达到预期数量。平均响应时间:以图表或数值形式呈现所有请求的平均响应时长。通过观察平均响应时间,你可以初步判断系......
  • WX小程序DevTocls调试工具hook注入失败解决方案
    !!!此问题只能解决志远大佬开发的工具相信很多小伙伴遇到hook注入失败的情况,如图:遇到这种,首先你先关闭微信,找到你的微信小程序的安装路径C:\Users\自己的用户\AppData\Roaming\Tencent\WeChat\XPlugin\Plugins\RadiumWMPF然后删除该目录的所有文件夹就行此刻你重新打开微信,再......
  • 前端必须掌握的设计模式——单例模式
    目录定义应用场景优缺点优点缺点JavaScript实现TypeScript实现总结定义    单例模式(SingletonPattern)属于 创建型 设计模式,是经典设计模式中最简单的一种,也是开发中最常见的一种。顾名思义,单例可以理解为一个类有且仅有一个实例对象,每次创建实例对象时,如......
  • 第 135 期 零基础 Shopify 前端教程 常用方法演示 修改店铺必看
    通过YouTube观看本期Shopify教程面向Shopify个人卖家和运营人员的零基础前端教程,看懂这一期视频教程,你就能修改常用的Shopify主题代码了。如果你没有前端基础,掌握这一期视频里的内容,比你去网上搜索和浏览n篇帖子都更直接有效。看一篇教程只是了解一种方法,而学会这期......
  • 说说你对持续集成的理解,它解决什么问题以及如何在前端中运用?
    持续集成(ContinuousIntegration,简称CI)是一种软件开发实践,旨在频繁地将代码集成到共享存储库中。每次集成都通过自动化的构建(包括编译、打包、测试)来验证,从而尽早地发现集成错误。CI解决的问题:尽早发现集成问题:传统的开发模式中,集成通常发生在项目后期,此时解决冲突的成本非常......
  • 微前端实战:大型前端应用的拆分与治理
    "这个系统太庞大了,每次发布都提心吊胆..."上个月的技术评审会上,我们团队正面临一个棘手的问题。一个运行了两年的企业级中后台系统,代码量超过30万行,构建时间长达20分钟,任何小改动都可能引发意想不到的问题。作为技术负责人,我决定是时候引入微前端架构了。经过一个月的......
  • 在工作中有没有遇到过哪些前端样式你是用css做不出来的?做不出来怎么办?
    在前端开发工作中,确实会遇到一些纯粹用CSS难以实现或实现成本过高的样式效果。以下列举一些常见情况以及对应的解决方案:1.复杂的形状和图形:问题:CSS主要擅长处理矩形、圆形等基本形状,对于一些不规则图形、复杂的曲线或动画图形,使用CSS实现起来非常困难,代码量大且难以......
  • outlook怎么发送超大附件,这里有解决方案!
    很多企业都是使用Outlook来进行邮件的收发,但Outlook邮箱的附件上传大小有限制(如50MB),如附件过大,将无法直接发送。在outlook怎么发送超大附件这个问题上,会遇到邮件服务提供商的限制、网络条件、安全风险、用户体验等问题。1.邮件服务提供商的限制Outlook以及大多数邮件服务提供商......
  • 前端 js + html + css 特效 001
    <!DOCTYPEhtml><htmllang="en"><head><title>CodeTheWorld-Electricstrings</title><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><sc......