如何让 React.js 和 Bootstrap 4 模态轮播始终在打开时显示第一张图像

Posted

技术标签:

【中文标题】如何让 React.js 和 Bootstrap 4 模态轮播始终在打开时显示第一张图像【英文标题】:How to get React.js and Bootstrap 4 modal carousel to always display the first image on open 【发布时间】:2020-05-06 06:05:02 【问题描述】:

我将 React.js 与 Bootstrap 4 模态/轮播一起使用,我希望在打开/重新打开模态时始终显示第一张图像。现在,第一次打开模态时会显示第一张图像,但是当用户滚动到另一个图像然后关闭并重新打开模态时,它会显示用户查看的最后一张图像,而不总是第一张。我尝试在我的 componentDidMount 中使用 jquery 来强制轮播索引,但它不起作用。

这是我预期行为的示例场景... 1. 打开模态(显示第一张图片) 2. 轮播到第二个项目 3. 关闭模态 4. 打开模态(显示第一张图片)

这是Demo

index.js

import React,  Component  from 'react';
import  render  from 'react-dom';
import './style.scss';
import $ from 'jquery';

class App extends Component 
    constructor() 
        super();
    

  componentDidMount() 
    // My attempts to always have carousel begin at index 0 on show event
    // $('.largeModal').on('show.bs.modal', function() 
        // console.log('show.bs.modal event');
        // $('.carousel').carousel(0);
    // );

    // $('.largeModal').on('show.bs.modal', function() 
        // console.log('show.bs.modal event');
        // $('#myCarousel').carousel(0);
    // );
  

    render() 
        return (
            <div className='container'>
                <h3 className='text-center mb-4'>React with Bootstrap 4 Modal & Carousel</h3>

                <div class='row mb-4'>
                    <div class='col text-center'>
                        <button
                            type='button'
                            className='btn btn-primary '
                            data-toggle='modal'
                            data-target='#largeModal'
                        >
                            Open Modal
                        </button>
                    </div>
                </div>

                /* Modal*/
                <div
                    className='modal fade'
                    id='largeModal'
                    tabIndex='-1'
                    role='dialog'
                    aria-labelledby='basicModal'
                    aria-hidden='true'
                >
                    <div className='modal-dialog modal-lg'>
                        <div className='modal-content'>
                            <div className='modal-body'>
                                /* Carousel */
                                <div
                                    id='myCarousel'
                                    className='carousel slide'
                                    data-ride='carousel'
                                >
                                    <ol className='carousel-indicators'>
                                        <li
                                            data-target='#myCarousel'
                                            data-slide-to='0'
                                            className='active'
                                        ></li>
                                        <li
                                            data-target='#myCarousel'
                                            data-slide-to='1'
                                        ></li>
                                        <li
                                            data-target='#myCarousel'
                                            data-slide-to='2'
                                        ></li>
                                    </ol>
                                    <div className='carousel-inner'>
                                        <div className='carousel-item active'>
                                            <img
                                                className='img-size'
                                                src='https://images.unsplash.com/photo-1485470733090-0aae1788d5af?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1391&q=80'
                                                alt='First slide'
                                            />
                                        </div>
                                        <div className='carousel-item'>
                                            <img
                                                className='img-size'
                                                src='https://images.unsplash.com/photo-1491555103944-7c647fd857e6?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80'
                                                alt='Second slide'
                                            />
                                        </div>
                                        <div className='carousel-item'>
                                            <img
                                                className='img-size'
                                                src='https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80'
                                                alt='Third slide'
                                            />
                                        </div>
                                    </div>
                                    <a
                                        className='carousel-control-prev'
                                        href='#myCarousel'
                                        role='button'
                                        data-slide='prev'
                                    >
                                        <span
                                            className='carousel-control-prev-icon'
                                            aria-hidden='true'
                                        >
                                            ' '
                                        </span>
                                        <span className='sr-only'>Previous</span>
                                    </a>
                                    <a
                                        className='carousel-control-next'
                                        href='#myCarousel'
                                        role='button'
                                        data-slide='next'
                                    >
                                        <span
                                            className='carousel-control-next-icon'
                                            aria-hidden='true'
                                        ></span>
                                        <span className='sr-only'>Next</span>
                                    </a>
                                </div>
                            </div>
                            <div className='modal-footer'>
                                <button
                                    type='button'
                                    className='btn btn-default'
                                    data-dismiss='modal'
                                >
                                    Close
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    


render(<App />, document.getElementById('root'));

style.scss

.img-size
    height: 450px;
    width: 700px;
    background-size: cover;
    overflow: hidden;

.modal-content 
   width: 700px;
  border:none;

.modal-body 
   padding: 0;


.carousel-control-prev-icon 
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23009be1' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E");
    width: 30px;
    height: 48px;

.carousel-control-next-icon 
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23009be1' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E");
    width: 30px;
    height: 48px;

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>React Modal with Carousel</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>

<body>
    <noscript>You need to enable javascript to run this app.</noscript>
    <div id="root"></div>
</body>

</html>

package.json


  "name": "react",
  "version": "0.0.0",
  "private": true,
  "dependencies": 
    "bootstrap": "^4.4.1",
    "jquery": "1.9.1 - 3",
    "node-sass": "^4.13.1",
    "popper.js": "^1.16.0",
    "react": "^16.9.0",
    "react-dom": "^16.9.0"
  ,
  "scripts": 
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  ,
  "devDependencies": 
    "react-scripts": "latest"
  

【问题讨论】:

你必须从 dom 中切换模式,这样就可以了 不是只控制模态框是否可见吗?我不明白这将如何解决我的问题,你能解释一下吗?这将如何强制每次打开模式时始终显示第一张图像? 切换使模式每次重新渲染,因此轮播缓存将被删除。这将有助于始终渲染第一张图像。仅供参考,将 jQuery 与 react 混合不是一个好习惯。我们有 reactstrap,它是一个用于反应的引导模块,它可以满足您的所有要求。查看@reactstrap.github.io 【参考方案1】:

tl,博士;

在你的 App 中导入的 jQuery 和 window 对象中的不一样。因此,Bootstrap 不会使用您正在使用的 .carousel() 方法对其进行扩展。您可以使用

访问 window 对象中的那个
const $ = window.$

componentDidMount 函数内。看到它here. 或者你可以在 jQuery 之后导入 popper.js 和 Bootstrap 的 js,并从 index.html 中删除 &lt;script&gt; 标签。


完整(初始)答案:

首先,你现在有一些问题:

您的尝试使用$('.largeModal') 完成,但我在您的代码中没有看到任何className="largeModal"。您可能想使用#largeModal。 你的标记中有几个 class 的情况,React 似乎不喜欢它们 您正在使用 Bootstrap v4.0.0。无论主要版本是什么,您都应始终使用该主要版本的最新稳定版本(当前 4 为 v4.4.1,当前 3 为 v3.4.1)。 您正在加载 jQuery 两次。一次在index.html(来自cdn)和一次在你的组件中(来自包)。虽然可以多次加载 jQuery(以允许不同的模块使用不同版本的 jQuery),但它有一种特殊的技术并且您没有使用它(在兼容模式下运行 jQuery)。我不会详细介绍(至少对于当前问题)您不需要它。

现在,您有两个选择:

a) 像您一样加载 jQuery、popper.js 和 bootstrap,但是您还必须将脚本放在 index.html 中,在它们之后(在 &lt;script&gt; 标记中,而不是在componentDidMount),并使用类似:

$(document).on('show.bs.modal', '#largeModal', function() 
  $('#myCarousel').carousel(0);
)

或...b) 在组件内正确加载 jQuery、popper.js 和 bootstrap 的 js(使用 import,从它们各自的 npm 包中)。

主要的问题是,如果你在你的组件中只导入 jQuery(除了加载两次,这本身就是一个问题),它不会有 bootstrap.js 扩展的方法。而且您似乎非常需要其中之一$().carousel()

现在,我知道 "b)" 不是一个理想的实用解决方案,因为您不必分别在每个组件中导入 jQuery、popper 和 bootstrap,解决方案是通过在componentDidMount 中使用const $ = window.$ 将外部引用分配给您的组件,如tl,dr; 中所述。

您可以看到它在工作(通过导入)here。 它也可以在 React 外部工作(选项 "a)")。只要确保您只使用一种方法加载jQuerypopper.jsbootstraps js,而不是同时使用这两种方法。我个人不推荐选项 "a)"(阅读说明)。

干杯!


注意:React 和 jQuery 是两种不同的 Web 范例,一起使用它们会让你的生活变得更加艰难(作为程序员)。通过选择一个并坚持使用它,您可能会更快乐(并且更熟练)(大多数开发人员会建议您放弃 jQuery 并使用 React Bootstrap,但选择完全由您自己决定)。

【讨论】:

我测试了你给我使用的两个选项,它们都有效。您的答案中有很多非常有用的信息,我从中学到了很多。我现在使用选项 b,将来会考虑使用 React Bootstrap。感谢您的帮助! 问题的核心是导入的 jQuery 不是 window 对象中的那个。您可以通过在componentDidMount 中使用const $ = window.$; 来访问外部的(因此您不必导入)。看到它working。注意我将事件从show.bs.modal 更改为shown.bs.modal。您现在可以看到幻灯片返回,因为它发生在模式打开之后。【参考方案2】:

将图像属性存储在对象数组中,例如。 并将它们映射到渲染。

let arr = [

className:'img-size',
src:'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80',
alt:'Third slide'
 ,
and more like this.
]

//Then map the images in carousel ann it would always show first image first, because it would always render images at runtime.

arr.map(img => 
return(
           <img
               className=img.className
               src=img.src
               alt=img.alt
          />
);
)

【讨论】:

我试过了,但它没有按我的预期工作。是的,当用户第一次打开模态时,它从第一张幻灯片开始,但是当他们滚动到第二张图像然后关闭模态并再次重新打开模态时,它在第二张幻灯片上打开,而不是我想要的第一张幻灯片。这是一个使用地图作为轮播项目和图像的更新示例。 react-modal-with-carousel-uavkft.stackblitz.io 制作一个modal的组件并在主文件中导入,然后每次点击按钮都会重新渲染。在我看来可能会起作用。

以上是关于如何让 React.js 和 Bootstrap 4 模态轮播始终在打开时显示第一张图像的主要内容,如果未能解决你的问题,请参考以下文章

基于 React.js + Redux + Bootstrap 的 Ruby China 示例

React.js 中的引导模式

单击按钮后,Bootstrap5 模态未在 React.js 中显示

将 html bootstrap 转换为 react.js jsx 样式后更改 css 样式

react js中的多级下拉菜单不可用还是啥?像 react-bootstrap

React.js + Summernote,如何导入 JavaScript 依赖库