StimulusJS与Turbolinks一起使用时,必须等待“turbolinks:load”事件才能执行StimulusJS控制器。

3

我有一个相当标准的Rails 5.2应用程序(遵循几乎所有惯例),使用yarn和webpacker,在我的package.jsonyarn.lock文件中,其中stimulus版本为1.1.1

# package.json
{
  "name": "MY_APP_NAME",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "^4.0.2",
    "coffeescript": "1.12.7",
    "stimulus": "^1.1.1"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.2.1"
  }
}

从 StimulusJS 的讨论页(https://discourse.stimulusjs.org/t/stimulusjs-and-turbolinks/669)开始,在 Stimulus 1.1 版本之后,使用 Turbolinks 时,stimulus 控制器会在 DOM 准备好后执行 connect/initialize 方法。
然而,我能够使下面的控制器正常执行的唯一方式是添加事件处理程序并等待 turbolinks:load 事件触发。
如果相关,请注意,我正在尝试使用 jQuery Select2 插件创建自定义选择元素。
# app/javascript/packs/controllers/intake_customization_controller.js
import { Controller } from "stimulus";

export default class extends Controller {
  static targets = [ "userIds" ]

  initialize() {
    // Code will not execute without this event handler wrapping it...
    $(document).on("turbolinks:load", ()=> {
      $(this.userIdsTarget).select2()
    })
  }
}

HTML表单:
<%= form_with model: @account, url: settings_intake_customization_path, method: :put, id: "settings-intake_customization-form", data: { controller: "intake-customization" } do |form| %>
  <%= form.collection_select :user_ids, current_account.users, :id, :name, { include_blank: false }, { multiple: true, data: { target: "intake-customization.userIds" } } %>
<% end %>

我在使用turbolinks设置刺激控制器时有什么遗漏吗?

使用事件处理程序,我可以获得所需的功能,但从Discourse论坛上阅读的内容来看,我不需要使用事件处理程序。

即使package.json中显示为最新版本的Stimulus,我的应用程序是否可能“缓存”了旧版本?

1个回答

4
据我所知,Stimulus被设计为与Turbolinks配合使用。如果您需要在事件处理程序turbolinks:load中包装代码,则可能会感到惊讶。您可能希望使用connect事件而不是initialize事件,因为在实例化控制器时会触发initialize事件。每当控制器连接到DOM时,都会触发connect事件。
connection生命周期回调的docs中可以看到:

当满足以下两个条件时,控制器将连接到文档:

  • 其元素存在于文档中(即作为document.documentElement的后代元素)
  • 其标识符存在于元素的data-controller属性中

当控制器变为已连接状态时,Stimulus将调用其connect()方法。

由于您想使用jQuery Select2操纵DOM,对我来说,connect生命周期回调似乎更合适。我会进行更多的研究,但我想象initialize事件在控制器的代码加载到浏览器时被触发。如果是这样的话,那么有可能在渲染使用您的控制器的DOM树的部分(以及您尝试查询的DOM元素)之前,initialize事件已经被触发了。
# app/javascript/packs/controllers/intake_customization_controller.js

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = [ "userIds" ]

  connect() {
    $(this.userIdsTarget).select2()
  }
}

我找到了一篇文章,建议使用connect而不是turbolinks:load。这篇文章是由一位发表过多篇Stimulus教程的人撰写的,因此他似乎很有信誉。除了initialize只会触发一次,而connect每次连接到DOM时都会触发外,我很难找到任何详细介绍initializeconnect之间区别的内容。为了再次触发connect事件,在其中需要触发disconnected事件。


1
遇到了同样的问题,但是针对 $(this.userIdsTarget).selectpicker()。使用 connect() 是正确的方法。 - Sergio Gonzalez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接