Mal*_*son 3 ruby-on-rails stimulusjs
在 Rails 6 安装中,我有以下内容:
控制器:
# app/controllers/foo_controller.rb
def bar
@items = [["firstname", "{{ FIRSTNAME }}"], ["lastname", "{{ LASTNAME }}"], ["company", "{{ COMPANY }}"]]
end
Run Code Online (Sandbox Code Playgroud)
看法:
# app/views/foo/bar.html.erb
<p>Quia <span data-field="firstname">{{ FIRSTNAME }}</span> quibusd <span data-field="firstname">{{ FIRSTNAME }}</span> am sint culpa velit necessi <span data-field="lastname">{{ LASTNAME }}</span> tatibus s impedit recusandae modi dolorem <span data-field="company">{{ COMPANY }}</span> aut illo ducimus unde quo u <span data-field="firstname">{{ FIRSTNAME }}</span> tempore voluptas.</p>
<% @items.each do |variable, placeholder| %>
<div data-controller="hello">
<input
type="text"
data-hello-target="name"
data-action="hello#greet"
data-field="<%= variable %>"
value="<%= placeholder %>">
</div>
<% end %>
Run Code Online (Sandbox Code Playgroud)
以及相关的刺激代码(vanilla JS):
//app/javascript/controllers/hello_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
static targets = [ "name" ]
greet() {
var elements = document.body.querySelectorAll('[data-field="' + this.nameTarget.dataset.field + '"]');
for (var i = 0; i < elements.length; i++) {
elements[i].innerText = this.nameTarget.value;
};
}
}
Run Code Online (Sandbox Code Playgroud)
现在,正如您可能已经猜到的那样,我们的想法是<input>从哈希中为每个项目生成一个字段@items,预先填充相关值并与 a “链接” <span>,它会在值更改时更新。到目前为止,一切正常。
但这是我的问题。这部分是普通的旧脏香草js,感觉不太“刺激”:
var elements = document.body.querySelectorAll('[data-field="' + this.nameTarget.dataset.field + '"]');
for (var i = 0; i < elements.length; i++) {
elements[i].innerText = this.nameTarget.value;
};
Run Code Online (Sandbox Code Playgroud)
当然有一些方法可以改善这一点。任何有关如何以更优雅的方式重构此代码的建议都将受到欢迎。
一种方法是拥有两个控制器,一个用于“将更改内容的事物”(我们称之为content),另一个用于“将在其他地方显示任何更新内容的事物”(我们称之为output)。
一旦设置了两个控制器,就可以更容易地推断它们是离散的。当用户交互更新值时,一个会执行某些操作,而另一个在知道更新的值时也应该执行某些操作。
Stimulus 建议跨控制器与事件协调。JavaScript 事件传递是一种强大的、浏览器本机的跨 DOM 元素通信的方式。
div元素,一个位于上面,用于显示标签name内的值h1和标签email内的值p。div 包含两个input标签,用户将在这些标签中更新值。<body>
<div
class="container"
data-controller="output"
data-action="content:updated@window->output#updateLabel"
>
<h1 class="title">
Hello
<span data-output-target="item" data-field="name">Joe</span>
</h1>
<p>
Email:
<span data-output-target="item" data-field="email">joe@joe.co</span>
</p>
</div>
<div data-controller="content">
<input
type="text"
data-action="content#update"
data-content-field-param="name"
value="Joe"
/>
<input
type="text"
data-action="content#update"
data-content-field-param="email"
value="joe@joe.co"
/>
</div>
</body>
Run Code Online (Sandbox Code Playgroud)
input更新,它将conten#update在更改时触发事件。data-content-field-param是一个操作参数,可在控制器上的event.params类方法的给定内部使用。updatecontentoutput有一个单独的操作来“侦听”调用的事件content:updated,它将全局侦听该事件(在 处window),然后updateLabel使用接收到的事件调用其自己的方法。output具有带有名称的目标item,每个目标都具有它应该在简单属性中引用的“字段”的映射data-field。ContentController有一个update方法将接收任何触发的输入元素的更改事件。currentTarget,并且可以通过 收集字段event.params.field。this.dispatch,我们给它命名updated,Stimulus 会自动附加类名,并content给出事件名称content:updated。根据文档 - https://stimulus.hotwired.dev/reference/controllers#cross-controller-coordination-with-eventsOutputController一个名称目标item和一个方法updateLabelupdateLabel将接收事件并从 的调度中“提取”为其提供的详细信息ContentController。updateLabel将遍历每个元素itemTargets并查看该元素的数据集上是否有匹配的字段名称,然后innerText在找到匹配项时更新。这也意味着您可以在该控制器的作用域 HTML 中拥有多个“名称”占位符。class ContentController extends Controller {
update(event) {
const field = event.params.field;
const value = event.currentTarget.value;
this.dispatch('updated', { detail: { field, value } });
}
}
class OutputController extends Controller {
static targets = ['item'];
updateLabel(event) {
const { field, value } = event.detail;
this.itemTargets.forEach((element) => {
if (element.dataset.field === field) {
element.innerText = value;
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4182 次 |
| 最近记录: |