/** * 包裹层 * 储存主要状态,组织架构 **/ // 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 (
{/*控制层*/} {/*位移控制层*/} {/*图片层*/} {/*背景层*/}
) } } // 主动调用显示,插入控件到指定节点(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( , wrapperNodeRef) // 对于函数调用模式,返回容器节点引用, 调用 remove() 即可移除(无动画) return { node: wrapperNodeRef, remove: remove } } export {showImage, Wrapper}