zoukankan      html  css  js  c++  java
  • Omi-touch实战 移动端图片轮播组件的封装

    pc端的轮播,移动端的轮播都很常见。一年前,我还为手机端没有左滑,右滑事件从而封装了一个swipe库,可以自定义超过多少滑动时间就不触发,也可以设置滑动多少距离才触发,这一个功能的代码就达到400多行了,当我遇到finger.js后,就直接抛弃自己写的那个库了。

    扯了那么多,是时候进入正题,这里用touch插件来写一个轮播组件的封装。

    使用姿势如下:

            var banner = new Banner({
                images: ['ci5.jpg', 'ci6.jpg', 'ci7.jpg', 'ci8.jpg'],
                title: ['原来你不爱我-威仔', '八年的爱', '终结敷衍', '我也憧憬过'],
                defaultIndex: 2,
                imgPath: './images/',
                style: {
                    height: '210px',
                }
            });
    
            setTimeout(() => {
                banner.setData({
                    images: ['47.jpg', '48.jpg', '49.jpg'],
                    title: ['怪我', '异性朋友', '我很快乐'],
                    defaultIndex: 3,
                    imgPath: './images/',
                    style: {
                        height: '220px',
                        top: '10%'
                    }
                })
            }, 1000);

    说明:实例化轮播对象时,可以传入数据。

            images: 图片名,

            title: 标题,

            defaultIndex: 轮播默认显示第几个图,

            imgPath: 图片的路径(为了你方便少写点重复的路径名),

            style: 样式, height:指轮播图的高度, top指轮播距离屏幕顶部的距离,单位随意,可以px, rem, %.

    有时候换数据,则使用实例的setData方法,传入参数即可,轮播会自己换数据和title.

    来看看具体实现:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>touch_banner</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
        </style>
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
    </head>
    <body>
        <script src="../src/omi_soda.js"></script>
        <script>
            Omi.OmiTouch.init();
            class Banner extends Omi.Component {
                constructor(data) {
                    super(data);
                    this.bannerVar = {
                        aA: null,
                        at: null,
                        tickId: null
                    };
                    this.data.imgWidth = this.data.imgCount = this.data.divWidth = this.data.minValue = 0;
                    this.setData(null, true);
                }
    
                installed() {
                    this.bannerVar.aA = this.refs.aTagDiv.getElementsByTagName('a');
                    this.fixDefaultIndexImage();
                    this.fixStyle();
                }
    
                setData(option, first) {
                    clearInterval(this.bannerVar.tickId);
                    option = option || this.data;
                    if (option.imgPath) {
                        option.images = option.images.map(function(imgDom) {
                            return option.imgPath + imgDom;
                        });
                    };
                    this.data.title = option.title;
                    this.data.images = option.images;
                    this.data.style = option.style;
                    if (option.defaultIndex >= 0 && option.defaultIndex <= option.images.length - 1) {
                        this.data.defaultIndex = option.defaultIndex;
                    } else {
                        this.data.defaultIndex = 0;
                    };
                    this.data.imgCount = option.images.length;
                    this.data.imgWidth = 100 / this.data.imgCount;
                    this.data.divWidth = 100 * this.data.imgCount;
                    this.data.minValue = -(window.innerWidth) * (this.data.imgCount - 1);
                    this.touch && (this.touch.min = -(window.innerWidth) * (this.data.imgCount - 1));
    
                    if (!first) {
                        banner.update();
                        this.fixDefaultIndexImage();
                        this.fixStyle();
                    };
                }
    
                fixDefaultIndexImage() {
                    this.touch.currentPage = this.data.defaultIndex;
                    this.touch.to(- (this.touch.currentPage)*(this.touch.step));
                    this.animationEnd();
                    this.loop();
                }
    
                fixStyle() {
                    if (this.data.style && this.data.style.top) this.refs.carousel_container.style.top = this.data.style.top;
                    if (this.data.style && this.data.style.height) {
                        var aImg = Array.prototype.slice.call(this.refs.scroller.getElementsByTagName('img'));
                        aImg.forEach(function(img) {
                            img.style.height = this.data.style.height;
                        }, this);
                    };
                }
    
                style() {
                    return `
                        .carousel_container {
                            position: absolute;
                            top: 0%;
                        }
                        .carousel {
                            overflow: hidden;
                            position: relative;
                        }
                        .carousel_div {
                            position: relative;
                            font-size: 0;
                        }
                        .nav {
                            position: absolute;
                            bottom: .3rem;
                            right: .5rem;
                        }
                        .nav a {
                            display: inline-block;
                             6px;
                            height: 6px;
                            background: #ffffff;
                            cursor: pointer;
                            -moz-border-radius: 5px;
                            -webkit-border-radius: 5px;
                            border-radius: 5px;
                            border: 1px solid #808080;
                            transition: all .5s ease-in;
                            margin: 0 .15rem;
                        }
                        .nav a.active {
                            background-color: #ffd800;
                             10px;
                        }
                        .title {
                            position: absolute;
                            bottom: .0rem;
                            left: .3rem;
                            color: #fff;
                             auto;
                            height: 1.8rem;
                            line-height: 1.8rem;
                            font-size: 15px;
                            /*background: red;*/
                        }
                    `;
                }
    
                touchStart() {
                    clearInterval(this.bannerVar.tickId);
                }
    
                touchEnd(evt, v, index) {
                    var value = -(this.touch.step * index);
                    var dt = v - value;
                    // console.log(dt);
    
                    if (v > this.touch.max) {    // 属性值大于最大值取最大值
                        this.touch.to(this.touch.max);
                        /*this.touch.target.translateX = this.touch.min + this.touch.step;
                         this.touch.to(this.touch.min);*/
                    } else if (v < this.touch.min) {    // 属性值小于最小值取最小值
                        this.touch.to(this.touch.min);
                        /*this.touch.target.translateX = -this.touch.step;
                         this.touch.to(this.touch.max);*/
                    } else if (Math.abs(dt) < 30) {    // 2边空隙小于30就回到当前值
                        this.touch.to(value);
                    } else if (dt > 0) {    // 大于0往右边滚动一个
                        this.touch.to(value + this.touch.step);
                    } else {    // 小于0就往左边滚动一个
                        this.touch.to(value - this.touch.step);
                    };
                    this.loop();
                    return false;
                }
    
                animationEnd(v) {
                    Array.prototype.slice.call(this.bannerVar.aA).forEach(function(item) {
                        item.className = '';
                    });
                    this.bannerVar.aA[this.touch.currentPage].className = 'active';
                    this.refs.title.innerHTML = this.data.title[this.touch.currentPage];
                }
    
                // 循环播放
                loop() {
                    this.bannerVar.tickId = setInterval(function() {
                        this.touch.currentPage += 1;
                        if (this.touch.currentPage > this.data.imgCount - 1) {
                            this.touch.currentPage = 0;
                            this.touch.target.translateX = -this.touch.step;
                        };
                        this.touch.to(-(this.touch.currentPage * this.touch.step));
                    }.bind(this), 2000);
                }
    
                render() {
                    return `
                        <div omi-touch ref="carousel_container" motionRef="scroller" touchInstance="touch" vertical="false" property="translateX"  max="0" step="window.innerWidth" min="{{minValue}}"  touchStart="touchStart" touchEnd="touchEnd" animationEnd="animationEnd" class="carousel_container">
                            <div class="carousel">
                                <div ref="scroller"  style=" {{divWidth}}%" class="carousel_div">
                                    <img o-repeat="imgItem in images" style=" {{imgWidth}}%" src="{{imgItem}}">
                                </div>
                                <div id="nav" class="nav" ref="aTagDiv">
                                    <a o-repeat="aItem in images" data-index="{{$index}}" class=" "></a>
                                </div>
                                <div class="title">
                                    <span ref="title"></span>
                                </div>
                            </div>
                        </div>
                    `;
                }
            };
    
            var banner = new Banner({
                images: ['ci5.jpg', 'ci6.jpg', 'ci7.jpg', 'ci8.jpg'],
                title: ['原来你不爱我-威仔', '八年的爱', '终结敷衍', '我也憧憬过'],
                defaultIndex: 2,
                imgPath: './images/',
                style: {
                    height: '210px',
                }
            });
    
            setTimeout(() => {
                banner.setData({
                    images: ['47.jpg', '48.jpg', '49.jpg'],
                    title: ['怪我', '异性朋友', '我很快乐'],
                    defaultIndex: 3,
                    imgPath: './images/',
                    style: {
                        height: '220px',
                        top: '10%'
                    }
                })
            }, 1000);
    
            setTimeout(() => {
                banner.setData({
                    images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg'],
                    title: ['怪我', '异性朋友', '我很快乐', '隔阂'],
                    defaultIndex: 3,
                    imgPath: './images/',
                    style: {
                        height: '220px',
                        top: '20%'
                    }
                })
            }, 2000);
    
            setTimeout(() => {
                banner.setData({
                    images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg', '48.jpg'],
                    title: ['怪我', '异性朋友', '我很快乐', '隔阂', '如果这是命'],
                    defaultIndex: 3,
                    imgPath: './images/',
                    style: {
                        height: '250px',
                        top: '30%'
                    }
                })
            }, 3000);
    
            setTimeout(() => {
                banner.setData({
                    images: ['47.jpg', '48.jpg', '49.jpg', '50.jpg', '48.jpg', '51.jpg'],
                    title: ['怪我', '异性朋友', '我很快乐', '隔阂', '如果这是命', '别爱'],
                    defaultIndex: 3,
                    imgPath: './images/',
                    style: {
                        height: '270px',
                        top: '40%'
                    }
                })
            }, 4000);
    
    
            Omi.render(banner, 'body');
        </script>
    </body>
    </html>

    注意:

    使用dnt原作者的omi-touch,以上代码并不能成功运行。

    原因: 1. AlloyTouch 的实例没有抛出,或者挂在到Component实例对象上去。

                  (改进版的,挂在到实例上去了,用户可以指定实例名,不指定会自动生成一个touchInstancs+id , id自增)

              2. dom上的属性,只能是字符串,原作者只是简单的把字符串转换为数值,其实也够用了,也许当时作者没想太多。

                  (改进版的,属性名对应的属性值可以是任意表达式,会自动计算的)

              3. 组件每一次更新时,都会实例化一个AlloyTouch对象,比较浪费

                  (改进版的,如果实例名一样的话,则不再重新实例化,只需把要运动的属性值更新即可)

    说了那么多废话,上一下omi-touch源码(已修改部分代码,但是不会影响别的)

        (function () {
    
            var OmiTouch = {};    // OmiTouch集合对象
            var AlloyTouch = Omi.AlloyTouch;
            var Transform = Omi.Transform;
    
            var noop = function() { };    // 空函数
            OmiTouch._instanceId = 0;    // touch实例id
            OmiTouch.getInstanceId = function () {
                return OmiTouch._instanceId ++;    // 自增
            };
            var preTouchInstanceName = null;
    
    
            // 获取绑定的函数
            var getHandler = function(name, dom, instance) {    // name: 属性值, dom: 反馈触摸的dom, instance实例
                var value = dom.getAttribute(name);    // 获取属性值
                if (value === null) {    // 没有函数就绑定noop空函数
                    return noop;
                }else{
                    return instance[value].bind(instance);    // 否则返回一个新函数
                }
            };
    
            // 获取数值
           /* var getNum = function(name, dom){    // name: 属性值, dom: 反馈触摸的dom
                var value = dom.getAttribute(name);    // 获取属性值
                if (value) {
                    return parseFloat(value);    // 把字符串转成数字返回
                };
            };*/
    
            var getNum = function(name, dom){    // name: 属性值, dom: 反馈触摸的dom
                var value = eval('(' + dom.getAttribute(name) + ')');    // 获取属性值
    
                return Object.prototype.toString.call(value) !== '[object Null]' ? value : undefined;
            };
    
            OmiTouch.init = function(){
                Omi.extendPlugin('omi-touch',function(dom, instance){
                    var target = instance.refs[dom.getAttribute('motionRef')];    // 找到要运动的dom
                    var touchInstanceName = dom.getAttribute('touchInstance') || 'touchInstance' + OmiTouch.getInstanceId();    // 获取touch实例名, 默认touchInstance+id 自增
                    Transform(target, target.getAttribute('perspective') ? false : true);    // 不在运动对象上写perspective属性,默认不要透视(perspective="true/false" 则开启透视,只有不写才关闭)
                    var initialValue = dom.getAttribute('initialValue');    // 初始值
                    if (initialValue) {
                        target[dom.getAttribute('property') || "translateY"] = parseInt(initialValue);    // 默认有初始值,是上下滑动
                    };
    
                    if (preTouchInstanceName !== touchInstanceName) {    // 实例名一样的话,就没必要重新生成实例了
                        instance[touchInstanceName] = new AlloyTouch({
                            touch: dom,//反馈触摸的dom
                            vertical: dom.getAttribute('vertical') === 'false' ? false : true,//不必需,默认是true代表监听竖直方向touch
                            target: target, //运动的对象
                            property: dom.getAttribute('property') || "translateY",  //被运动的属性
                            min:  getNum('min', dom), //不必需,运动属性的最小值
                            max:  getNum('max', dom), //不必需,滚动属性的最大值
                            sensitivity: getNum('sensitivity', dom) ,//不必需,触摸区域的灵敏度,默认值为1,可以为负数
                            factor: getNum('factor', dom) ,//不必需,表示触摸位移与被运动属性映射关系,默认值是1
                            step: getNum('step', dom),//用于校正到step的整数倍
                            bindSelf: dom.getAttribute('bindSelf') === 'true' ? true : false,
                            touchStart: getHandler('touchStart', dom, instance),
                            change: getHandler('change', dom, instance),
                            touchMove: getHandler('touchMove', dom, instance),
                            touchEnd: getHandler('touchEnd', dom, instance),
                            tap: getHandler('tap', dom, instance),
                            pressMove: getHandler('pressMove', dom, instance),
                            animationEnd: getHandler('animationEnd', dom, instance)
                        });
                        preTouchInstanceName = touchInstanceName;
                    };
    
                });
            }
    
            OmiTouch.destroy = function() {    // 从Omi的插件集合移除该插件
                delete Omi.plugins['omi-touch'];
            };
    
            Omi.OmiTouch = OmiTouch;
        })();

    这样就可以了,虽然改了些库代码。

  • 相关阅读:
    Softmax
    网络流模板大全
    简单数据结构题(from 钟子谦——IOI2018集训队自选题)
    [POJ3177]Redundant Paths
    [BZOJ1051][HAOI2006]受欢迎的牛
    [BZOJ2036]聪明的阿卑多
    [BZOJ1455]罗马游戏
    [POJ2942][LA3523]Knights of the Round Table
    [POJ3352]Road Construction
    练级(train)
  • 原文地址:https://www.cnblogs.com/sorrowx/p/6769624.html
Copyright © 2011-2022 走看看