Selaa lähdekoodia

增加一个本地化的轮播实现

guohh 5 vuotta sitten
vanhempi
commit
943b84acd1

+ 350 - 0
2019/ah-hsx/biz/js/compoent/CustomCarousel.js

@ -0,0 +1,350 @@
1
// 临时用组件
2
define(["Hammer", "jquery", "ipuUI"], function (Hammer, $, ipuUI) {
3
  /**
4
   * @class
5
   * @uses Hammer.js
6
   * 通过hammer.js实现的banner功能组件,
7
   * 因为实现轮播,显示第一项后,再显示第一项,所以第一项有被复制到添加到最后
8
   *
9
   *        @example
10
   *        <!-- 组件html结构如下,li里的内容用户可自定义  -->
11
   *        <div class="ipu-carousel ipu-hammer-carousel">
12
   *          <ul class="ipu-carousel-wrapper">
13
   *            <li ><img src="../../biz/img/01.jpg" alt=""></li>
14
   *            <li ><img src="../../biz/img/02.jpg" alt=""></li>
15
   *            <li ><img src="../../biz/img/03.jpg" alt=""></li>
16
   *            <li ><img src="../../biz/img/04.jpg" alt=""></li>
17
   *          </ul>
18
   *        </div>
19
   *
20
   * @constructor  不能直接访问该类,调用 {@link ipu#customCarousel}生成实例
21
   * @param {String|JqueryObj} slt
22
   *      jquery选择器字符串或jquery对象,用来查找要被组件初始化化的dom
23
   * @param {Object} option 组件配置参数,默认配置见 {@link #cfg-defaultOption}
24
   */
25
  function CustomCarousel(slt, option) {
26
    this.option = $.extend({}, this.defaultOption, option);
27
    this.el = $(slt).get(0);
28
    this._init();
29
  }
30
31
  $.extend(CustomCarousel.prototype, {
32
    /**
33
     * 组件默认配置项
34
     *
35
     * @cfg {Object} defaultOption
36
     * @cfg {Number} defaultOption.index 初始化时显示第几项,用户未指定时,会查找子项内容上有ipu-current的项显示,默认显示第一项
37
     * @cfg {Number} defaultOption.showItemSize 一屏最多时出现的子项数量(循环的时候要复制的数量)
38
     * @cfg {Boolean} defaultOption.loop 是否循环切换,只有轮播切换时,才能自动轮播
39
     * @cfg {Boolean} defaultOption.autoPlay 是否自动轮播
40
     * @cfg {Number} defaultOption.duration 自动轮播时的间隔时间,单位ms
41
     * @cfg {Boolean} defaultOption.indicator 是否生成banner提示器,true右下角出现小点
42
     * @cfg {Function} defaultOption.callBack 轮播显示某项时的回调函数
43
     * @cfg {Number} defaultOption.callBack.index 当前显示的项索引
44
     * @cfg {Function} defaultOption.clickBack
45
     *          切换项时被点击时的回调函数,此处主要是为了处理复制项与第一项的点击事件进行处理,
46
     *          让用户不关注点击的是第一项或是复制项,回调作用域为组件对象
47
     * @cfg {Number} defaultOption.clickBack.index 点击的项索引
48
     */
49
    defaultOption: {
50
      index: null,
51
      showItemSize: 1,
52
      startIndex: 0,  // 起始位置,有时起始位置不为0;
53
      loop: true,
54
      autoPlay: false,
55
      duration: 3000,
56
      indicator: false,
57
      callBack: null,
58
      clickBack: null
59
    },
60
    _init: function () {
61
      this.wrapper = $(">.ipu-carousel-wrapper", this.el);
62
      this.carouselItems = $(">li", this.wrapper);
63
      this.itemSize = this.carouselItems.size();  // 子项数量
64
      this.showItemSize = this.option.showItemSize; // 一屏展示子项数量,默认显示1个,做循环显示时只需要复制一个子项
65
66
      if (this.showItemSize > this.itemSize + 1) {
67
        this.enable = false;
68
        return; // 不能正常工作,无法初始化此组件,需要做异常处理
69
      }
70
71
      this.enable = true;
72
      this.startIndex = Math.ceil(this.option.startIndex);   // 起始位置,表明0不会显示,因为没法显示0
73
      this.endIndex = this.startIndex + this.itemSize;       // 结束位置展现同起始位置,只是索引不同
74
      this.carouselItemWides = []; // 子项宽度尺寸
75
76
      /** @property {Number} 当前显示子项索引,从0开始 */
77
      this.currentIndex = 0; // 当前显示子项索引
78
      this.moveLen = 0;      // 当前滚动移动距离
79
80
      /** @type {Boolean} 循环展示时,第一项会被复制,显示项是第一项时,是否为第一项的复制项 */
81
      this.cloneItem = false; //这个参数用来标记是否复制项
82
83
      if (this.option.indicator) {
84
        this._addIndicator();
85
      }
86
87
      // 如果做循环展示,则要复制起始展示项到最后面
88
      if (this.option.loop) {
89
        var cloneItem = this.carouselItems.slice(0, this.showItemSize).clone().appendTo(this.wrapper).removeClass("ipu-current");  // 这里假设每个元素宽度都是相等的
90
        if (cloneItem.size() < this.showItemSize) {
91
          this.carouselItems.slice(0, 1).clone().appendTo(this.wrapper).removeClass("ipu-current");
92
        }
93
      }
94
95
      var that = this;
96
      if (this.option.clickBack) {
97
        $(">li", this.wrapper).each(function (i) {
98
          $(this).click(function () {
99
            that.option.clickBack.call(this, i % that.size);
100
          });
101
        })
102
      }
103
104
      this.hammer = new Hammer.Manager(this.el);
105
      this.hammer.add(new Hammer.Pan({direction: Hammer.DIRECTION_HORIZONTAL, threshold: 10}));
106
      this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this._onPan, this));
107
108
      this._sizeCount();
109
      $(window).resize(function () { // 在窗口尺寸变化时,更新尺寸信息
110
        that.refresh();
111
      });
112
113
      if (this.option.index == null) {
114
        var activeIndex = this.carouselItems.filter(".ipu-current").index();
115
        this.currentIndex = activeIndex != -1 ? activeIndex : 0;
116
      }
117
118
      this._show(this.currentIndex, false);
119
    },
120
    /**
121
     * 停止自动滚动
122
     */
123
    stop: function () {
124
      this._pause();
125
      this.option.autoPlay = false;
126
    },
127
    _pause: function () {
128
      if (this.timeoutId) {
129
        clearTimeout(this.timeoutId);
130
        this.timeoutId = null;
131
      }
132
    },
133
    /**
134
     * 切换到上一项
135
     */
136
    prev: function () {
137
      var index;
138
      if (this.option.loop) {
139
        if (this.realIndex == this.startIndex) {
140
          this._show(this.endIndex, false);
141
          this.wrapper.width();
142
          index = this.endIndex - 1;
143
        } else {
144
          index = this.realIndex - 1;
145
        }
146
      } else {
147
        index = (this.currentIndex - 1 + this.itemSize) % this.itemSize;
148
      }
149
150
      this._show(index);
151
    },
152
    /**
153
     * 切换到下一项
154
     */
155
    next: function () {//下一张
156
      var index;
157
      if (this.option.loop) {
158
        if (this.realIndex == this.endIndex) {
159
          this._show(this.startIndex, false);
160
          this.wrapper.width();
161
          index = this.startIndex + 1;
162
        } else {
163
          index = this.realIndex + 1;
164
        }
165
      } else {
166
        index = (this.currentIndex + 1) % this.itemSize;
167
      }
168
169
      this._show(index);
170
    },
171
    /**
172
     * 切换显示指定项
173
     *
174
     * @param {Number} index 要切换到的项索引
175
     *
176
     */
177
    show: function (index) {  // 跳到指定索引处,这里是realIndex
178
      var index = index % this.itemSize;  // todo: 起始项与结束项相同,应该看离那项近,往那边移动?
179
      if (index < 0) {
180
        index = this.itemSize + index;
181
      }
182
      index = this.startIndex + index;
183
      this._show(index); // 默认追加动画
184
    },
185
    /**
186
     * 自动轮播
187
     */
188
    play: function () {
189
      this.option.autoPlay = true;
190
      this._play();
191
    },
192
    _play: function () {
193
      if (this.option.autoPlay && this.option.loop && !this.timeoutId) {
194
        var that = this;
195
        this.timeoutId = setTimeout(function () {
196
          that.timeoutId = null;//清空这个timeoutId,代表该次处理已经执行了
197
          that.next();
198
        }, that.option.duration);
199
      }
200
    },
201
    _addIndicator: function () {
202
      var html = "";
203
      for (var i = 0; i < this.itemSize; i++) {
204
        html += "<li></li>";
205
      }
206
      html = "<ul class='ipu-carousel-indicator'>" + html + "</ul>";
207
      this.indicator = $(html).appendTo(this.el);
208
      this.indicatorIndexs = $("li", this.indicator);
209
    },
210
    _sizeCount: function () {
211
      this.wrapperWidth = this.wrapper.outerWidth(true);
212
      this.itemWidth = this.carouselItems.eq(0).outerWidth(true);
213
      $(this.wrapper).removeClass("ipu-carousel-animate").width();
214
      this.carouselItemWides = [];
215
216
      var that = this;
217
      $(">li", this.wrapper).each(function (index, dom) {
218
        console.log("index:" + $(this).position().left);
219
        that.carouselItemWides[index] = $(this).position().left;
220
      });
221
      this.mostSize = this.itemSize * this.itemWidth;           // 宽度*数量
222
      this.startSize = that.carouselItemWides[this.startIndex]; // 起始位置
223
      this.endSize = that.carouselItemWides[this.endIndex];     // 宽度*数量
224
      console.log(this.startSize + "--" + this.endSize);
225
    },
226
    /**
227
     * 宽度信息或尺寸信息发生变更时,进行刷新计算
228
     * 判断是否需要重新计算尺寸,若宽度尺寸发生变化,进行重新尺寸计算
229
     */
230
    refresh: function () {
231
      if (this.wrapperWidth != this.wrapper.outerWidth(true)) {
232
        this._sizeCount();
233
        this._show(this.realIndex, false); //新的位置
234
      }
235
    },
236
    _move: function (moveLen) { // 拖动时的处理
237
      this._pause();
238
      $(this.wrapper).removeClass("ipu-carousel-animate");
239
240
      if (this.option.loop) { // 循环时,起始位置
241
        moveLen = moveLen % this.mostSize;
242
        var move = (this.moveLen - moveLen);
243
        if (move < this.startSize) {
244
          move = move + this.mostSize;
245
        } else if (move > this.endSize) {
246
          move = move - this.mostSize
247
        }
248
      } else {
249
        var move = this.moveLen - moveLen;
250
        if (move < 0) {
251
          move = move / 2;
252
        } else if (move > this.endSize) {
253
          move = this.endSize + (move - this.endSize) / 2;
254
        }
255
      }
256
257
      this.displayMoveLen = move;
258
      move = -move + "px";
259
      $(this.wrapper).css("transform", "translate3d(" + move + ", 0, 0)");
260
    },
261
    _show: function (index, animate) { // index = realIndex
262
      if (animate !== false) { // 默认值为true
263
        animate = true;
264
      }
265
266
      this._pause();
267
      $(this.wrapper).toggleClass("ipu-carousel-animate", animate);
268
269
      if (index < this.startIndex) {  // 起始位置不一定位于0
270
        index = this.itemSize + index;
271
      } else if(index > this.endIndex){
272
        index = index - this.itemSize;
273
      }
274
275
276
      this.realIndex = index;
277
      this.currentIndex = index % this.itemSize;
278
      this.cloneItem = index >= this.itemSize;
279
280
      this.moveLen = this.carouselItemWides[index];
281
      var move = -this.moveLen + "px";
282
283
      $(this.wrapper).css("transform", "translate3d(" + move + ", 0, 0)");
284
285
      var currentIndex = this.currentIndex;
286
      if (animate && this.option.callBack) {
287
        this.option.callBack(currentIndex, this.cloneItem);//返回当前索引,以及是滞最后一项参数
288
      }
289
290
      if (this.indicator) {
291
        this.indicatorIndexs.eq(currentIndex).addClass("ipu-current").siblings().removeClass("ipu-current");
292
      }
293
294
      this._play();//处理自动播放
295
    },
296
    _onPan: function (ev) {
297
      var delta = ev.deltaX;  // 内容往左,deltaX为正值
298
299
      // pancancel与panend,有效的pan事件结束与无效的pan事件结束?
300
      if (ev.type == 'panend' || ev.type == 'pancancel') {
301
        var value = delta / this.itemWidth;
302
        var intValue = parseInt(Math.abs(value));               // 取整数
303
        var decimal = Math.abs(value) % 1;                      // 取小数
304
305
        if (decimal > 0.2) { // 滑动超过页面宽20%;
306
          intValue = intValue + 1;
307
        }
308
        if (delta > 0) {
309
          intValue = -intValue;
310
        }
311
        var index;
312
313
        if (this.option.loop) {
314
          intValue = intValue % this.itemSize;
315
          index = (this.realIndex + intValue);
316
          if(index < this.startIndex){
317
            index = index + this.itemSize;
318
          } else if(index > this.endIndex){
319
            index = index - this.itemSize;
320
          }
321
        } else { // 非循环时
322
          index = this.currentIndex + intValue;
323
          if (index < 0) {
324
            index = 0;
325
          } else if (index > this.itemSize - 1) {
326
            index = this.itemSize - 1;
327
          }
328
        }
329
330
        this._show(index);
331
      } else if (ev.type == 'panmove') {
332
        this._move(delta);
333
      }
334
    }
335
  });
336
337
  /**
338
   * @member ipuUI
339
   * 生成HammerCarousel实例,参数信息见{@link CustomCarousel#method-constructor}
340
   *
341
   * @param {String} slt
342
   * @param {Object} option
343
   * @returns {CustomCarousel}
344
   */
345
  ipuUI.customCarousel = function (slt, option) {
346
    return new CustomCarousel(slt, option);
347
  };
348
349
350
});

+ 83 - 0
2019/ah-hsx/carousel-demo.html

@ -0,0 +1,83 @@
1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
  <title>营销学院</title>
5
  <meta charset="utf-8">
6
  <!-- 宽度自动适配 -->
7
  <meta name="viewport"
8
        content="width=device-width, initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0, user-scalable=no"/>
9
  <!-- 不识别页面上的数字为可拨打号码 -->
10
  <meta content="telephone=no" name="format-detection"/>
11
  <link rel="stylesheet" type="text/css" href="ipu/ui/css/ipuUI.css">
12
  <link rel="stylesheet" type="text/css" href="biz/css/base.css">
13
14
  <script src="ipu/lib/requirejs/require.min.js"></script>
15
  <script src="biz/js/require-config.js"></script>
16
  <style>
17
    .demo {
18
      overflow: hidden;
19
    }
20
21
    .demo  .ipu-carousel-wrapper img {
22
      width: 100%;
23
      height: 1.2rem;
24
      padding: 0 .075rem;
25
    }
26
27
    .demo .ipu-carousel {
28
      width: 2.3rem;
29
      margin: 0 auto;
30
      overflow: visible;
31
    }
32
  </style>
33
  <script>
34
    require(["ipuUI", "jquery", "../biz/js/compoent/CustomCarousel"], function (ipuUI, $) {
35
36
37
      // 需要判断子项数量最少要为2,否则组件无法工作,子项为1?
38
      var carousel = ipuUI.customCarousel(".ipu-carousel", { // 第一页设置幻灯片
39
        showItemSize: 3,  // 一屏最多会出现几个子项,决定复制的数量
40
        startIndex: 1,    // 显示起始位置,不能直接显示第0项,因为前面没有图片
41
        autoPlay: false, // 是否自动循环
42
        indicator: true, // 是否生成指示器(右下角的小圆点)
43
        loop: true       // 是否循环
44
      });
45
46
      $("#prev").on("click", function () {
47
        console.log("点了上一张");
48
        carousel.prev();
49
      });
50
      $("#next").on("click", function () {
51
        console.log("点了下一张");
52
        carousel.next();
53
      });
54
      $("#play").on("click", function () {
55
        console.log("点了自动播放");
56
        carousel.play();
57
      });
58
      $("#stop").on("click", function () {
59
        console.log("点了停止播放");
60
        carousel.stop();
61
      });
62
    });
63
  </script>
64
</head>
65
<body class="">
66
67
<div class="demo">
68
  <div class="ipu-carousel ipu-hammer-carousel" id="noLoopCarousel">
69
    <ul class="ipu-carousel-wrapper">
70
      <li><img src="temp/img/01.jpg" alt=""></li>
71
      <li><img src="temp/img/02.jpg" alt=""></li>
72
      <li><img src="temp/img/03.jpg" alt=""></li>
73
    </ul>
74
  </div>
75
</div>
76
<div class="ipu-fn-m">
77
  <button id="prev" class="ipu-btn ipu-btn-s">上一张</button>
78
  <button id="play" class="ipu-btn ipu-btn-s">播放</button>
79
  <button id="stop" class="ipu-btn ipu-btn-s">停止</button>
80
  <button id="next" class="ipu-btn ipu-btn-s">下一张</button>
81
</div>
82
</body>
83
</html>

BIN
2019/ah-hsx/temp/img/01.jpg


BIN
2019/ah-hsx/temp/img/02.jpg


BIN
2019/ah-hsx/temp/img/03.jpg


BIN
2019/ah-hsx/temp/img/04.jpg