前言
现代框架大多数是先生成一个空的页面,然后通过特定的模板语言将JSON转换为DOM元素来填充该页面。而Stimulus并不会干扰HTML的创建,相反的,它是依附于现有HTML文档的。Stimulus关注的重点是对现有DOM元素的操纵,而不是对DOM元素的创建。Stimulus+Turbolinks的结合会更适合“传统前端”。
本文只是针对用stimulus-start新建的项目。
新建
先从git上面将stimulus框架拖下来:
$ git clone https://github.com/stimulusjs/stimulus-starter.git
$ cd stimulus-starter
安装依赖,要使用yarn:
$ yarn install
运行项目:
$ yarn start
然后打开http://localhost:9000/
文件结构
stimulus是mvc框架。视图在public目录下,控制器在src/controllers目录下。
|- public
|-- *.html
|-- *.css
|- src
|-- controllers
|---- hello_controller.js
|-- index.js
控制器
命名规则
- 控制器文件:
${controllerIdentifier}_controller.js,单词间用下划线_连接; - 控制器类:始终使用驼峰命名来对方法和属性命名;
- DOM:用短横线
-连接单词。
视图中元素和控制器的buxia关联都是由data属性来完成。
作用域
当Stimulus将控制器连接到元素时,该元素及其所有子元素构成控制器的范围。
例如,<div>及子元素<h1>是控制器的范围的一部分,但周边<main>元件是没有的。
<main>
<div data-controller="reference">
<h1>Reference</h1>
</div>
</main>
绑定控制器
用data-controller=${ controllerIdentifier }指定控制器,将当前DOM块和控制器绑定,单词间用短横线-连接。
<div data-controller="hello">
<input type="text">
<button>Greet</button>
</div>
一个DOM绑定多个控制器的时候用空格分隔:
// 绑定clipboard和list-item两个控制器
<div data-controller="clipboard list-item"></div>
同样,多个DOM绑定相同的控制器也是很常见的:
<ul>
<li data-controller="list-item">One</li>
<li data-controller="list-item">Two</li>
<li data-controller="list-item">Three</li>
</ul>
这里,每个<li>都有自己的list-item控制器实例。
方法
命名
始终用驼峰命名。
注册方法
export default class extends Controller {
// 注册sayHi事件
sayHi() {
console.log("Hello, Stimulus!", this.element)
}
}
event对象
同原生js事件绑定的event参数一样。
适用于所有事件的属性:
| 属性名 | 值 |
|---|---|
| event.type | 事件名称(例如:'click') |
| event.target | 触发事件的元素(点击的最内层元素) |
| event.currentTarget | 监听事件的元素(具有data-action属性的元素,document或者window) |
还可以使用:
| 方法 | 结果 |
|---|---|
| event.preventDefault() | 取消事件的默认行为 |
| event.stopPropagation() | 取消冒泡 |
绑定事件
用data-action为DOM绑定事件。格式为eventName->controllerIdentifier#method。
比如,点击按钮的时候触发hello控制器里面的sayHi方法:
<div data-controller="hello">
<button data-action="click->hello#sayHi">click</button>
</div>
Stimulus规定click是<button>元素的默认事件,可以省略click->。
<div data-controller="hello">
<button data-action="hello#sayHi">click</button>
</div>
绑定多个事件
给元素绑定很多动作是很常见的,多个动作用空格分隔,Stimulus按照其描述符出现的顺序从左到右调用动作:
<input type="text" data-action="focus->field#highlight input->search#update">
绑定全局事件
有时控制器需要监听在全局window或document对象上分派的事件。
您可以附加@window或@document在一个data-action上一般监听全局事件:
// 当在window上触发click事件的时候,指定gallery控制器的layout方法
<div data-controller="gallery"
data-action="click@window->gallery#layout">
</div>
Stimulus默认事件
不同标签的默认事件是不同的。
| element | default event |
|---|---|
| a | click |
| button | click |
| form | submit |
| input | change |
| input[type="submit"] | click |
| select | change |
| textarea | change |
取消浏览器默认行为
如果是为一个<a>标签绑定click事件,也会触发标签的默认跳转。这个时候可以用event.preventDefault()来取消默认行为。
greet( event ) {
event.preventDefault()
}
生命周期回调
生命周期回调方法允许在控制器连接到文档和从文档断开连接时进行响应。
| 事件名 | 事件内容 |
|---|---|
| initialize | 当控制器首次实例化时执行一次 |
| connect | 每当控制器连接到DOM时,都会调用该方法 |
| disconnect | 每当控制器与DOM断开连接时,都会调用该方法 |
connect
当满足以下两个条件时,控制器才算连接到文档:
- 控制器对应的DOM存在于文档中(必须是
document.documentElement的子元素); - 控制器标识符存在于DOM元素的
data-controller属性中。
disconnect
当connect两个条件中的任意一个不满足时,将触发disconnect事件,例如在一下情况:
- 从文档中删除元素;
- 从文档中删除元素的一个父元素;
- 元素的一个父元素的内容被替换;
data-controller被删除或修改;- 文档被安装一个新元素,例如在Turbolinks页面更改期间。
目标(target)
目标对应了页面上特定的DOM元素,方便在方法中操作DOM元素或者拿到DOM元素的值。用${name}Target获取。
命名
始终用驼峰命名。
定义目标
使用static targets数组在控制器类中定义目标名称:
export default class extends Controller {
/* 声明目标数组,只有在该数组中注册了的目标才是有效的 */
static targets = [ "name" ];
greet() {
/* this.nameTarget就是注册的name目标对应的DOM元素 */
let element = this.nameTarget;
/* 取得目标的值 */
let name = element.value;
}
}
目标属性
对于static targets数组中定义的每个目标名称,Stimulus会将以下属性添加到控制器,其中[name]对应目标的名称:
| 名称 | 值 |
|---|---|
| this.[name]Target | 范围中的第一个匹配目标 |
| this.[name]Targets | 范围内所有匹配目标的数组 |
| this.has[Name]Target | 如果范围内存在匹配的目标,返回true |
注意:当没有匹配元素时,访问this.[name]Target将引发错误。
绑定目标
用data-target来绑定目标,格式为controllerIdentifier.targetName。
<div data-controller="hello">
<input data-target="hello.name" type="text">
</div>
绑定多个目标
元素可能具有多个目标描述符,并且范围中的多个元素共享相同的描述符是很常见的。多个目标用空格分隔。
<form data-controller="search checkbox">
<input type="checkbox" data-target="search.projects checkbox.input">
<input type="checkbox" data-target="search.messages checkbox.input">
</form>
getter & setter
在取得目标值得时候,this.nameTarget.value的写法在复用时略显笨重,所以提供了目标的getter来简化操作。
export default class extends Controller {
greet() {
let name = this.name; // tom
this.name+=1; // tom1
}
get name() {
return this.nameTarget.value;
}
set name( value ) {
this.nameTarget.value = value;
}
}
自定义数据(data)
如果要给控制器传送一些自定义数据,可以这样做,在视图中:
<div data-controller="slideshow" data-slideshow-index="1"></div>
在控制器中:
initialize() {
let index = this.element.getAttribute( 'data-slideshow-index' );
}
这样做很繁琐,所以Stimulus内置了data对象来简化操作。
每个Stimulus控制器都有this.data数据对象。数据对象是为了方便地访问data-controller元素上的自定义属性。
- 视图中自定义属性的命名规则是
data-${controllerIdentifier}-${dataName}。dataName要用短横线连接。 - 在控制器中要取得相应的属性就要用
this.data.get( dataName )。dataName要用驼峰写法。
在控制器里面要取得上面的data-slideshow-index就可以这样:
initialize() {
let index = this.data.get("index")
}
更多方法
| 方法名 | 解释 |
|---|---|
has( dataName ) |
如果有指定属性,返回true |
get( dataName ) |
返回指定属性的值(字符串) |
set( dataName, value ) |
设置指定属性的值 |
delete( dataName ) |
删除指定属性的值 |
getter & setter
在大量复用data的时候,可以定义getter和setter来简化操作。
get index() {
return this.data.get("index");
}
set index( value ) {
this.data.set("index", value)
}