突發奇想,給滾動的banner,每個圖片的頂部都加上一個和當前banner圖片搭配的具備背景色的色條,這樣作能夠在不改變圖片規格的狀況下在移動端作到沉浸式。javascript
swiper 4.0 / react / canvascss
大體思路是使用canvas在背後依次加載每一張圖片,而後獲取每一張圖片左上角的第一個像素值,以此做爲色條的背景色。html
App.js import React, { Component } from 'react'; import Banner from './Banner.js'; import banners from '../public/banner.json'; class App extends Component { constructor(props) { super(props) this.state = { banners: [] } this.colorCache = JSON.parse(localStorage.getItem('bannerColor')) || {} // 有緩存直接使用 } componentDidMount() { this.processBanners(banners) } processBanners(banners) { const that = this; const canvasDom = document.getElementById("cavans") const context = canvasDom.getContext('2d') const imgPromises = [] for (let i = 0, j = banners.length; i < j; i++) { if (this.colorCache[banners[i].imgUrl]) continue // 有緩存直接使用,避免重複計算 const imgObj = new Image() imgObj.crossOrigin = "Anonymous" // 容許跨域加載給canvas使用 imgObj.src = banners[i].imgUrl imgPromises.push(imageLoad(imgObj, banners[i])) } Promise.all(imgPromises).then(values => { for (let i = 0, j = values.length; i < j; i++) { const { img, banner } = values[i] context.drawImage(img, 0, 0); const colors = context.getImageData(0, 0, 1, 1); // 取出圖片左上角第一個像素值 const colorStr = `rgba(${[colors.data[0], colors.data[1], colors.data[2], colors.data[3]].join(',')})`; this.colorCache[banner.imgUrl] = colorStr // 把計算出的色值,以圖片url爲key,存儲到緩存中 banner.bgColor = colorStr // banner數據中新增bgColor屬性,代表背景色 } localStorage.setItem('bannerColor', JSON.stringify(this.colorCache)) that.setState({ banners }) }) } render() { return ( <div> <canvas id="cavans" style={{display: 'none'}}/> <Banner res={this.state.banners} colorCache={this.colorCache} /> </div> ); } } // 使用promise封裝的加載圖片的方法,便於併發load圖片 function imageLoad(imgObj, banner) { return new Promise((resolve, reject) => { imgObj.onload = function () { const img = this; resolve({ img, banner }) } }) } export default App;
Banner.js import React, { Component } from 'react'; import Swiper from 'swiper'; import "../node_modules/swiper/dist/css/swiper.min.css" class Banner extends Component { constructor(props) { super(props); this.bannerContainerRef = React.createRef(); } componentDidUpdate() { // 經過判斷document中是否存在swiperContainer DOM,來初始化swiper if (this.bannerContainerRef) { this.initSwiper() } } initSwiper() { new Swiper(".swiper-container", { direction: "horizontal", autoplay: true }) } render() { // 沒有banner數據時,顯示loading信息 if (!this.props.res.length) return <div>Loading....</div> return <div className="swiper-container" ref={this.bannerContainerRef}> <div className="swiper-wrapper"> { this.props.res.map(banner => { return ( <div className="swiper-slide" key={banner._id}> <div style={{ backgroundColor: this.props.colorCache[banner.imgUrl] }}>header</div> <img width="100%" alt={banner.name} src={banner.imgUrl} /> </div> ) }) } </div> </div> } } export default Banner;
banner.json [{ "_id": "5d5539521848690226d12555", "imgUrl": "./picture1.png", "name": "picture1.png" }, { "_id": "5d561fb6184869336dd12661", "imgUrl": "./picture2.png", "name": "picture2.png" }, { "_id": "5d552c1218486991f2d124c3", "imgUrl": "./picture3.png", "name": "picture3.png" }]
感謝閱讀,轉載請註明出處。
下期會講解 前端的緩存實現方式,喜歡閱讀的朋友能夠關注個人公衆號:雨茗良記,每週會按期更新文章哦,包括但不限於技術。
我是雨茗良記,一個愛作飯的程序猿😜
前端