Created
April 25, 2016 09:00
-
-
Save hophacker/24060929d3d48577d0225798fdcafe56 to your computer and use it in GitHub Desktop.
Responsively show images using qiniu's image service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {Component, PropTypes} from 'react' | |
import _ from 'lodash' | |
import ReactDOM from 'react-dom' | |
function getRatio () { | |
const multi = ['414x736', '375x667'].indexOf(`${window.innerWidth}+${window.innerHeight}`) !== -1 ? 2 : 1 | |
// iPhone6 || iPhone6p | |
return (window.devicePixelRatio || 1) * multi | |
} | |
/* | |
/0/w/<LongEdge>/h/<ShortEdge> 限定缩略图的长边最多为<LongEdge>,短边最多为<ShortEdge>,进行等比缩放,不裁剪。 | |
如果只指定 w 参数则表示限定长边(短边自适应),只指定 h 参数则表示限定短边(长边自适应)。 | |
/1/w/<Width>/h/<Height> | |
限定缩略图的宽最少为<Width>,高最少为<Height>,进行等比缩放,居中裁剪。 | |
转后的缩略图通常恰好是 <Width>x<Height> 的大小(有一个边缩放的时候会因为超出矩形框而被裁剪掉多余部分)。 | |
如果只指定 w 参数或只指定 h 参数,代表限定为长宽相等的正方图。 | |
/2/w/<Width>/h/<Height> | |
限定缩略图的宽最多为<Width>,高最多为<Height>,进行等比缩放,不裁剪。 | |
如果只指定 w 参数则表示限定宽(长自适应),只指定 h 参数则表示限定长(宽自适应)。 | |
它和模式0类似,区别只是限定宽和高,不是限定长边和短边。 | |
从应用场景来说,模式0适合移动设备上做缩略图,模式2适合PC上做缩略图。 | |
/3/w/<Width>/h/<Height> | |
限定缩略图的宽最少为<Width>,高最少为<Height>,进行等比缩放,不裁剪。 | |
如果只指定 w 参数或只指定 h 参数,代表长宽限定为同样的值。 | |
你可以理解为模式1是模式3的结果再做居中裁剪得到的。 | |
/4/w/<LongEdge>/h/<ShortEdge> | |
限定缩略图的长边最少为<LongEdge>,短边最少为<ShortEdge>,进行等比缩放,不裁剪。 | |
如果只指定 w 参数或只指定 h 参数,表示长边短边限定为同样的值。 | |
这个模式很适合在手持设备做图片的全屏查看(把这里的长边短边分别设为手机屏幕的分辨率即可),生成的图片尺寸刚好充满整个屏幕(某一个边可能会超出屏幕)。 | |
/5/w/<LongEdge>/h/<ShortEdge> 限定缩略图的长边最少为<LongEdge>,短边最少为<ShortEdge>,进行等比缩放,居中裁剪。 | |
如果只指定 w 参数或只指定 h 参数,表示长边短边限定为同样的值。 | |
同上模式4,但超出限定的矩形部分会被裁剪。 | |
*/ | |
export const ImageUtil = { | |
getTopLeftCornerPosition (clickEvent) { | |
let e = this.imageElement(clickEvent) | |
let x = 0 | |
let y = 0 | |
while (e !== null) { | |
x += e.offsetLeft | |
y += e.offsetTop | |
e = e.offsetParent | |
} | |
return { x: x, y: y } | |
}, | |
imageViewOfType (url, width, height, type, onlyWidth, onlyHeight) { | |
const ratio = getRatio() | |
const w = Math.floor(width * ratio) | |
const h = Math.floor(height * ratio) | |
let suffix = '' | |
if (onlyWidth) { | |
suffix = `/w/${w}` | |
} else if (onlyHeight) { | |
suffix = `/h/${h}` | |
} else { | |
suffix = `/w/${w}/h/${h}` | |
} | |
return `${url}?imageView2/${type}${suffix}` | |
} | |
} | |
export default class Image extends Component { | |
constructor (props) { | |
super(props) | |
this.state = { | |
src: '', | |
style: _.extend(this.props.style) | |
} | |
} | |
componentDidMount () { | |
this.setSrc() | |
} | |
componentDidUpdate (prevProps) { | |
if (this.props.src !== prevProps.src || this.props.type !== prevProps.type) { | |
this.setSrc() | |
} | |
} | |
setSrc () { | |
if (!_.isEmpty(this.props.src)) { | |
const {type, onlyWidth, onlyHeight} = this.props | |
const src = ImageUtil.imageViewOfType(this.props.src, this.width, this.height, type || 1, onlyWidth, onlyHeight) | |
const style = this.props.style | |
this.setState({ src, style }) | |
} | |
} | |
get height () { | |
return this.props.height || ReactDOM.findDOMNode(this).offsetHeight | |
} | |
get width () { | |
return this.props.width || ReactDOM.findDOMNode(this).offsetWidth | |
} | |
render () { | |
return <img {...this.props} style={this.state.style} src={this.state.src} /> | |
} | |
} | |
Image.propTypes = { | |
style: PropTypes.object, | |
className: PropTypes.string, | |
onClick: PropTypes.func, | |
src: PropTypes.string, | |
type: PropTypes.number, | |
onlyHeight: PropTypes.bool, | |
onlyWidth: PropTypes.bool, | |
height: PropTypes.number, | |
width: PropTypes.number | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment