【问题标题】:Jquery don't work after page has being rendered second time页面第二次呈现后 Jquery 不起作用
【发布时间】:2025-12-18 03:30:01
【问题描述】:

我尝试在 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 

【问题讨论】:

    标签: javascript jquery vue.js


    【解决方案1】:

    已安装与已创建

    您注意到,当您将代码放入 created 生命周期挂钩时,它不起作用。要弄清楚为什么会这样,我们需要深入研究the lifecycle hooks。您的滑块的工作原理是找到一个元素,然后将其转换为滑块。

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

    它只运行一次,但为什么呢?

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

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

    如何解决这个问题?

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

    如果您需要让它与 jQuery 一起使用,最好的办法是稍微更改您的 slider.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);
      });
    }
    

    【讨论】:

    • 非常感谢您!
    最近更新 更多