jQuery在第二次呈现页面后不起作用

时间:2019-01-20 11:13:49

标签: javascript jquery vue.js

我尝试在created的vuejs内调用我的jquery自定义滑块,但不幸的是它没有用。仅当我将代码放在mounted上时,它才起作用,但是当我离开页面并返回同一页面时,它就停止了。

这是我的代码。

export default {
  //This only worked on first load and never to work again on leaving the page and coming back!
    mounted() {
      require("./slider.js");
    },
        ...
    }

...

export default {
  //This never works!
    created() {
      require("./slider.js");
    },
        ...
    }

slider.js

//Star slider
  (function($) {

  'use strict';

  var pluginName = 'slider',
    defaults = {
      next: '.slider-nav__next',
      prev: '.slider-nav__prev',
      item: '.slider__item',
      dots: false,
      dotClass: 'slider__dot',
      autoplay: false,
      autoplayTime: 3000,
    };

  function slider(element, options) {
    this.$document = $(document);
    this.$window = $(window);
    this.$element = $(element);
    this.options = $.extend({}, defaults, options);
    this.init();
  };

  slider.prototype.init = function() {
    this.setup();
    this.attachEventHandlers();
    this.update();
  };
  slider.prototype.setup = function(argument) {
    this.$slides = this.$element.find(this.options.item);
    this.count = this.$slides.length;
    this.index = 0;

    this.$next = $(this.options.next);
    this.$prev = $(this.options.prev);

    this.$canvas = $(document.createElement('div'));
    this.$canvas.addClass('slider__canvas').appendTo(this.$element);
    this.$slides.appendTo(this.$canvas);

    this.$dots = $(this.options.dots);
    this.$dots.length && this.createDots();
  };

  slider.prototype.createDots = function() {
    var dots = [];

    var dotClassName = this.options.dotClass;
    this.$element.children().find('.slider__item__title').each(function(__index, el) {
      var __title = $(this).text();
      dots[__index] = '<div data-index="' + __index + '" class="' + dotClassName + '">' + __title + '</div>';
    });
    this.$dots.append(dots);
  }

  slider.prototype.attachEventHandlers = function() {
    this.$element.on('prev.' + pluginName, this.prev.bind(this));
    this.$document.on('click', this.options.prev, (function(e) {
      this.$element.trigger('prev.' + pluginName);
    }).bind(this));

    this.$element.on('next.' + pluginName, this.next.bind(this));
    this.$document.on('click', this.options.next, (function(e) {
      this.$element.trigger('next.' + pluginName);
    }).bind(this));

    this.$element.on('update.' + pluginName, this.update.bind(this));
    this.$window.on('resize load', (function(e) {
      this.$element.trigger('update.' + pluginName);
    }).bind(this));

    this.$element.on('jump.' + pluginName, this.jump.bind(this));
    this.$document.on('click', ('.' + this.options.dotClass), (function(e) {
      var index = parseInt($(e.target).attr('data-index'));
      this.$element.trigger('jump.' + pluginName, index);
    }).bind(this));

    this.$element.on('autoplay.' + pluginName, this.autoplay.bind(this));
    this.$element.on('autoplayOn.' + pluginName, this.autoplayOn.bind(this));
    this.$element.on('autoplayOff.' + pluginName, this.autoplayOff.bind(this));
    this.$element.bind('prev.' + pluginName + ' next.' + pluginName + ' jump.' + pluginName, this.autoplay.bind(this));
    this.options.autoplay && this.$element.trigger('autoplayOn.' + pluginName);
  };

  slider.prototype.next = function(e) {
    this.index = (this.index + 1) % this.count;
    this.slide();
  };

  slider.prototype.prev = function(e) {
    this.index = Math.abs(this.index - 1 + this.count) % this.count;
    this.slide();
  };

  slider.prototype.jump = function(e, index) {
    this.index = index % this.count;
    this.slide();
  }

  slider.prototype.autoplayOn = function(argument) {
    this.options.autoplay = true;
    this.$element.trigger('autoplay.' + pluginName);
  };

  slider.prototype.autoplayOff = function() {
    this.autoplayClear();
    this.options.autoplay = false;
  }

  slider.prototype.autoplay = function(argument) {
    this.autoplayClear();
    if (this.options.autoplay) {
      this.autoplayId = setTimeout((function() {
        this.$element.trigger('next.' + pluginName);
        this.$element.trigger('autoplay.' + pluginName);
      }).bind(this), this.options.autoplayTime);
    }
  };

  slider.prototype.autoplayClear = function() {
    this.autoplayId && clearTimeout(this.autoplayId);
  }

  slider.prototype.slide = function(index) {
    undefined == index && (index = this.index);
    var position = index * this.width * -1;
    this.$canvas.css({
      'transform': 'translate3d(' + position + 'px, 0, 0)',
    });
    this.updateCssClass();
  };

  slider.prototype.update = function() {
    this.width = this.$element.width();
    this.$canvas.width(this.width * this.count);
    this.$slides.width(this.width);
    this.slide();
  };

  slider.prototype.updateCssClass = function() {
    this.$slides
      .removeClass('x__slider-active')
      .eq(this.index)
      .addClass('x__slider-active');

    this.$dots
      .find('.' + this.options.dotClass)
      .removeClass('x__slider-active')
      .eq(this.index)
      .addClass('x__slider-active');
  }

  $.fn[pluginName] = function(options) {
    return this.each(function() {
      !$.data(this, pluginName) && $.data(this, pluginName, new slider(this, options));
    });
  };

})(window.jQuery);

$('#x__slider').slider({
  prev: '#x__slider-prev',
  next: '#x__slider-next',
  dots: '#x__slider-dots',
  autoplay: true,
});
//End slider 

1 个答案:

答案 0 :(得分:1)

安装与创建

您注意到,将代码放入创建的生命周期挂钩后,代码将无法正常工作。为了弄清楚原因,我们需要深入研究the lifecycle hooks。滑块的工作原理是找到一个元素,然后将其转换为滑块。

运行创建的挂钩时,尚无组件渲染。在生命周期挂钩beforeMount之后,只有组件中的html。之后,您可以使用的第一个生命周期挂钩是mounted挂钩。

它只能运行一次,为什么?

您使用require(..)运行滑块的代码。需要您的滑块文件运行IIFE。包含它之后,就无需再次运行它。再次加载滑块时,文件已从内存加载,因为之前已经“需要”。

最好将代码完全放在组件生命周期挂钩之外,然后使用从文件中导出的一些初始化函数。

如何解决此问题?

我建议不要在Vue应用程序中使用jQuery。 jQuery和Vue都可以操作DOM。 Vue没有jQuery不能做的事,但是您可能需要重新考虑如何构造元素。如果您不想自己写任何东西,那么那里还有几个预制的滑块。

如果您需要使其与jQuery一起使用,最好的选择是稍微更改一下slide.js文件以在底部导出初始化代码。

export default function (element) {
  $(element).slider({
    prev: '#x__slider-prev',
    next: '#x__slider-next',
    dots: '#x__slider-dots',
    autoplay: true,
  });
}

代替使用require,只需将其导入组件顶部即可。

<script>
  import sliderInit from './slider';

  export default {
    // ...

更改模板以在元素上包含a ref。这样一来,您就可以引用DOM元素,而无需冒页面上重复ID的风险。

<template>
  <div ref="slider">
    <div class="slide">
      <!-- You get the idea -->
    </div>
  </div>
</template>

现在,我们只需要初始化滑块即可。最好的方法是执行我们刚刚在安装的钩子中导入的功能。您可能需要稍等片刻,以使引用保持不变

mounted () {
  // Option 1
  sliderInit(this.$refs.slider);

  // Option 2
  this.$nextTick(() => {
    sliderInit(this.$refs.slider);
  });
}