图片引入
react组件里面需要引入本地图片,按照通常的方式,
<img src="../../assets/images/default-avatar.jpg"/>
引入肯定是不行的。
react提供的引用本地图片的方式:
1. 通过import引入
import defaultAvatar from '../../assets/images/default-avatar.jpg'
...
<img src={defaultAvatar}/> //img中直接使用变量即可
这种引入方式,webpack把当前图片当做资源文件打包,可以自己在配置文件里面设置图片加载器,小于多少kb用base64的格式打包;当大于指定kb时,webpack会把当前图片也编译到打包目录下面。
2. 使用require引入
<img src={require("../../assets/images/default-avatar.jpg")}/>
这种方式,可以在css文件里面使用,因为css-loader会把资源文件一起打包,而在js文件中这样引入,webpack只会把当前的src当做字符串,并不会当做资源文件去处理;当项目打包到线上时,就会出现资源文件路劲找不到的问题。
按照这个说法,本地应该还是可以使用这种引入方式,但是这个方法,在我自己的本地项目里面使用时,
img标签的src里面显示的是这样的一个值。
查询之后了解到,使用create-react-app创建了react项目,使用require引入图片文件时,require返回的是一个ES模块,而不是字符串。这是因为在file-loader中,esModule是默认启动的。
所以这种方式需要改写为
const imgSrc = require("../assets/image/whitehouse.jpeg").default;
<img src={imgSrc}/>
不过这种方法,打包的时候还是可能会存在路径找不到的问题,还是建议使用import来引入本地图片。
图片懒加载
既然要加载图片,那么当页面上存在大量图片的时候,就存在需要懒加载图片的问题。
1. 监听window.scroll事件
定义lazyLoad方法,监听window.scroll事件。
import defaultAvatar from '../../assets/images/default-avatar.jpg'
...
componentDidMount() {
window.addEventListener('scroll', this.lazyLoad)
}
componentWillUnmount() {
window.removeEventListener('scroll', this.lazyLoad);
}
lazyLoad(){
this.setState({imgSrc:defaultAvatar})
}
render(){
return <img src={this.state.imgSrc}/>
}
不过这种方式,只要页面开始滚动,就会加载图片。页面上加载的图片较多时,就没有了优势。
2. 使用getBoundingClientRect Scroll + with Throttle + DataSet API
引入一个新的API Element.getBoundingClientReact() 方法返回元素的大小及其相对于视口的位置。
img.getBoundingClientRect().top < document.documentElement.clientHeight
监听window.scroll的事件优化一下,加个节流器提高性能。lodash
import _ from 'lodash';
import throttle from 'lodash/throttle';
...
constructor(props){
super(props);
this.lazyLoad = _.throttle(this.lazyLoad.bind(this), 300);
this.lazyLoad = throttle(this.lazyLoad.bind(this), 300);
}
3. 使用html5的IntersectionObserver API监听元素是否到了当前视口。
constructor(){
this.myRef = React.createRef();
}
componentDidMount() {
const observer = new IntersectionObserver((changes) => {
changes.forEach(change => {
if (change.isIntersecting) {
this.myRef.current.src = this.props.imgSrc;
observer.unobserve(this.myRef.current);
}
});
});
observer.observe(this.myRef.current);
}
...
render() {
return <div className="img-wrapper">
<img src={this.state.imgSrc} ref={this.myRef} data-src={this.state.imgSrc} loading="lazy"/>
</div>
}
4. LazyLoading属性
<img src="imgSrc" loading="lazy">
兼容性不太好,慎用。
react获取DOM元素
这里补充一个react获取dom元素的方法
- 原生js获取dom元素,ById ByClassName querySelector等
- react 自带的 refs 方式 这个官方推荐使用 但不建议使用在事件源上面
- 事件对象 event 来使用 通常用于事件源
参考链接