React 組件圖片庫的延遲加載

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)

    1. ok,我會用2種方式,在render()中用 div 包裹 調用 renderImage 每次加載一個 imgurl(圖片地址)
      我們將使用 es中的 Array.prototype.map() 來生成數組類型的dom節點

添加延遲圖片

  • 如果圖片已經加載成功,如果沒有 旋轉加載的小圖標,用戶看到空白的圖片效果很糟糕,所以接下來我們就添加
    小圖標, 只需要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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章