You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用Swiper Element:避免injectStyles影响多轮播

在React中使用Swiper Element实现多轮播样式隔离

我在React组件中使用Swiper Element(WebComponent)为房产机构开发页面,需要配置多个不同样式的轮播。最初通过injectStyles成功设置第一个轮播的分页样式,但第二个轮播的样式无法生效,出现样式继承或不显示的问题。文档显示Swiper样式会注入全局作用域和Shadow DOM,但未明确隔离方法。目前已通过CSS变量修改第二个轮播颜色,希望使用injectStyles实现样式隔离,预期修改单个轮播样式不影响其他轮播。

第一个轮播代码

import React, { useRef, useEffect } from 'react';
import { register } from 'swiper/element/bundle';
import ArticleCardContainer from './ArticleCard';

import { ArrowRight, ArrowLeft } from './Icons';

register();

export const PropertiesNewsCarousel = () => {
  const { articles } = Homeflow.get('latestPropertyNews');
  const isBackgroundWhite = Homeflow.get('isBackgroundWhite').is_background_white;

  const swiperElRef = useRef(null);

  //  Swiper Element web components - css to overide shadown down styles
  const navigationStyles = {
    position: 'static',
    height: '14px',
    marginTop: '0 !important',
    width: 'calc(var(--swiper-navigation-size) / 44 * 27)',
    zIndex: 10,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  };

  useEffect(() => {
    const swiperContainer = swiperElRef.current;

    const params = {
      grabCursor: true,
      // Default parameters
      slidesPerView: 1,
      spaceBetween: 40,
      // Responsive breakpoints
      breakpoints: {
        // small screens
        640: {
          slidesPerView: 1,
          spaceBetween: 40,
        },
        // medium screens
        768: {
          slidesPerView: 2,
          spaceBetween: 50,
        },
        // normal laptop screens
        1024: {
          slidesPerView: 3,
          spaceBetween: 60,
        },
      },
      mousewheel: {
        forceToAxis: true,
      },
      paginationClickable: true,
      pagination: {
        el: '.property-news-swiper-paginations',
        dynamicBullets: true,
        clickable: true,
        dynamicMainBullets: 3,
      },
      navigation: {
        nextEl: '.property-news-swiper-button-next',
        prevEl: '.property-news-swiper-button-prev',
      },
      injectStyles: [
        `
        .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet,
        .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet-active-prev,
        .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet-active-next,
        .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet-active-prev-prev,
        .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet-active-next-next {
            background-color: transparent;
          }

          .swiper-1 .property-news-swiper-paginations .swiper-pagination-bullet.swiper-pagination-bullet-active-main {
            width: 10px;
            height: 10px;
            background-color: ${isBackgroundWhite ? '#002844' : '#fff'};
          }

          .swiper-1 .swiper-pagination {
            bottom: -60px !important;
          }

          .swiper-1 .property-news-swiper-paginations {
            margin: 44px auto 0;
            transform: translateX(0) !important;
          }

          .swiper-1 .property-news-swiper-button-next.swiper-button-disabled,
          .swiper-1 .property-news-swiper-button-prev.swiper-button-disabled {
            opacity: .35;
            cursor: auto;
            pointer-events: none;
          }
      `,
      ],
    };

    Object.assign(swiperContainer, params);
    swiperContainer.initialize();
  }, []);

  return (
    <section className="swiper-section">
      <swiper-container
        ref={swiperElRef}
        init="false"
        id="swiper-container"
        class="swiper-1"
      >
        {articles?.map(article => (
          <swiper-slide key={article?.slug}>
            <ArticleCardContainer imageUrl={article?.image} title={article?.title} articleUrl={`/articles/${article?.slug}`} />
          </swiper-slide>
        ))}
      </swiper-container>

      {/* Boolet points pagination */}
      <div className="property-news-swiper-paginations" />

      {/* isBackgroundWhite type String */}

      {/* Arrows navigation */}
      <div className={`${isBackgroundWhite ? 'swiper-buttons-box' : 'swiper-buttons-box-primary'}`}>
        <section className={`${isBackgroundWhite ? 'swiper-buttons-box__section' : 'swiper-buttons-box-primary__section'}`}>
          <div className="property-news-swiper-button-prev" style={navigationStyles}>
            <ArrowLeft className={`${isBackgroundWhite ? 'swiper-buttons-box__section-arrow' : 'swiper-buttons-box-primary__section-arrow'}`} />
          </div>
          <div className="property-news-swiper-button-next" style={navigationStyles}>
            <ArrowRight className={`${isBackgroundWhite ? 'swiper-buttons-box__section-arrow' : 'swiper-buttons-box-primary__section-arrow'}`} />
          </div>
        </section>
      </div>
    </section>
  );
};

export default PropertiesNewsCarousel;

第二个轮播代码

import React, { useRef, useEffect } from 'react';
import { uniqueKey } from 'homeflowjs';
import { register } from 'swiper/element/bundle';

register();

const PromoBoxesCarousel = () => {
  const promoCardsData = Homeflow.get('promoCards').promo_cards_data;

  const swiperElRef = useRef(null);

  //  Swiper Element web components - css to overide shadown down styles
  const paginationStyles = {
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    height: '15px',
    transform: 'translateX(0)',
  };

  useEffect(() => {
    const swiperContainer = swiperElRef.current;
    const params = {
      grabCursor: true,
      // Default parameters
      slidesPerView: 1,
      spaceBetween: 10,
      // Responsive breakpoints
      breakpoints: {
        // small screens
        640: {
          slidesPerView: 1,
        },
        // medium screens
        768: {
          slidesPerView: 3,
        },
        // small laptop screens
        1024: {
          slidesPerView: 4,
        },
        // normal laptop screens
        1400: {
          slidesPerView: 5,
        },
      },
      mousewheel: {
        forceToAxis: true,
      },
      paginationClickable: true,
      pagination: {
        el: '.promo-swiper-paginations',
        dynamicBullets: true,
        clickable: true,
        dynamicMainBullets: 3,
      },
      injectStyles: [
        `
        .swiper-2 .promo-swiper-paginations .swiper-pagination-bullet,
        .swiper-2 .promo-swiper-paginations .swiper-pagination-bullet-active-prev,
        .swiper-2 .promo-swiper-paginations .swiper-pagination-bullet-active-next,
        .swiper-2 .promo-swiper-paginations .swiper-pagination-bullet-active-prev-prev,
        .swiper-2 .promo-swiper-paginations .swiper-pagination-bullet-active-next-next {
            background-color: transparent;
          }

          .swiper-2 .promo-swiper-paginations span.swiper-pagination-bullet.swiper-pagination-bullet-active.swiper-pagination-bullet-active-main {
            width: 10px;
            height: 10px;
            background-color: #fff;
          }

          .swiper-2 .swiper-pagination {
            bottom: -60px !important;
          }

          .swiper-2 .promo-swiper-paginations {
            margin: 44px auto 0;
            transform: translateX(0) !important;
          }
      `,
      ],
    };

    Object.assign(swiperContainer, params);
    swiperContainer.initialize();
  }, []);

  return (
    <section className="swiper-section">
      <swiper-container
        ref={swiperElRef}
        init="false"
        id="swiper-promo-container"
        class="swiper-2"
      >
        {promoCardsData?.map(card => (
          <swiper-slide key={uniqueKey()}>
            <section className="promo-boxes__item" style={{ backgroundImage: `url(${card.image_url})` }}>
              <div className="promo-boxes__item-content">
                <h2 className="promo-boxes__item-content-title">{ card.title }</h2>
                <a className="promo-boxes__item-content-mob-btn" href={card.button_url}>{ card.button_title }</a>

                <div className="promo-boxes__item-content-box">
                  <p className="promo-boxes__item-content-text">{ card.content }</p>
                  <a className="promo-boxes__item-content-button" href={card.button_url}>{ card.button_title }</a>
                </div>
              </div>
            </section>
          </swiper-slide>
        ))}
      </swiper-container>

      {/* Boolet points pagination */}
      <div className="promo-paginations-box">
        <div className="promo-swiper-paginations" style={{ ...paginationStyles, '--swiper-pagination-color': 'white' }} />
      </div>
    </section>
  );
};

export default PromoBoxesCarousel;

核心修复逻辑

  1. 利用唯一父级选择器隔离样式:每个swiper-container已配置唯一class(swiper-1、swiper-2),将injectStyles中的所有样式选择器前添加该class,确保样式仅作用于当前轮播组件。
  2. 消除全局样式冲突:原代码中.swiper-pagination这类通用选择器会影响所有轮播,添加唯一父级后,样式作用范围被精准限制,不会互相干扰。
  3. 保留原有样式逻辑:仅修改选择器的作用范围,不改动原有的样式属性和逻辑,确保轮播的视觉效果符合预期。

内容的提问来源于stack exchange,提问作者Marcos Riani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 07:52:01