gpt4 book ai didi

javascript - 在滚动事件上 react 更改图像源

转载 作者:行者123 更新时间:2023-11-29 16:36:18 26 4
gpt4 key购买 nike

作为 React 的新手但熟悉 JavaScript,我很难知道在给定的 React 组件中确切地放置某些功能的位置,并且不确定我遇到的这个特定问题是否与我的 React 逻辑或只是加载图像时的延迟时间,尽管如果是后者我不明白这一点,因为我将图像预加载到隐藏的 div 中。

我预期的工作流程如下:

  • 加载两张图片,一张“预加载” height:0作为 hide 的一部分类(class)。
  • 当窗口滚动时,有效地切换 hide在这两个图像中的任何一个上设置类,以便根据滚动位置有效地更改显示哪个图像。发生这种情况时,标题的背景颜色也会发生变化。

  • 在我的组件中 Header.jsx我有以下内容:
    componentDidMount() {
    if (this.props.changeColorOnScroll) {
    window.addEventListener("scroll", this.headerColorChange);
    }
    }
    headerColorChange() {
    console.log("Scroll Fire!");
    const { classes, color, changeColorOnScroll} = this.props;
    const windowsScrollTop = window.pageYOffset;
    if (windowsScrollTop > changeColorOnScroll.height) {
    document.body
    .getElementsByTagName("header")[0]
    .classList.remove(classes[color]);
    document.body
    .getElementsByTagName("header")[0]
    .classList.add(classes[changeColorOnScroll.color]);
    document
    .getElementById("headerLogoContainer").getElementsByClassName("logo")[0]
    .classList.add('hide');
    document
    .getElementById("headerLogoContainer").getElementsByClassName("logoalt")[0]
    .classList.remove('hide');
    } else {
    document.body
    .getElementsByTagName("header")[0]
    .classList.add(classes[color]);
    document.body
    .getElementsByTagName("header")[0]
    .classList.remove(classes[changeColorOnScroll.color]);
    document
    .getElementById("headerLogoContainer").getElementsByClassName("logo")[0]
    .classList.remove('hide');
    document
    .getElementById("headerLogoContainer").getElementsByClassName("logoalt")[0]
    .classList.add('hide');
    }
    }

    我相信这是在 componentDidMount() 中附加事件监听器的正确位置.我的问题是当我滚动时,窗口会随着图像的变化而卡住,即使我在这里预加载了图像:
    render() {
    const {
    classes,
    color,
    rightLinks,
    leftLinks,
    brand,
    logo,
    logoalt,
    fixed,
    absolute
    } = this.props;
    const appBarClasses = classNames({
    [classes.appBar]: true,
    [classes[color]]: color,
    [classes.absolute]: absolute,
    [classes.fixed]: fixed
    });
    let brandComponent;
    if(!logo){
    brandComponent = (
    <Button className={classes.title}>
    {brand}
    </Button>
    );
    }else{
    brandComponent = (
    <div id='headerLogoContainer'>
    <img className='logo' src={logo}></img>
    <img className='logoalt hide' src={logoalt}></img>
    </div>
    );
    }
    return (
    <AppBar className={appBarClasses}>
    <Toolbar className={classes.container}>
    {leftLinks !== undefined ? brandComponent : null}
    <div className={classes.flex}>
    {leftLinks !== undefined ? (
    <Hidden smDown implementation="css">
    {leftLinks}
    </Hidden>
    ) : (
    brandComponent
    )}
    </div>

    如您所见,在 componentDidMount()我设置了事件监听器,然后在渲染中设置了 <div id='headerLogoContainer'>作为我的 brandComponent 的一部分.我看到 brandComponent成功渲染到 DOM,但在第一次滚动(向下)时,它会锁定屏幕(在 Chrome 中)或不显示 logoalt马上(在 Edge 和 Firefox 中)。几秒钟后图像切换,然后我可以向上或向下滚动,毫无问题地切换它。这让我认为这可能是一个预加载问题,但为什么当我在 brandComponent 中预加载图像时会出现这种情况?并在 DOM 中查看它。没有发出额外的网络请求,只需切换 hide要显示的图像。

    所以我的问题是,如何根据滚动事件更改 React 中的图像源,而不会出现延迟或卡住滚动位置?

    编辑:

    我已经根据建议的答案更改了我的代码以利用内部状态,并且当图像更改时它仍然具有相同的延迟效果:
    class Header extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    mobileOpen: false,
    logoaltState: false
    };
    this.handleDrawerToggle = this.handleDrawerToggle.bind(this);
    this.headerColorChange = this.headerColorChange.bind(this);
    }
    handleDrawerToggle() {
    this.setState({ mobileOpen: !this.state.mobileOpen });
    }
    componentDidMount() {
    if (this.props.changeColorOnScroll) {
    window.addEventListener("scroll", this.headerColorChange);
    }
    }
    headerColorChange() {
    console.log("Scroll Fire!");
    const { classes, color, changeColorOnScroll} = this.props;
    const windowsScrollTop = window.pageYOffset;
    if (windowsScrollTop > changeColorOnScroll.height) {
    document.body
    .getElementsByTagName("header")[0]
    .classList.remove(classes[color]);
    document.body
    .getElementsByTagName("header")[0]
    .classList.add(classes[changeColorOnScroll.color]);
    this.setState({ logoaltState: true });
    } else {
    document.body
    .getElementsByTagName("header")[0]
    .classList.add(classes[color]);
    document.body
    .getElementsByTagName("header")[0]
    .classList.remove(classes[changeColorOnScroll.color]);
    this.setState({ logoaltState: false });
    }
    }

    然后在我的渲染中......
    render() {
    const {
    classes,
    color,
    rightLinks,
    leftLinks,
    brand,
    logo,
    logoalt,
    fixed,
    absolute
    } = this.props;
    const{
    mobileOpen,
    logoaltState
    } = this.state
    const appBarClasses = classNames({
    [classes.appBar]: true,
    [classes[color]]: color,
    [classes.absolute]: absolute,
    [classes.fixed]: fixed
    });
    let brandComponent;
    if(!logo){
    brandComponent = (
    <Button className={classes.title}>
    {brand}
    </Button>
    );
    }else{
    brandComponent = (
    <div id='headerLogoContainer'>
    <img className='logo' src={logo} style={{display: logoaltState === false ? "block" : "none"}}></img>
    <img className='logoalt' src={logoalt} style={{display: logoaltState === true ? "block" : "none"}}></img>
    </div>
    );
    }

    不同的代码/方法,同样的问题......

    编辑 2:

    我不认为这是这个应用程序逻辑的问题,因为正如我所提到的,它只会卡住 第一次图像/状态需要改变。我认为这是某种首次加载问题,即使我没有任何网络请求,也许我错误地包含了图像源?或者在 React 中,图像需要通过其他方法进行预加载,因为图像源在包含时会略微偏离......即 /static/media/logo.ad924167.pngrequire("assets/img/tovlogo.png" 相反我认为这是因为我的节点服务器设置,但我不太确定发生了什么,因为我对这个生态系统还很陌生……我正在使用 Material UI React Template ,这就是这个组件的来源。

    主题文件本身是这样的: https://www.creative-tim.com/product/material-kit-react?partner=104080所以我想知道它如何处理图像,考虑到实际 src 的性质与 require 不同...但是再次没有对图像的其他请求...这只是 CSS/样式更改...

    编辑 3:

    这是我的调试器(Chrome:Performance)卡住时的样子:

    debugger

    我意识到查看图像非常大的绘制时间,但不应该预加载地址......我想不是因为那是网络预加载而不是 display:none;" 的绘制预加载...也许我可以试试 opacity取而代之的是 CSS 属性,但这会使其他 CSS 复杂化……有没有更好的方法来做到这一点?

    最后编辑:

    我的图像超过 10,000 像素宽...我将它用作 Logo ,所以直到我做了性能指标才意识到它有多糟糕...我猜这就是它卡住的原因...抱歉使用react。 :(

    最佳答案

    我认为不是手动更改 DOM 元素上的类,而是利用组件状态并根据滚动位置在事件图像之间切换会更容易。

    示例

    class App extends React.Component {
    state = { active: 0 };

    componentDidMount() {
    window.addEventListener("scroll", this.handleScroll);
    }

    componentWillUnmount() {
    window.removeEventListener("scroll", this.handleScroll);
    }

    handleScroll = event => {
    const { pageYOffset } = window;
    const { active } = this.state;

    if (pageYOffset >= 500 && active === 0) {
    this.setState({ active: 1 });
    } else if (pageYOffset < 500 && active === 1) {
    this.setState({ active: 0 });
    }
    };

    render() {
    const { active } = this.state;
    return (
    <div style={{ height: 1000, width: 1000 }}>
    <div
    style={{
    height: "100%",
    width: "100%",
    backgroundColor: "red",
    display: active === 0 ? "block" : "none"
    }}
    />
    <div
    style={{
    height: "100%",
    width: "100%",
    backgroundColor: "blue",
    display: active === 1 ? "block" : "none"
    }}
    />
    </div>
    );
    }
    }

    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="root"></div>

    关于javascript - 在滚动事件上 react 更改图像源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51236524/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com