作为一个刚开始使用react但熟悉javascript的人,我很难确切地知道在给定的react组件中应该将某些功能放在何处,并且不确定我遇到的这个问题是react逻辑的问题还是加载图像时的延迟时间,虽然如果是后者,我不理解这一点,因为我将图像预加载到一个隐藏的div中。
我期望的工作流如下:
-
加载两个图像,其中一个“预加载”
height:0
作为
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>
如你所见,在
组件didmount()
我设置事件侦听器,然后在渲染中设置
<div id='headerLogoContainer'>
作为我的一部分
brandComponent
是的。我看到了
品牌成分
成功渲染到dom,但在第一个滚动(向下)时,它锁定屏幕(在chrome中)或不显示
logoalt
马上(在edge和firefox中)。几秒钟后,图像切换,然后我可以向上或向下滚动,切换没有问题。这使我认为这可能是一个预加载问题,但为什么当我在
品牌成分
在教堂里看。没有其他网络请求,只需切换
隐藏
要显示的图像。
所以我的问题是,如何在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.png
作为反对
require("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)在冻结时的样子:
我意识到在油漆时间,图像是相当大的,但不应该预装地址…我想不是因为那是一个网络预加载不是一个油漆预加载
display:none;"
…也许我可以试试
opacity
而是css属性,但这会使其他css复杂化…总的来说有更好的方法吗?
最终编辑:
我的图像超过10000像素宽…我用它作为一个标志,所以直到我做了性能指标,才意识到它有多糟糕…我猜
这
是它冻结的原因…抱歉,反应过来。:。(