[note] stimulus
本篇內容擷取自:Stimulus 手冊 - 繁體中文 @ Andyyou
目錄
[TOC]
基本使用
<!-- snippets -->
<div data-controller="hello">
<input data-target="hello.name" type="text" />
<button data-action="click->hello#greet">Greet</button>
</div>
// snippets
// src/controllers/hello_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['name']; // 將 data-target 的名稱加到定義列表中
// 當 Controller 和 DOM 綁定時會觸發 connect
connect() {
this.element; // 取得被綁定的 DOM 元素
}
// 透過 DOM 上的 data-action="click->hello#greet" 觸發
greet() {
this.nameTarget; // Object, 取得第一個符合的 target
this.nameTargets; // Array, 取得所有符合的 targets
this.hasNameTarget; // Boolean, 檢查是否有符合的 target
}
}
data-controller
:主要用來設定繫結或停止繫結 Stimulus 的 controllers。data-action
:用來設定事件(events),即元素該觸發 controller 裡的哪個方法(action)。data-target
:則是協助我們在 controller 影響的範圍內方便的操作特定元素。
定義 controller 並檢查是否成功綁定到 HTML 元素
keywords: data-controller
<!-- public/index.html -->
<!-- data-controller -->
<div data-controller="hello">
<input type="text" />
<button>Greet</button>
</div>
connect()
這個方法會在 Stimulus 完成 controller 和 DOM 綁定的時候被呼叫
// src/controllers/hello_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
connect() {
console.log('Hello, Stimulus!', this.element);
}
}
action 回應 DOM 事件
keywords: data-action
在 Stimulus 裡,controller 的方法我們叫做 action
:
<!-- public/index.html -->
<!-- data-action -->
<div data-controller="hello">
<input type="text" />
<button data-action="click->hello#greet">Greet</button>
<!-- multiple data-action if needed -->
<div data-action="mouseover->monkey#mouseOver mouseout->monkey#mouseOut"></div>
</div>
其中 data-action
的值 click->hello#greet
稱為動作描述子(action descriptor)。其實就是一個設定格式。下面是格式的說明:
click
為綁定的事件hello
為 controller 識別名稱greet
為調用的方法(action)
當我們 click 時,即會出發 hello controller 裡的 greet action。
// src/controllers/hello_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
greet() {
console.log('Hello, Stimulus!', this.element);
}
}
Action 預設事件可省略
上述 button 的 action 也可以省略寫成 <button data-action="hello#greet">Greet</button>
,這是因為 Stimulus 定義了 click
是 <button>
的預設事件。
其他特定的元素也有預設事件,下列是完整的列表:
元素 | 預設事件 |
---|---|
a | click |
button | click |
form | submit |
input | change |
input type=submit | click |
select | change |
textarea | change |
target 為重要元素建立 controller 的參考屬性
keywords: data-target
, this.nameTarget
, this.nameTargets
, this.hasNameTarget
<!-- public/index.html -->
<!-- data-target -->
<div data-controller="hello">
<input data-target="hello.name" type="text" />
<button data-action="click->hello#greet">Greet</button>
</div>
觀察到 data-target
的值為 hello.name
又稱為目標元素描述子(target descriptor)。其實就是一個設定格式。下面是格式的說明:
hello
為 controller 是識別名稱name
為 target 名稱
接著透過 static targets = ['name']
,把 name
加入到 controller 目標元素的定義列表中,Stimulus 會自動建立一個 this.nameTarget
屬性,這個屬性會參考到符合條件的第一個目標元素。我們就可以直接使用這個屬性來讀取元素的值,用它來產生我們的問候句。
// src/controllers/hello_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['name']; // 將 data-target 的名稱加到定義列表中
greet() {
const element = this.nameTarget;
const name = element.value;
console.log(`Hello, ${name}!`);
}
}
如上面的範例我們的 "name"
target 名稱會產生下面這些屬性:
this.nameTarget
等於在 controller 影響的範圍內找到符合source
的第一個元素,如果沒有任何元素符合,當我們存取屬性會產生錯誤。this.nameTargets
所有在 controller 範圍內符合source
的元素this.hasNameTarget
判斷是否有符合name
元素,如果有就是true
,沒有則是false
狀態管理與 Data API
keywords: data-<controller-name>-<attribute-name>
, this.data.get()
, this.data.has()
, this.data.set()
一個 Stimulus 應用程式的狀態基本上會存在 DOM 的屬性上;controller 基本上不管理狀態。命名的方式是使用 data-<controller-name>-<attribute-name>
<!-- 直接在 DOM 上面透過 data 屬性帶入狀態 -->
<!-- data-<controller-name>-<attribute-name> -->
<div data-controller="slideshow" data-slideshow-index="1"></div>
注意
data-slideshow-index
必須要放在 controller 的根元素上。- 因為
data-slide-show-index
是 HTML 的 attribute 所以只能是字串,若要存成陣列,則需透過split()
和join()
處理;若是物件則需要先透過JSON.stringify()
等方法。
由於 data 屬性太常被使用,因此若按上面慣例命名的話,除了過去使用 el.dataset
或 el.getAttribute
的做法外,在 Stimulus 中可以 直接使用 this.data.get('<attribute-name>')
:
// ./slideshow_controller
initialize() {
// const index = parseInt(this.element.dataset.slideshowIndex)
// const index = parseInt(this.element.getAttribute('data-slideshow-index'))
const index = parseInt(this.data.get("index"))
this.showSlide(index)
}