React 組件圖片庫的延遲加載
原文地址:http://andrewhfarmer.com/react-image-gallery/
水平有限,有誤的地方請指正
- 事實證明,用react建立一個 帶有延遲加載效果的圖片庫 非常容易,
這裏是一個單頁面的組件 僅僅只有70行代碼 包含 空行 和 註釋 - 我將帶你 一步一步 的建立這個圖片庫的組件,當你跟着寫完,就會學會啦
項目準備
- 如果你不知道如何啓動一個react項目,沒關係,下載我的項目,克隆一份到本地
就可以啦。
git clone https://github.com/ahfarmer/minimal-react-starter.git
cd minimal-react-starter
npm install
npm start
- 這項目文件有個 單一的 HelloWorld 組件,你完全可以動手編輯這個文件(HelloWorld.js)
跟着我寫項目的其餘的部分,當你保存修改的時候,瀏覽器會自動刷新。
圖庫步驟
- 1.首先,我將寫一個新的組件 起個名字 定義一個 屬性(propTypes);
import React from 'react';
//組件名稱一定要大寫
class Gallery extends React.Component {
// 效果代碼寫在這裏
}
Gallery.propTypes = {
imageUrls: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
};
export default Gallery; //導出圖庫
這裏 只用到一個屬性:一個 imgUrl(圖片路徑) 的【數組】!!!
正確的使用 React PropTypes(定義屬性的類型) 能夠節省大量的調試時間,
比如,你的圖庫組件傳遞的不是字符串數組,
那麼,控制檯就清晰的看到 警告提示性的文字。
不要省略 React.PropTypes.object or React.PropTypes.any!!!
- 2.我們寫一一些圖片地址到 組件中(index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import Gallery from './Gallery';
let urls = [
'/react-image-gallery/img/cat1.jpg',
'/react-image-gallery/img/cat2.jpg',
'/react-image-gallery/img/cat3.jpg',
];
ReactDOM.render(
<Gallery imageUrls={urls}/>,
document.getElementById('mount')
);
如果你不喜歡這些 小貓的圖片,可以替換成你喜歡的美圖,
添加多少張都行
圖庫的渲染
- 1.到目前爲止,還不能顯示出來,我們要編譯一下render()中的代碼
import React from 'react';
class Gallery extends React.Component {
renderImage(imageUrl) {
return (
<div>
<img src={imageUrl} />
</div>
);
}
render() {
return (
<div className="gallery">
<div className="images">
{this.props.imageUrls.map(imageUrl => this.renderImage(imageUrl))}
</div>
</div>
);
}
}
// 定義屬性值的類型 必須爲 字符串組成的數組
Gallery.propTypes = {
imageUrls: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
};
export default Gallery;
我的代碼都儘量用最新的語法(最簡潔和可讀的 es6)
- ok,我會用2種方式,在render()中用 div 包裹 調用 renderImage 每次加載一個 imgurl(圖片地址)
我們將使用 es中的 Array.prototype.map() 來生成數組類型的dom節點
- ok,我會用2種方式,在render()中用 div 包裹 調用 renderImage 每次加載一個 imgurl(圖片地址)
添加延遲圖片
- 如果圖片已經加載成功,如果沒有 旋轉加載的小圖標,用戶看到空白的圖片效果很糟糕,所以接下來我們就添加
小圖標, 只需要4步
1.添加狀態state
- 首先,組件需要跟蹤 圖片加載的 狀態,顯示默認爲小圖標。
- 在 cunstructor中設置默認狀態,默認爲true,當組件第一次渲染成功時候就加載圖片。
constructor(props) {
super(props);
this.state = {
loading: true,
};
}
2.顯示小圖標
- 當圖片的狀態爲加載中時,就顯示。
- 創建一個 圖片加載的方法 randerSpinner()
- 在你的 rnder() 方法中調用它就可以了
//封裝 圖片正在加載:
renderSpinner() {
if (!this.state.loading) {
// Render nothing if not loading
return null;
}
return (
<span className="spinner" />
);
}
// render()中的代碼爲:
render() {
return (
<div className="gallery">
{this.renderSpinner()}
<div className="images">
{this.props.imageUrls.map(imageUrl => this.renderImage(imageUrl))}
</div>
</div>
);
}
此時,你會在頁面中看到圖標一直在加載。。。
3.通過onLoad 和 onError 來加載
- 接下來我們將添加 onload 和 onError 事件來監控圖片加載成功獲至失敗
- 添加這些屬性到你的圖片標籤上
onload = {this.handleStateChange.bind(this)}
onError = {this.handleStateChange.bind(this)}添加 事件到組件中
handleStateChange() {
// In React 0.13 use: 'this.refs.gallery.getDOMNode()'
const galleryElement = this.refs.gallery;
this.setState({
loading: !imagesLoaded(galleryElement),
});
}
接下來 我們要 寫一個 imageLoader() 方法,括號中接收一個參數,當加載成功,返回一個true.
獲取圖庫 元素的DOM節點 的用ref ,在 render()中寫入就可以啦.
<div className="gallery" ref="gallery">
獲取。用 this.refs.gallery
4.檢測所有的圖片是否加載完成
imageLoader()方法 不依賴任何組件,所有我們直接在組件外部定義它就好了。
function imagesLoaded(parentNode) {
const imgElements = parentNode.querySelectorAll('img');
for (const img of imgElements) {
if (!img.complete) {
return false;
}
}
return true;
}
完整的代碼
import React from 'react';
/**
* Given a DOM element, searches it for <img> tags and checks if all of them
* have finished loading or not.
* @param {Element} parentNode
* @return {Boolean}
*/
function imagesLoaded(parentNode) {
const imgElements = parentNode.querySelectorAll('img');
for (const img of imgElements) {
if (!img.complete) {
return false;
}
}
return true;
}
class Gallery extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
};
}
handleImageChange() {
// In React 0.13 use: 'this.refs.gallery.getDOMNode()'
const galleryElement = this.refs.gallery;
this.setState({
loading: !imagesLoaded(galleryElement),
});
}
renderSpinner() {
if (!this.state.loading) {
return null;
}
return (
<span className="spinner" />
);
}
renderImage(imageUrl) {
return (
<div>
<img
src={imageUrl}
onLoad={this.handleImageChange.bind(this)}
onError={this.handleImageChange.bind(this)}
/>
</div>
);
}
render() {
return (
<div className="gallery" ref="gallery">
{this.renderSpinner()}
<div className="images">
{this.props.imageUrls.map(imageUrl => this.renderImage(imageUrl))}
</div>
</div>
);
}
}
Gallery.propTypes = {
imageUrls: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
};
export default Gallery;