老师,针对之前的遗留问题(js和发送消息),客服老师已经发给我了,但是看不太懂

老师,针对之前的遗留问题(js和发送消息),客服老师已经发给我了,但是看不太懂

还想请老师帮我解释一下修改的思路

我的问题的链接:(js动画失效问题和发送消息问题)(第二种滑入滑出方试)

https://class.imooc.com/course/qadetail/193450

(function($) {
  'use strict';

  function Slider($elem, options) {
    this.$elem = $elem;
    this.options = options;
    this.$items = this.$elem.find('.slider-item');
    this.$indicators = this.$elem.find('.slider-indicator');
    // this.$controlLeft=this.$elem.find('.slider-control-left');
    // this.$controlRight=this.$elem.find('.slider-control-right');
    this.$controls = this.$elem.find('.slider-control');
    this.itemNum = this.$items.length;
    this.curIndex = this._getCorrectIndex(this.options.activeIndex);

    this._init();
  }

  Slider.DEFAULTS = {
    css3: false,
    js: false,
    animation: 'fade', // slide
    activeIndex: 0,
    interval: 0,
    loop: false
  };

  Slider.prototype._init = function() {
    var self = this;
    // init show

    this.$indicators.removeClass('slider-indicator-active');
    this.$indicators.eq(this.curIndex).addClass('slider-indicator-active');
    //to
    if (this.options.animation === 'slide') {
      this.$elem.addClass('slider-slide');
      // // this.$items.eq(this.curIndex).css('left', 0);

      // 应该用 this.$container 监听事件,而不是 this.$items
      // 因为此时移动的是 this.$container
      // 所以这里的代码需要往后移,因为此时 this.$container 还没定义
      //send message
      // this.$items.on('move moved', function(e) {
      //   var index = self.$items.index(this);

      //   if (e.type === 'move') {
      //     if (index === self.curIndex) {
      //       self.$elem.trigger('slider-hide', [index, this]);
      //     } else {
      //       self.$elem.trigger('slider-show', [index, this]);
      //     }
      //   } else {
      //     // moved
      //     if (index === self.curIndex) {
      //       // 指定的
      //       self.$elem.trigger('slider-shown', [index, this]);
      //     } else {
      //       self.$elem.trigger('slider-hidden', [index, this]);
      //     }
      //   }
      // });

      // // move init
      // this.$items.move(this.options);

      this.to = this._slide;
      this.$container = this.$elem.find('.slider-container');
      this.itemWidth = this.$items.eq(0).width();
      this.$container.css('left', -1 * this.curIndex * this.itemWidth);
      // this.itemWidth = this.$items.eq(0).width();
      // this.transitionClass = this.$items.eq(0).hasClass('transition') ? 'transition' : '';

      // 移到这里来
      // 多接收了两个参数:$container 表示正在移动的元素;distLeft 表示移动完成后,移动元素 的 left值
      // 这里需要修改 move.js 的 to 方法,在触发move事件时,多传递2个参数
      // 也需要修改 move.js 的 Js.prototype.to 方法,在触发 moved 事件时,多传递4个参数
      this.$container.on('move moved', function(
        e,
        $container,
        distLeft,
        distTop,
        originalLeft,
        originalTop
      ) {
        // 计算 index 的方法错了,此时移动的是 this.$container
        // 这样是无法计算它的索引的,总是 -1
        // var index = self.$items.index(this);

        if (e.type === 'move') {
          // 想要计算移动前的索引是多少
          var left = parseInt($container.css('left'));
          // 计算出移动刚开始时的索引值
          var index = Math.abs(parseInt(left / self.itemWidth));
          // 计算出移动完成后的索引值
          var distIndex = Math.abs(parseInt(distLeft / self.itemWidth));
          // console.log(index, self.curIndex);
          // console.log(index, distIndex);

          // 当前的开始隐藏
          self.$elem.trigger('slider-hide', [index, this]);
          // 移动完成后的开始显示
          self.$elem.trigger('slider-show', [distIndex, this]);

          // if (index === self.curIndex) {
          //   self.$elem.trigger('slider-hide', [index, this]);
          // } else {
          //   self.$elem.trigger('slider-show', [index, this]);
          // }
        } else {
          // moved
          // 计算出移动刚开始时的索引值
          var index = Math.abs(parseInt(originalLeft / self.itemWidth));
          // 计算出移动完成后的索引值
          var distIndex = Math.abs(parseInt(distLeft / self.itemWidth));

          // 移动刚开始时的那个幻灯片完全隐藏
          self.$elem.trigger('slider-hidden', [index, this]);
          // 移动完成后的那个幻灯片完全显示
          self.$elem.trigger('slider-shown', [distIndex, this]);

          // if (index === self.curIndex) {
          //   // 指定的
          //   self.$elem.trigger('slider-shown', [index, this]);
          // } else {
          //   self.$elem.trigger('slider-hidden', [index, this]);
          // }
        }
      });

      //move init
      this.$container.move(this.options);

      if (this.options.loop) {
        this.$container.append(this.$items.eq(0).clone());
        this.transitionClass = this.$container.hasClass('transition')
          ? 'transition'
          : '';
        this.itemNum++;
      }
    } else {
      this.$elem.addClass('slider-fade');
      this.$items.eq(this.curIndex).show();

      // send message
      this.$items.on('show shown hide hidden', function(e) {
        self.$elem.trigger('slider-' + e.type, [self.$items.index(this), this]);
        // 发送消息,同时传参当前显示的第几个及该DOM
      });

      // showHide init
      this.$items.showHide(this.options);
      this.to = this._fade;
    }

    //bind event
    this.$elem
      .hover(
        function() {
          self.$controls.show();
        },
        function() {
          self.$controls.hide();
        }
      )
      .on('click', '.slider-control-left', function() {
        self.to(self._getCorrectIndex(self.curIndex - 1), 1); //通过第二个参数有无来确定是点击的箭头还是下面的圆点
      })
      .on('click', '.slider-control-right', function() {
        self.to(self._getCorrectIndex(self.curIndex + 1), -1);
      })
      .on('click', '.slider-indicator', function() {
        self.to(self._getCorrectIndex(self.$indicators.index(this)));
      });

    // auto
    if (this.options.interval && !isNaN(Number(this.options.interval))) {
      this.$elem.hover($.proxy(this.pause, this), $.proxy(this.auto, this));
      this.auto();
    }
  };

  Slider.prototype._getCorrectIndex = function(index, maxNum) {
    maxNum = maxNum || this.itemNum;
    if (isNaN(Number(index))) return 0;
    if (index < 0) return maxNum - 1;
    if (index > maxNum - 1) return 0;
    return index;
  };

  Slider.prototype._activateIndicators = function(index) {
    // this.$indicators.eq(this.curIndex).removeClass('slider-indicator-active');
    this.$indicators.removeClass('slider-indicator-active');
    this.$indicators.eq(index).addClass('slider-indicator-active');
  };

  Slider.prototype._fade = function(index) {
    if (this.curIndex === index) return;
    this.$items.eq(this.curIndex).showHide('hide');
    this.$items.eq(index).showHide('show');
    this._activateIndicators(index);
    this.curIndex = index;
  };
  Slider.prototype._slide = function(index, direction) {
    if (this.curIndex === index) return;
    var self = this;

    // 之前有停顿问题的原因就在于这里
    // 因为这里一上来就开始运动了,后面判断完该往哪里运动后,又开启了一次运动,相当于有2次运动,造成了冲突
    // 所以把这里的运动注释掉,放在后面的 if 分支中,保证同一时间只有一次运动
    // this.$container.move('x', -1 * index * this.itemWidth);
    // this.curIndex = index;
    if (this.options.loop && direction) {
      if (direction < 0) {
        if (index === 0) {
          console.log(index);
          this.$container.removeClass(this.transitionClass).css('left', 0);
          this.curIndex = index = 1;
          setTimeout(function() {
            self.$container
              .css('left', 0)
              .addClass(self.transitionClass)
              .move('x', -1 * index * self.itemWidth);
          }, 20);
        } else {
          // 这里是新增的分支,表示当 direction < 0 时,index !=0 的情况下该怎么运动
          // 其实就是把上面注释掉的代码,拿过来了
          this.$container.move('x', -1 * index * this.itemWidth);
          this.curIndex = index;
        }
      } else {
        if (index === this.itemNum - 1) {
          console.log(index);
          this.$container
            .removeClass(this.transitionClass)
            .css('left', -1 * index * this.itemWidth);
          this.curIndex = index = this.itemNum - 2;
          setTimeout(function() {
            self.$container
              .addClass(self.transitionClass)
              .css('left', -1 * (self.itemNum - 1) * self.itemWidth)
              .move('x', -1 * index * self.itemWidth);
          }, 20);
        } else {
          // 这里是新增的分支,表示当 direction >= 0 时,index != this.itemNum - 1 的情况下该怎么运动
          // 其实就是把上面注释掉的代码,拿过来了
          this.$container.move('x', -1 * index * this.itemWidth);
          this.curIndex = index;
        }
      }

      index = this._getCorrectIndex(index, this.itemNum - 1);
    } else {
      // 这里是新增的分支,表示当 this.options.loop!=true或direction没有值的情况下该怎么运动
      // 其实就是把上面注释掉的代码,拿过来了
      this.$container.move('x', -1 * index * this.itemWidth);
      this.curIndex = index;
    }
    this._activateIndicators(index);

    // if (this.curIndex === index) return;

    // var self = this;

    // // 确定滑入滑出的方向
    // if (!direction) { // click indicators
    //     if (this.curIndex < index) {
    //         direction = -1;
    //     } else if (this.curIndex > index) {
    //         direction = 1;
    //     }
    // }

    // // 设置指定滑入幻灯片的初始位置
    // this.$items.eq(index).removeClass(this.transitionClass).css('left', -1 * direction * this.itemWidth);

    // // 当前幻灯片滑出可视区域,指定幻灯片滑入可视区域
    // setTimeout(function() {
    //     self.$items.eq(self.curIndex).move('x', direction * self.itemWidth);
    //     self.$items.eq(index).addClass(self.transitionClass).move('x', 0);
    //     self.curIndex = index;
    // }, 20);

    // // 激活indicator
    //  this._activateIndicators(index);
  };

  Slider.prototype.auto = function() {
    var self = this;
    this.intervalId = setInterval(function() {
      self.to(self._getCorrectIndex(self.curIndex + 1), -1);
    }, this.options.interval);
  };
  Slider.prototype.pause = function() {
    clearInterval(this.intervalId);
  };

  $.fn.extend({
    slider: function(option) {
      return this.each(function() {
        var $this = $(this),
          slider = $this.data('slider'),
          options = $.extend(
            {},
            Slider.DEFAULTS,
            $(this).data(),
            typeof option === 'object' && option
          );
        // dropdown(this, options);
        if (!slider) {
          //解决多次调用dropdown问题
          $this.data('slider', (slider = new Slider($this, options)));
        }

        if (typeof slider[option] === 'function') {
          slider[option]();
        }
      });
    }
  });
})(jQuery);


正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

3回答
好帮手慕慕子 2020-04-10 20:11:15

同学你好,对于你的问题解答如下:

  1. 理解是对的。

  2. 参数是用来计算索引的,不传的话就是undefined,计算结果为NAN,不会报错的。只要执行了trigger事件,就会发送消息,触发事件,只是前面显示的索引是NAN而已。可以换成css方式,测试下,如下:

    http://img1.sycdn.imooc.com//climg/5e90622f095f354506400410.jpg

同学可以试着理解下,如果还有疑惑,可以详细描述下具体是哪里不明白,我们会继续为您解答的,祝学习愉快~

好帮手慕慕子 2020-04-10 11:45:08

同学你好,对于你的问题解答如下:

  1. 可以查看下move.js中css方式是直接通过css方法设置left和top值实现位移,是瞬间移动到指定位置的,而js方式是使用animate方法实现位移,在移动到指定位置时会有一个过渡效果。如下:

    http://img1.sycdn.imooc.com//climg/5e8fe7c40942978a15361270.jpg

  2. js和css方式,slider.js中发送消息是相同的,两者不同的是move.js中css和js的位移方式(也就是to方法)。

同学可以试着理解下,祝学习愉快~

  • 提问者 迷失的小麦 #1
    关于问题2,可能我的意思没表达清楚。js和css方式,既然发送消息是相同的,那么触发moved事件的时候,只有js传入了参数originalLeft,而css并没有在move.js中传入参数originalLeft,为什么这样写代码还没报错? (当使用css时slider-hidden的事件)
    2020-04-10 12:24:57
  • 提问者 迷失的小麦 #2
    关于问题1,我能否这样理解: css是没有移动过程的,只是肉眼上有个动画效果。而js是有一个移动过程,所以肉眼上有个动画效果。(但是感觉这样理解很牵强)
    2020-04-10 12:26:47
  • 提问者 迷失的小麦 #3
    打漏了,问题2是slider-hidden和slider-shown
    2020-04-10 12:28:07
好帮手慕星星 2020-04-09 17:26:19

同学你好,问题解答如下:

1、js方式移动的问题

当索引为0的时候,会进行两次移动

http://img1.sycdn.imooc.com//climg/5e8ee813091bdeb115980579.jpg

运动都是需要时间的,两次叠加在一起,效果上就会有问题。所以需要将一开始的移动的代码注释掉,分别在不同方向上添加else判断,如下

http://img1.sycdn.imooc.com//climg/5e8ee3f709b882d316780705.jpg

http://img1.sycdn.imooc.com//climg/5e8ee8510944150e14940635.jpg最外层的if相对应的else也可以添加判断

http://img1.sycdn.imooc.com//climg/5e8ee8ac09aa2f8c12160263.jpg

2、发送消息这部分比较复杂,修改的地方较多

(1)代码中调用move方法是this.$container元素

http://img1.sycdn.imooc.com//climg/5e8ee982097409a707240088.jpg

所以on绑定事件也需要在这个元素上,而不是$items上

http://img1.sycdn.imooc.com//climg/5e8ee9c009705df506970113.jpg

可以看一下下面的注释

 Slider.prototype._init = function() {
        var self = this;

        this.$indicators.removeClass('slider-indicator-active');
        this.$indicators.eq(this.curIndex).addClass('slider-indicator-active');

        if (this.options.animation === 'slide') {
            this.$elem.addClass('slider-slide');

            // 这里不应该监听 this.$items 上的事件,而应该监听 this.$container 上的事件
            // 因为此时移动的是 this.$container,而不是 this.$items
            // 这里的代码需要往后移,因为此时 this.$container 还没定义
            // 需要移动到 this.$container 定义后,再来监听相关事件
            // 所以这里先注释掉
            //send message
            // this.$items.on('move moved', function(e) {
            //   var index = self.$items.index(this);

            //   if (e.type === 'move') {
            //     if (index === self.curIndex) {
            //       self.$elem.trigger('slider-hide', [index, this]);
            //     } else {
            //       self.$elem.trigger('slider-show', [index, this]);
            //     }
            //   } else {
            //     // moved
            //     if (index === self.curIndex) {
            //       // 指定的
            //       self.$elem.trigger('slider-shown', [index, this]);
            //     } else {
            //       self.$elem.trigger('slider-hidden', [index, this]);
            //     }
            //   }
            // });

            this.to = this._slide;
            this.$container = this.$elem.find('.slider-container');
            this.itemWidth = this.$items.eq(0).width();
            this.$container.css('left', -1 * this.curIndex * this.itemWidth);

            // 上面注释掉的代码移到这里来了
            // 监听 this.$container 上的事件
            // 我们的目标是将 move 和 moved 这两个事件,转换成 slider-show、slider-hide、slider-shown 和 slider-hidden 四个事件

            // 在监听到 move 事件时,表示幻灯片开始运动了,我们需要将其转换成  slider-show 和 slider-hide
            // 此时我们需要根据 this.$container 的偏移位置,计算出当前显示的是第几张幻灯片(就是索引值是多少),这张幻灯片就是开始隐藏的幻灯片(slider-hide)
            // 再根据传入的 distLeft 参数(this.$container 运动到目的地后的偏移位置,因为我们这里改变的是 left 值,所以起名叫 distLeft),计算出将要显示的是第几张幻灯片,这张幻灯片就是开始显示的幻灯片(slider-show)

            // 在监听到 moved 事件时,表示幻灯片已经运动完成了,我们需要将其转换成  slider-shown 和 slider-hidden
            // 此时我们需要根据 this.$container 的当前位置,计算出当前显示的是第几张幻灯片,这张幻灯片就是已经完全显示了的幻灯片(slider-shown)
            // 再根据传入的 originalLeft 参数(this.$container 刚开始运动时的偏移位置),计算出这是第几张幻灯片,这张幻灯片就是已经完全隐藏了的幻灯片(slider-hidden)

            // 这里需要多接收两个参数 distLeft 和 originalLeft,帮助我们计算幻灯片的索引值
            // distLeft 参数是由 move.js 的 to 方法在触发 move 事件时传递的,需要在 move.js 的 to 方法中添加这一步
            // originalLeft 参数是由 move.js 的 Js.prototype.to 方法在触发 moved 事件时传递的,需要在 move.js 的 Js.prototype.to 方法中添加这一步
            this.$container.on('move moved', function(
                e,
                $container,
                distLeft,
                originalLeft
            ) {
                if (e.type === 'move') {
                    // 计算刚开始运动时,将要隐藏的幻灯片的索引值
                    var left = parseInt($container.css('left'));
                    var index = Math.abs(parseInt(left / self.itemWidth));
                    // 计算运动到目的地后,将要显示的幻灯片的索引值
                    var distIndex = Math.abs(parseInt(distLeft / self.itemWidth));

                    // 刚开始运动时,将要隐藏的幻灯片开始隐藏
                    self.$elem.trigger('slider-hide', [index, this]);
                    // 运动到目的地后,将要显示的幻灯片开始显示
                    self.$elem.trigger('slider-show', [distIndex, this]);
                } else {
                    // moved
                    // 计算出已经完全隐藏了的幻灯片的索引值
                    var index = Math.abs(parseInt(originalLeft / self.itemWidth));
                    // 计算出已经完全显示了的幻灯片的索引值
                    var distIndex = Math.abs(parseInt(distLeft / self.itemWidth));

                    // 触发事件,表示幻灯片已经完全隐藏
                    self.$elem.trigger('slider-hidden', [index, this]);
                    // 触发事件,表示幻灯片已经完全显示
                    self.$elem.trigger('slider-shown', [distIndex, this]);
                }
            });

            this.$container.move(this.options);

            if (this.options.loop) {
                this.$container.append(this.$items.eq(0).clone());
                this.transitionClass = this.$container.hasClass('transition') ?
                    'transition' :
                    '';
                this.itemNum++;
            }
        } else {
            this.$elem.addClass('slider-fade');
            this.$items.eq(this.curIndex).show();

            this.$items.on('show shown hide hidden', function(e) {
                self.$elem.trigger('slider-' + e.type, [self.$items.index(this), this]);
            });

            this.$items.showHide(this.options);
            this.to = this._fade;
        }

        this.$elem
            .hover(
                function() {
                    self.$controls.show();
                },
                function() {
                    self.$controls.hide();
                }
            )
            .on('click', '.slider-control-left', function() {
                self.to(self._getCorrectIndex(self.curIndex - 1), 1);
            })
            .on('click', '.slider-control-right', function() {
                self.to(self._getCorrectIndex(self.curIndex + 1), -1);
            })
            .on('click', '.slider-indicator', function() {
                self.to(self._getCorrectIndex(self.$indicators.index(this)));
            });

        if (this.options.interval && !isNaN(Number(this.options.interval))) {
            this.$elem.hover($.proxy(this.pause, this), $.proxy(this.auto, this));
            this.auto();
        }
    };

move.js中也需要修改,在触发move和move.js事件中传入参数

  var to = function (x, y, callback) {
    x = typeof x === 'number' ? x : this.curX;
    y = typeof y === 'number' ? y : this.curY;
    if (this.curX === x && this.curY === y) return;

    // 这里需要把想要移动到哪里传递出去(也就是 distLeft 参数)
    // this.$elem.trigger('move', [this.$elem]);
    this.$elem.trigger('move', [this.$elem, x]);

    if (typeof callback === 'function') {
      callback();
    }

    this.curX = x;
    this.curY = y;
  };
Js.prototype.to = function (x, y) {
    var self = this;

    // 需要修改这里,计算出运动元素的初始 left 值(也就是 originalLeft)
    var originalLeft = parseInt(self.$elem.css('left'));

    to.call(this, x, y, function () {
      self.$elem.stop().animate(
        {
          left: x,
          top: y
        },
        function () {
          // 在触发 moved 事件时,多传递 2 个参数
          //   self.$elem.trigger('moved', [self.$elem]);
          self.$elem.trigger('moved', [self.$elem, x, originalLeft]);
        }
      );
    });
  };

自己再理解下,祝学习愉快!

  • 提问者 迷失的小麦 #1
    老师说是js方式移动的问题的原因是当索引为0的时候,会进行两次移动,那为什么当css方式移动时不会出现错误,我对这里的原理有点晕,不太理解
    2020-04-09 20:21:18
  • 提问者 迷失的小麦 #2
    另外,关于发送消息,为什么originalLeft写在了js里面,如果是css呢?
    2020-04-10 11:07:17
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
2.组件化网页开发
  • 参与学习           人
  • 提交作业       1121    份
  • 解答问题       14456    个

本阶段在运用JS实现动态网页开发的基础上,带你深入理解企业开发核心思想,完成一个企业级网页的开发,体验前端工程师的成就感。

了解课程
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师