webapp之滑动组件(基于zepto)

一直都没有封装过一套移动web下的滑动组件,正巧今天公司没事,就闲下来写了一个半成品,称之为半成品是因为,循环效果暂时还没有添加。

;
(function($) {
    $.fn.slider = function(opts) {
        this.each(function() {
            init.call(this, opts);
        });
        return this;
    };

    function init(opts) {
        var defaults = {
            cont: this,
            contWidth: false, //容器宽度,默认屏幕宽
            contHeight: false, //容器高度,默认屏幕高
            dots: false,
            loop: false,
            autoplay: false,
            spacing: 5000, //自动播放间隔时长
            ifAjax: false, //ajax传图生成html,默认false
            ajaxUrl: ‘‘, //当开启ajax后,需传入用以构建的json
            ifMiddle: false //是否开启图片垂直居中
        };
        var options = $.extend({}, defaults, opts);

        var index = 0, //图片索引
            cWidth = options.contWidth ? options.contWidth : $(window).width(), //容器宽度
            cHeight = options.contHeight ? options.contHeight : $(window).height(), //容器高度
            cScale = cWidth / cHeight,
            self = this,
            currentX = 0,
            slopeSwitch = true,
            defaultSwitch = true,
            startX, startY, endX, endY, offsetX, offsetY, startTime, endTime, autoTime;

        var utils = {
            render: function() { //如果给定json,则渲染
                var hm = ‘‘,
                    ele = options.ajaxUrl,
                    eleLen = ele.length,
                    h_li = $(‘li‘),
                    i = 0;
                for (; i < eleLen; i++) {
                    hm += ‘<li>‘ + ‘<img src="‘ + ele[i].img + ‘" data-width="‘ + ele[i].width + ‘" data-height="‘ + ele[i].height + ‘" /></li>‘
                }
                $(self).html(‘<ul>‘ + hm + ‘</ul>‘)
            },
            imgResize: function() { //重置图片,把超出限制宽(高)度的图片都缩小
                var imgOriginalWidth,
                    imgOriginalHeight,
                    imgScale,
                    imgNewWidth,
                    imgNewHeight,
                    _this = this;
                $(‘li‘, self).find(‘img‘).each(function(i) {
                    imgOriginalWidth = _this.getImgWidth($(this))
                    imgOriginalHeight = _this.getImgHeight($(this))
                    imgScale = imgOriginalWidth / imgOriginalHeight
                    if (imgScale >= cScale) { //利用长宽比,计算该用宽度限制还是长度限制
                        imgNewWidth = imgOriginalWidth >= cWidth ? cWidth : imgOriginalWidth
                        $(this).attr(‘width‘, imgNewWidth)
                        $(this).attr(‘height‘, imgNewWidth / imgScale) //这里的高度一定要赋值,否则高度居中的时候获取不到值
                    } else {
                        imgNewHeight = imgOriginalHeight >= cHeight ? cHeight : imgOriginalHeight
                        $(this).attr(‘height‘, imgNewHeight)
                    }
                    $(this).parent().width(cWidth)
                    // console.log(imgScale, cScale)
                });
                if (options.ifMiddle) {
                    this.setImgMiddle()
                }
                this.setUlWidth()
            },
            setImgMiddle: function() {
                var _this = this,
                    wHeight = $(window).height(),
                    imgHeight, offsetHeight;
                $(‘li‘, self).find(‘img‘).each(function(i) {
                    imgHeight = $(this).height()
                    offsetHeight = wHeight - imgHeight
                    $(this).css(‘margin-top‘, offsetHeight / 2)
                })
            },
            getImgWidth: function(pic) {
                return pic.attr(‘data-width‘)
            },
            getImgHeight: function(pic) {
                return pic.attr(‘data-height‘)
            },
            setUlWidth: function() {
                var len = this.getElementNum();
                $(self).find(‘ul‘).width(cWidth * len)
            },
            getElementNum: function() {
                return $(self).find(‘li‘).size()
            },
            setAutoplay: function() {
                var _this = this
                if (options.autoplay) {
                    autoTime = setInterval(function() {
                        _this.goToIndex(1)
                    }, options.spacing)
                }
            },
            clearAutoplay: function() {
                var _this = this
                if (options.autoplay) {
                    clearInterval(autoTime)
                }
            },
            dotsRender: function() {
                var len = this.getElementNum(),
                    lists = ‘‘,
                    i = 0;
                for (; i < len; i++) {
                    lists += ‘<span>‘ + (i + 1) + ‘</span>‘
                }
                $(self).append(‘<div class="dots">‘ + lists + ‘</div>‘)
                this.dotsOn(0)
            },
            dotsOn: function(i) {
                var $dots = $(‘.dots‘, self).find(‘span‘)
                $dots.removeClass(‘cur‘)
                $dots.eq(i).addClass(‘cur‘)
            },
            bindEvents: function() {
                var _this = this,
                    slideEle = $(self).find(‘ul‘);
                slideEle.on(‘touchstart‘, _this.touchStart)
                slideEle.on(‘touchmove‘, _this.touchMove)
                slideEle.on(‘touchend‘, _this.touchEnd)
                this.setAutoplay()
            },
            touchStart: function(e) {
                var slideEle = $(self).find(‘ul‘),
                    nowTime = new Date();
                slopeSwitch = true;
                defaultSwitch = true;
                startTime = nowTime.getTime()
                startX = e.touches[0].pageX
                startY = e.touches[0].pageY
                slideEle.css(‘transition‘, ‘-webkit-transform 0ms ease-out‘)
                utils.clearAutoplay()
            },
            touchMove: function(e) {
                var arrX = []
                var slope = (startX - e.touches[0].pageX) / (startY - e.touches[0].pageY)
                if (defaultSwitch) { //如果判定已经为浏览器默认滚动,则跳过流程
                    if (Math.abs(slope) < 0.8 && slopeSwitch) { //slopeSwitch控制当判定为图片轮播时,slope判定失效
                        defaultSwitch = false
                    } else {
                        slopeSwitch = false
                        var slideEle = $(self).find(‘ul‘)
                        offsetX = e.touches[0].pageX - startX
                        slideEle.css(‘transform‘, ‘translate3d(‘ + (currentX + offsetX) + ‘px, 0,0)‘)
                        e.preventDefault()
                    }
                }
                // console.log(Math.abs(slope))
            },
            touchEnd: function(e) {
                if (!defaultSwitch) {
                    return false
                }
                var nowTime = new Date(),
                    duration = 0;
                endTime = nowTime.getTime()
                duration = endTime - startTime
                if (duration > 300) { //手指拨的慢
                    if (Math.abs(offsetX) >= cWidth / 2) {
                        if (offsetX < 0) {
                            utils.goToIndex(1)
                        }
                        if (offsetX > 0) {
                            utils.goToIndex(-1)
                        }
                    } else {
                        utils.goToIndex(0)
                    }
                } else { //手指划的快
                    if (offsetX < -50) {
                        utils.goToIndex(1)
                    } else if (offsetX > 50) {
                        utils.goToIndex(-1)
                    } else {
                        utils.goToIndex(0)
                    }
                }
                offsetX = 0 //当结束后,重置offsetX,避免影响后续流程
                utils.setAutoplay()
            },
            goToIndex: function(i) {
                var slideEle = $(self).find(‘ul‘),
                    len = this.getElementNum();
                currentX = 0;
                if (i > 0) {
                    index++
                    index = index >= len ? len - 1 : index
                } else if (i < 0) {
                    index--
                    index = index <= 0 ? 0 : index
                }
                currentX = -(cWidth * index)
                this.dotsOn(index)
                slideEle.css(‘transition‘, ‘-webkit-transform 150ms ease-out‘)
                slideEle.css(‘transform‘, ‘translate3d(‘ + currentX + ‘px, 0,0)‘)
            }
        };

        var initialize = (function() { //初始化
            if (options.ifAjax) {
                utils.render()
            }
            utils.imgResize()
            utils.bindEvents()
            if (options.dots) {
                utils.dotsRender()
            }
        })()
    }
})(Zepto)

其实移动端的滑动组件编写起来与电脑上的还是有很大差异的,对于手指滑动的角度问题,动画需要使用css3,还有手指快速滑动图片切换的效果等等,这些都是电脑上不会遇到的问题。由于添加了一个图片不论大小都能在content中自适应居中的效果,所以循环效果可能要晚点才能实现,另外还有一个边界时再拉动的一个减速效果,这个后期应该也会实现。等全部实现后,就详细说明下怎么实现一个滑动组件,以及会遇到的问题的处理。

ps: 要想写能用的滑动组件,千万别看慕课网的那个教程啊!!!

时间: 2024-10-17 15:08:44

webapp之滑动组件(基于zepto)的相关文章

基于zepto的插件之移动端无缝向上滚动并上下触摸滑动

该插件乃本博客作者所写,目的在于提升作者的js能力,也给一些js菜鸟在使用插件时提供一些便利,老鸟就悠然地飞过吧. 公司的移动端项目是基于zepto的,有一个页面要求文字能够无缝地不停向上滚动,但查了网上的资料,大多都是基于jquery的,虽然稍作修改就可以用于移动端,但不能实现触摸上下翻滚.所以就去了zepto的官网查看其API,却发现如果要使用zepto的swipe()方法,需要引用其已经封装好的touch.js文件,我就赶紧引用了这个js文件,可在实际测试中,官网给出的touch.js文件

基于zepto.js的模仿手机QQ空间的大图查看组件ImageView.js

调用方式 :ImageView(index,imgData)  --index参数 为图片默认显示的索引值,类型 为Number  --imaData参数 为图片url数组 ,类型为Array 使用之前要先引入 zepto.js 文件 ImageView.js具体代码如下: /* * ImageView v1.0.0 * --口袋蓝房网 基于zepto.js的大图查看 * --调用方法 ImageView(index,imgDada) * --index 图片默认值显示索引,Number --i

基于zepto的手机焦点图touchstart touchmove

基于zepto的手机焦点图,查看地址:demo (建议使用手机浏览器查看)代码如下: <!DOCTYPE HTML> <html> <head> <title>zepto实现手机网站焦点图触屏划动效果</title> <meta content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="view

iSlider手机平台JS滑动组件

iSlider手机平台JS滑动组件,无任何插件依赖.它能够处理任何元素,例如图片或者DOM元素.它有如下特性:能够自定义动画,自带的动画包括default, rotate, flip 和 depth你能够简易地添加回调函数(onslidestart, onslide, onslideend, onslidechange)我们还支持滑动衰减效果,循环效果,自动滑动效果,水平/垂直滑动.兼容主流浏览器,懒人图库推荐下载! 使用方法: 1.你需要为iSlider先新建好数据: var data = [

从零开始学android&lt;SeekBar滑动组件.二十二.&gt;

拖动条可以由用户自己进行手工的调节,例如:当用户需要调整播放器音量或者是电影的播放进度时都会使用到拖动条,SeekBar类的定义结构如下所示: java.lang.Object ? android.view.View ? android.widget.ProgressBar ? android.widget.AbsSeekBar ? android.widget.SeekBar 常用方法 public SeekBar(Context context) 构造 创建SeekBar类的对象 publi

基于Zepto的Alert提示框开源框架Tiny-Alert

项目主页:http://shootyou.github.io/Tiny-Alert/ 什么是Tiny-Alert? 这是一个基于Zepto的提示框插件,在移动端使用会有更好的效果.它被设计成是移动端原生alert和confirm提示框的更美观替代品.同时它还实现了一个loading效果.它的核心代码参考了rDailog,在它基础上适配了zepto,去掉了移动端用不到的特性,另外让它看上去更美观了. 它有如下特性: 轻量级,代码量不超过300行,压缩后仅2k. 基于zepto更适合移动端. 支持回

android滑动组件嵌套一般思路,多任务手势思路,触摸传递思路,【例】listview嵌套viewpager

在android UI开发中,我们经常会遇到这种需求: 两个支持滑动的组件,比如listview嵌套多个listview,listview的item是一个viewpager或gallary?亦或是scrollview嵌套scrollview等等. 一般情况下,你还可能需要支持如下几种功能: ¤ 两层组件都可以滑动 ¤ 不让两个组件同时滑动,或者让两个组件同时滑动并可以自己调节 ¤ 不影响底层view的子view和嵌套view的子view的点击事件 实现上述功能时,我们也经常遇到一些问题: ¤ 点

基于zepto判断mobile的横竖屏状态

借用jquery mobile中的代码,删除了一些多余的部分,简单的基于zepto的模块 var CheckOrientation = (function(){ var win = $( window ), get_orientation, last_orientation, initial_orientation_is_landscape, initial_orientation_is_default, portrait_map = { "0": true, "180&qu

基于CSS3的WEBAPP横向滑动模式演化

http://ued.ctrip.com/blog/webapp-horizontal-sliding-mode-based-on-css3-evolution.html