Skip to content

Instantly share code, notes, and snippets.

@hophacker
Created April 25, 2016 09:00
Show Gist options
  • Save hophacker/24060929d3d48577d0225798fdcafe56 to your computer and use it in GitHub Desktop.
Save hophacker/24060929d3d48577d0225798fdcafe56 to your computer and use it in GitHub Desktop.
Responsively show images using qiniu's image service
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