[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)
}
使 controller 的狀態與 DOM 上的狀態保持一致
this.data.has('<attribute-name>')
假如 controller 根元素有data-slideshow-index
屬性的話,會回傳true
。this.data.get('<attribute-name>')
取得根元素上data-slideshow-index
屬性值。this.data.set('<attribute-name>', <value>)
將index
的值設定到根元素的data-slideshow-index
屬性上。
// ./slideshow_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['slide'];
initialize() {
this.showCurrentSlide();
}
previous() {
this.index--;
}
next() {
this.index++;
}
showCurrentSlide() {
this.slideTargets.forEach((el, i) => {
el.classList.toggle('slide--current', this.index == i);
});
}
get index() {
return parseInt(this.data.get('index'));
}
set index(value) {
this.data.set('index', value);
this.showCurrentSlide();
}
}
生命週期
keywords: initialize
, connect
, disconnect
在 Stimulus 中 controller 從初始化到解構有其生命週期,每個階段有對應的生命週期回調,這些方法通常可以協助我們設定狀態或解除繫結。
回調 | 由 Stimulus 自動調用 |
---|---|
initialize | 僅執行一次,當 controller 建立物件實例的時候 |
connect | 當 controller 和 DOM 完成繫結的時候 |
disconnect | 當 controller 和 DOM 解除繫結的時候 |
處理外部資源
keywords: content-loader
, AJAX
有時候我們的 controller 需要追蹤來自外部的資料,這裡我們說的「外部」指的是任何只要不是存在 DOM 或者 Stimulus 中的資料。
1.建立 content-loader
controller 和 data-content-loader-url
:
<!-- public/index.html -->
<div data-controller="content-loader" data-content-loader-url="/messages.html"></div>
2.新增要外部載入的檔案
<!-- public/messages.html -->
<ol>
<li>New Message: Stimulus Launch Party</li>
<li>Overdue: Finish Stimulus 1.0</li>
</ol>
3.透過 controller 載入外部資源
// src/controllers/content_loader_controller.js
import { Controller } from 'stimulus';
export default class extends Controller {
connect() {
this.load();
}
load() {
fetch(this.data.get('url'))
.then((response) => response.text())
.then((html) => {
this.element.innerHTML = html;
});
}
}
Working with external resources @ Andyyou's Gitbook
命名慣例
檔名 | 識別名稱 |
---|---|
clipboard_controller.js | clipboard |
date_picker_controller.js | date-picker |
users/list_item_controller.js | users--list-item |
local-time-controller.js | local-time |
controller 檔案名稱與對應的識別名稱(identifier) @ Andyyou's Gitbook
資料來源
- Stimulus 手冊 - 繁體中文 @ Andyyou