项目中要做图片查看器的需求,需要支持滑动切换上下张、手势缩放、双击放大等功能,用iScroll来实现是比较理想的方案。有以下几点需要注意:

  1. 页面要禁用缩放。(user-scalable=no)。
  2. 处于缩放状态时,滑动操作不要切换图片。可以通过图片元素的getBoundingClientRect方法判断。
  3. 自行给图片元素绑定touch事件,而不用iScroll的onScrollStart(Move、End)。避免在zoom状态切换时zoom状态判断出错。

下面贴出代码:

html

<pre><code>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0;">
    <meta charset="utf-8"/>
    <title></title>
    <script src="./iScroll.js" type="text/javascript"></script>
    <script src="./imageViewer.js" type="text/javascript"></script>
</head>
<body>
    <div id="wrapper">
        <img id="image" src="" alt="" title="" style="width:100%;height:100%;" />
    </div>
</body>
<script type="text/javascript">
    var wrapperEl = document.querySelector("#wrapper");
    var imageEl = document.querySelector("#image");
    new ImageViewer({
        wrapperEl:wrapperEl,
        imageEl:imageEl,
        totalImageCount:8,        
        getImageSrcByIndex:function(index) {
            return "./frl.action" + index + ".jpg";
        },
        minScrollDistance:30
    });
</script>
</html>

</code></pre>

js
<pre><code>
/*
 *图片查看器组件
 */


/*图片查看器参数定义
interface IImageViewerOptions{
    wrpperEl:HTMLElement;                               图片元素的父元素
    imageEl:HTMLImageElement;                           图片元素DOM对象
    totalImageCount:number;                             需要展示的图片总数
    getImageSrcByIndex:(index:number)=>string;          按索引值获取图片地址
    minScrollDistance?:number;                          触发切换图片的最小滚动距离
    onloadingImage?:()=>void;                           加载图片时要执行的操作,比如加些loading效果什么的
    onloaded?:()=>void;                                 图片加载完成时要执行的操作,比如取消loading效果什么的
}*/
</code></pre>
<code>
function ImageViewer(options) {
    this.imageEl = options.imageEl;
    this.initialize(options);
}

ImageViewer.prototype = {

    initialize:function(options) {
        this.options = options;
        this.currentImageIndex = 0;
        this.imageEl.src = this.options.getImageSrcByIndex(this.currentImageIndex);
        this.initEvents();
    },

    initEvents:function() {
        var self = this;

        if (!this.isSupportTouchEvents()) {
            this.initClickEvents();
        } else {
            this.initTouchEvents();
        }

        //图片加载成功后设置下当前图片相对视窗的初始信息
        this.imageEl.onload = function() {
            self.initBoundingRectInfo = this.getBoundingClientRect();   
            self.options.onloadedImage && self.options.onloadedImage();
        }
    },

    initClickEvents:function() {
        var self = this;

        this.imageEl.onclick = function(e) {
            var eventX = e.pageX;
            var boundingRectInfo = this.getBoundingClientRect();
            boundingRectInfo.width = boundingRectInfo.width || (boundingRectInfo.right - boundingRectInfo.left);

            var isClickedLeft = (eventX - boundingRectInfo.left) < (boundingRectInfo.width /2);

            var delta = isClickedLeft ? -1 : 1;
            self.loadAdjacentImage(delta);

        };
    },

    initTouchEvents:function() {
        var self = this;

        this.minScrollDistance = this.options.minScrollDistance || 20;
        new iScroll(this.options.wrapperEl,{
            zoom: true,
            zoomMin: 1,
            zoomMax: 4,
            doubleTapZoom: 2,
            useTransition: true,
            checkDOMChanges: false,
            hScrollbar: false,
            vScrollbar: false
            /*onZoomStart: function() {
                return false;
            },
            onScrollStart:function(e) {
                self.touchStartX = e.touches[0].pageX;
            },
            onScrollMove: function(e) {
                self.touchMoveX = e.touches[0].pageX;
            },
            onScrollEnd: function() {
                if(self.isImageZoomed()){
                    return;
                }
                var moveDistance = self.touchMoveX - self.touchStartX;
                if (Math.abs(moveDistance) < self.options.minScrollDistance) {
                    return;
                }
                var delta = moveDistance > 0 ? -1 : 1;
                self.loadAdjacentImage(delta);
            }*/
        });
        //双击放大,再双击还原后会触发onScrollEnd,此时this.isImageZoomed()为false;会去加载下一张。
        //不如自己绑定touch事件。

        this.imageEl.ontouchstart = function(e) {
            self.touchStartX = e.touches[0].pageX;
        };

        this.imageEl.ontouchmove = function(e) {
            self.isMoving = true;
            self.touchMoveX = e.touches[0].pageX;
        };

        this.imageEl.ontouchend = function() {
            if (self.isMoving && !self.isImageZoomed()) {
                var moveDistance = self.touchMoveX - self.touchStartX;
                if (Math.abs(moveDistance) < self.options.minScrollDistance) {
                    return;
                }
                var delta = moveDistance > 0 ? -1 : 1;
                self.loadAdjacentImage(delta);
                self.isMoving = false;
            }
        }
    },

    /*
     *加载相邻的一张图片
     */
    loadAdjacentImage:function(delta) {
        var targetIndex = this.currentImageIndex + delta;
        if (targetIndex < 0 || targetIndex > this.options.totalImageCount) {
            return;
        }
        this.imageEl.src = this.options.getImageSrcByIndex(targetIndex);
        this.currentImageIndex += delta;
        this.options.onloadingImage && this.options.onloadingImage();
    },

    /*
     *判断图片是否处于缩放状态
     */
    isImageZoomed: function() {
        var boundingRectInfo = this.imageEl.getBoundingClientRect();   

        for(var key in boundingRectInfo){
            if(['top','bottom','right','left'].indexOf(key) > -1){
                if (boundingRectInfo[key] !== this.initBoundingRectInfo[key]) {
                    return true;
                }
            }
        }
        return false;
    },

    /*
     *判断是否是触摸设备
     */
    isSupportTouchEvents:function() {
        return document.hasOwnProperty("ontouchstart");
    }
}
</code>

泡泡
1.6k 声望63 粉丝

« 上一篇
爬坑记
下一篇 »
数组的flatten

引用和评论

0 条评论