大三學生的第三個基於 React 的 3D 輪播組件

前面寫了兩篇關於 slider 組件如何實現的文章,有興趣的朋友能夠點擊這裏 原生 slider 組件的實現React slider組件的實現 查看,今天寫一篇關於 3D 輪播圖實現原理的文章。javascript

目前在找實習工做,有合適的機會但願小夥伴們多多推薦~css

正文開始

本文最終的 3D 輪播效果以下圖:html

預覽地址 源碼地址java

依然參照原來的思路,按照一個正規的項目來對待,咱們仍是按照以下過程來實現。react

  • 需求文檔
  • 設計方案
  • 編碼實現
  • 自我測試
  • 提交到 github
  • 發佈 npm 包

需求文檔

由於咱們是要實現一個 3D 輪播組件,因此不可避免地要使用一些 3D 屬性,除了在 W3CSchool 上學習,我還買了本小冊 WebGL 入門與實踐,雖然這是本講解 Webgl 的小冊,可是這本小冊也開闢了幾個章節講述 CSS3 中 3D 屬性的用法,給我帶來了一些新的思路。webpack

列舉一下咱們的需求:css3

  • 使用者傳入四張圖片,可以實現 3D 輪播效果,支持向上輪播和向下輪播的方向配置。
  • 能夠配置尺寸。
  • 能夠配置輪播持續時間。
  • 能夠配置輪播間隔時間。
  • 能夠經過 npm install 的方式安裝使用。

需求比較簡單,核心就是 3D 輪播效果。git

設計方案

產品的需求到了,那麼做爲開發人員,要開始思考如何實現產品的需求了,除此以外,還須要考慮將來產品的意圖,按照這個思路,我又想到了一些配置項,前面也講過,這些都是隱含的開發需求:github

  • 針對以上的配置要設置一個默認參數:
    • 方向配置,默認爲 1,即向上轉動。
    • 尺寸配置,默認爲父容器的尺寸。
    • 輪播持續時間,默認爲 2 秒。
    • 輪播間隔時間,默認爲 2 秒。

那麼咱們要開始寫設計方案了。web

  • 需求關鍵: 關鍵需求就是根據傳入的四張圖片實現 3D 輪播效果。
  • 視覺關鍵: 暫無。
  • 交互關鍵: 暫無。
  • 性能關鍵:這裏我目前只想到:若是圖片的尺寸過大,那麼可能還未加載出來就已經開始轉動了,須要在圖片所有加載到本地以後再開始輪播。本期暫不作優化。

具體實現

實現主要就是利用 css3 transform 屬性的 translateY 和 translateZ 值,將四張圖片經過前移後移、上移、下移組成一個圖片方盒。 拿四張 300px 高的圖片舉例。

  • 父容器要設置 transform-style 爲 preserve-3d 纔可讓子元素展現出 3D 效果:
.container{
  position: relative;
  transform-style: preserve-3d;
}
複製代碼
  • 同時子元素要上下先後平移:
.imgs:nth-child(1){
  transform: translateZ(150px);
}
.imgs:nth-child(2){
  transform: translateY(-150px)  rotateX(90deg);
}
.imgs:nth-child(3){
  transform: translateZ(-150px) rotateX(180deg);
}
.imgs:nth-child(4){
  transform: translateY(150px)  rotateX(270deg);
}
複製代碼

以上兩個簡單的設置,就能夠造成一個圖片方盒,那麼,咱們接下來要讓它輪播起來,這些代碼和上一節的 3D slider 實現原理相似,不作具體講述,你們看看源碼就很容易理解了:

import React from 'react';
import './index.css';
export default class extends React.Component {
  constructor(props) {
    super(props);
    this.index = 1;
    this.container = React.createRef();
  }
  componentDidMount () {
    // 獲取間隔時間,默認爲 2000 ms。
    const delayTime = this.props.delayTime * 1000 || 2000;
    // 獲取父容器
    let parent = this.container.current.parentNode;
    //獲取父容器的寬度
    let width = this.props.width || parent.clientWidth;
    //獲取父容器的高度。
    let height = this.props.height || parent.clientHeight;
    // 設置第一張圖片和第三張圖片的先後偏移。
    let imgs = this.container.current.children;
    imgs[0].style.transform = `translateZ(${height / 2}px)`;
    imgs[2].style.transform = `translateZ(-${height / 2}px) rotateX(180deg)`;
    // 設置輪播容器的尺寸
    this.container.current.style.width = width + 'px';
    this.container.current.style.height = height + 'px';
    // 開始輪播
    this.timer = setTimeout(this.loop.bind(this), delayTime);
    this.container.current.addEventListener('transitionend', () => {
      this.timer = setTimeout(this.loop.bind(this), delayTime);
    })
  }
  loop () {
    this.container.current.style.transform = 'rotateX(' + ((this.props.direction || 1) * this.index * 90) + 'deg)';
    this.container.current.style.transition = (this.props.transitionTime || 2) + 's';
    this.index++;
  }
  render () {
    return <div className='container' ref={this.container}>
      {this.props.imgList.map(item => {
        return <img className='img-item' src={item.src} />
      })}
    </div>
  }
}
複製代碼

自我測試

自我測試比較簡單,就是將本身做爲一個用戶來模擬使用這個組件,模擬一切可能遇到的狀況進行測試,若是有問題,再進行修復。

構建

  • 執行 npm run build 構建出可供你們引入的 index.js
  • 執行 npm run demo 構建出可供你們預覽的頁面。

提交到 git

分別將上面的構建結果提交到 github 的 master 和 gh-pages 分支。

  • git add ./
  • git commit -m '...'
  • git push origin master
  • git checkout -b gh-pages
  • git push origin gh-pages

發佈

最後一步就是發佈了,這裏也比較簡單,可是咱們要在package.json 中設置入口文件,設置 main 爲./dist/index.js 便可。

{
  "name": "react-slider3d-fjj",
  "version": "0.0.1",
  "description": "",
  "main": "./dist/index.js", 
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --mode=development",
    "demo": "webpack --config ./webpack.config.js --progress --colors",
    "build": "babel src -d dist --copy-files "
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel": "^6.23.0",
    "babel-cli": "^6.26.0",
    "babel-core": "~6.26.0",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^2.1.0",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.9.0",
    "less-loader": "^4.1.0",
    "source-list-map": "^2.0.1",
    "style-loader": "^0.23.1",
    "watchpack": "^1.6.0",
    "webpack": "^4.29.5",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  },
  "dependencies": {
    "react": "^16.8.3",
    "react-dom": "^16.8.3"
  }
}
複製代碼

小結

以上就是我作的第三個小組件,都比較簡單,因爲本人還沒有畢業,因此能力有限,但願你們多提意見,將來我還會逐漸輸出一些新的組件供你們學習~~

相關文章
相關標籤/搜索