216 lines
5.2 KiB
JavaScript
216 lines
5.2 KiB
JavaScript
/**
|
||
* 包裹层
|
||
* 储存主要状态,组织架构
|
||
**/
|
||
|
||
// React Libs
|
||
import React from 'react'
|
||
import ReactDOM from 'react-dom'
|
||
// Style
|
||
import './index.less'
|
||
// Components
|
||
import Position from '../Position'
|
||
import Control from '../Control'
|
||
import Image from '../Image'
|
||
import Background from '../Background'
|
||
|
||
import {addListenEventOf, removeListenEventOf} from '../../utils'
|
||
|
||
class Wrapper extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
|
||
this.state = {
|
||
// 显示
|
||
show: false,
|
||
// 缩放
|
||
zoom: false,
|
||
// 当前页数
|
||
page: props.page || 0
|
||
}
|
||
}
|
||
|
||
componentWillReceiveProps(nextProps) {
|
||
if (this.props.page != nextProps.page) {
|
||
this.setState({page: nextProps.page});
|
||
}
|
||
}
|
||
|
||
componentWillMount() {
|
||
// 延迟 100 毫秒加载自己,保证动画正常
|
||
setTimeout(this.mountSelf, 50)
|
||
}
|
||
|
||
componentWillUnmount() {
|
||
removeListenEventOf('keydown', this.handleKeyDown)
|
||
removeListenEventOf('wheel', this.handleWheelScroll)
|
||
}
|
||
|
||
/**
|
||
* 加载器
|
||
**/
|
||
mountSelf = () => {
|
||
const {coverNodeRef} = this.props
|
||
// 隐藏封面原图
|
||
// if (coverNodeRef) coverNodeRef.style.visibility = 'hidden'
|
||
// 显示并绑定事件
|
||
this.setState({show: true}, () => {
|
||
addListenEventOf('keydown', this.handleKeyDown)
|
||
addListenEventOf('wheel', this.handleWheelScroll)
|
||
})
|
||
}
|
||
unmountSelf = () => {
|
||
const {coverNodeRef} = this.props
|
||
const {page} = this.state
|
||
// 显示封面原图(当前不为第一页时,遮罩从上方移除会迅速露出,需要立即显示,否则交由图片层处理)
|
||
if (coverNodeRef && page !== 0) coverNodeRef.style.visibility = 'visible'
|
||
this.setState({show: false})
|
||
}
|
||
|
||
/**
|
||
* 事件处理
|
||
**/
|
||
handleKeyDown = (e) => {
|
||
// 阻止默认事件
|
||
e.preventDefault()
|
||
const {imageSet} = this.props
|
||
const {zoom} = this.state
|
||
const hasImageSet = imageSet && imageSet.constructor === Array
|
||
const toPrevPage = this.handleSwitchPages("prev")
|
||
const toNextPage = this.handleSwitchPages("next")
|
||
switch (e.key) {
|
||
case "ArrowLeft":
|
||
// 上一张
|
||
!zoom && toPrevPage()
|
||
break
|
||
case "ArrowRight":
|
||
// 下一张
|
||
!zoom && hasImageSet && toNextPage()
|
||
break
|
||
case " ":
|
||
// 缩放
|
||
this.handleToggleZoom()
|
||
break
|
||
case "Escape":
|
||
// 退出
|
||
zoom ? this.handleToggleZoom() : this.unmountSelf()
|
||
break
|
||
default:
|
||
return
|
||
}
|
||
}
|
||
handleWheelScroll = (e) => {
|
||
this.state.show && this.unmountSelf()
|
||
}
|
||
|
||
/**
|
||
* 翻页控制
|
||
**/
|
||
handleSwitchPages = (direction) => {
|
||
return () => {
|
||
const {imageSet} = this.props
|
||
const {page} = this.state
|
||
this.setState({
|
||
page: direction === "prev" ?
|
||
Math.abs(imageSet.length + page - 1) % imageSet.length :
|
||
(page + 1) % imageSet.length
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 缩放控制
|
||
**/
|
||
handleToggleZoom = () => {
|
||
this.setState({
|
||
zoom: !this.state.zoom
|
||
})
|
||
}
|
||
|
||
render() {
|
||
const {coverNodeRef, imageSet, remove} = this.props
|
||
const {show, zoom, page} = this.state
|
||
return (
|
||
<div className="wrapperLayer">
|
||
{/*控制层*/}
|
||
<Control
|
||
show={show}
|
||
zoom={zoom}
|
||
page={page}
|
||
imageSet={imageSet}
|
||
unmountSelf={this.unmountSelf}
|
||
toggleZoom={this.handleToggleZoom}
|
||
switchPages={this.handleSwitchPages}
|
||
/>
|
||
|
||
{/*位移控制层*/}
|
||
<Position
|
||
show={show}
|
||
zoom={zoom}
|
||
page={page}
|
||
imageSet={imageSet}
|
||
coverNodeRef={coverNodeRef}
|
||
>
|
||
{/*图片层*/}
|
||
<Image
|
||
show={show}
|
||
zoom={zoom}
|
||
page={page}
|
||
imageSet={imageSet}
|
||
coverNodeRef={coverNodeRef}
|
||
remove={remove}
|
||
/>
|
||
</Position>
|
||
|
||
{/*背景层*/}
|
||
<Background
|
||
show={show}
|
||
unmountSelf={this.unmountSelf}
|
||
toggleZoom={this.handleToggleZoom}
|
||
/>
|
||
|
||
</div>
|
||
)
|
||
}
|
||
}
|
||
|
||
// 主动调用显示,插入控件到指定节点(Body末端)
|
||
const showImage = ({id, lazyLoad, indicator, imageSet, page}) => {
|
||
|
||
// 封面节点
|
||
const coverNodeRef = document.getElementById(id)
|
||
|
||
// 容器节点
|
||
const wrapperNodeId = `zmage-wrapper`
|
||
const previousOverlayNode = document.getElementById(wrapperNodeId)
|
||
previousOverlayNode && previousOverlayNode.remove()
|
||
const wrapperNode = document.createElement('div')
|
||
wrapperNode.id = wrapperNodeId
|
||
document.body.appendChild(wrapperNode)
|
||
const wrapperNodeRef = document.getElementById(wrapperNodeId)
|
||
|
||
//移除函数
|
||
const remove = () => {
|
||
ReactDOM.unmountComponentAtNode(wrapperNodeRef)
|
||
wrapperNodeRef.remove()
|
||
}
|
||
|
||
// 插入容器节点
|
||
wrapperNodeRef && ReactDOM.render(
|
||
<Wrapper
|
||
coverNodeRef={coverNodeRef}
|
||
lazyLoad={lazyLoad}
|
||
indicator={indicator}
|
||
imageSet={imageSet}
|
||
remove={remove}
|
||
page={page}
|
||
/>, wrapperNodeRef)
|
||
|
||
// 对于函数调用模式,返回容器节点引用, 调用 remove() 即可移除(无动画)
|
||
return {
|
||
node: wrapperNodeRef,
|
||
remove: remove
|
||
}
|
||
}
|
||
|
||
export {showImage, Wrapper} |