iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Modern Web

初階 Rails 工程師的養成系列 第 26

Day26. 認識 Stimulus,與Javascript成為好朋友

React.js, Vue.js, Angular.js為近期很流行的框架,改變了前端生活圈的生態。不過除了這些主流框架以外,Basecamp出了一款基於Rails的微型框架Stimulus

Stimulus為Basecamp出品的基於SSR框架,宗旨為Rails的後端工程師不用瞭解更多的Javascript概念而設計出來的框架。在 Rails 圈已經紅了一段時間,而我自己本身,是聽 Drifting Ruby 的課程才了解 Stimulus

目前Stimulus已經發展到 v2.0!它已經問世了一段時間,並且已經進行了1個大版本的更動。

Config

首先我們使用以下指令安裝框架

yarn add stimulus

Rails 進入點的撰寫位置會放在 config/webpacker.yml

app/javascript/packs/application.js 中,我們可以看到許多被 require 進來的套件或資料夾,這些都是使用者請 webpack 幫忙編譯與打包的東西。

我們在app/javascript/packs/application.js 寫下import 'controllers' ,就可以讀取controllers 資料夾裡面的檔案。

import "controllers"

import Rails from "@rails/ujs"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
ActiveStorage.start()

在使用Stimulus前,我們必須要了解Webpack的使用。

Webpack 預設會先讀取 index.js 的檔案,所以我們會先在app/javascript底下創建一個資料夾名controllers,並且在app/javascript/controllers 創一個檔案index.js。假設我們要引入一個han_theme.scss,我們可以在index.js 寫下

import 'han_theme.scss';

Webpack 一層一層讀取,首先由Layout寫下javascript_include_tag

➡️ 讀取app/javascript/packs/application.js

➡️ 讀取 require("styles")

➡️ 讀取 ./styles/index.js

➡️ 讀取import 'han_theme.scss';

✅ Webpack 就會知道讀取han_theme.scss

若我們使用 Stimulus,要在index.js寫下

// Load all the controllers within this directory and all subdirectories. 
// Controller files must be named *_controller.js or *_controller.ts.

import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

const application = Application.start()
// 動態讀取結尾為 _controller 的檔案
const context = require.context("controllers", true, /_controller\.(js|ts)$/)
application.load(definitionsFromContext(context))

Introduction

接著開始要介紹 Stimulus的基本用法。

Stimulus 一共有三個主體(引言出自Hotwire.dev

  • value ➡️ 資料 字串, 數字, 陣列...
  • target ➡️ 即為 DOM 元素(跟常見的event.target為同一角色)
  • action ➡️ 執行動作

actions, which connect controller methods to DOM events using data-action attributes

targets, which locate elements of significance within a controller

values, which read, write, and observe data attributes on the controller’s element

Usage

為了部落格列表使用Stimulus,我們先創建1檔案:app/javascript/controllers/admin/blogs_controller.js,並且在檔案裡頭寫下一段基本的用法

import { Controller } from 'stimulus';

export default class extends Controller {
  connect() {
    console.log('部落格列表')
  }
}

Stimulus 是用Javascript假物件導向的語法糖的語法寫,但雖然如此,Rails的精神就是慣例優於設定,除非真的很好奇,不然我們不需要懂其中的內涵。

import { Controller } from 'stimulus';

export default class extends Controller {
  constructor() {
    super();
    // 自定義邏輯
  }
  
  connect() {
    console.log('部落格列表')
  }
}

之前做了一個破壞慣例的動作,在內部class加入建構子Constructor,之後便出現了問題。

connect() 為位於生命週期中的畫面載入階段。若重整畫面後,就會馬上執行connect()方法。個人習慣在connect()寫下一段簡單的console.log ,檢查該頁面是否執行Stimulus Code。

接著我們對畫面進行改寫

= title '部落格列表'

= tag.div data: { controller: 'admin--blogs' }
  / 卡片內容
  = card do
    / ......    
  
  
  / 彈跳視窗
  = modal(id: 'new-blog-modal', confirm_wording: '送出文章',
          confirm_form: 'new_modal', title: '新增文章') do
    / ......

最後呈現的結果如下 ⬇️

https://ithelp.ithome.com.tw/upload/images/20210919/20115854wjQHbMp7Ku.png

我們來實作官方首頁的程式碼吧!

https://ithelp.ithome.com.tw/upload/images/20210919/20115854VDEjBEEugA.png

= tag.div data: { controller: 'admin--blogs' }
  / Stimulus 卡片內容
  = card do
    = card_header(title: 'Stimulus')
    = card_body do
      = tag.input type: 'text', data: { 'admin--blogs-target': 'name' }
      = button_tag '輸出', type: 'button', data: { action: 'click->admin--blogs#greet' },
                            class: 'btn btn-primary mx-2'
      = tag.span data: { 'admin--blogs-target': 'output' }
import { Controller } from 'stimulus';

export default class extends Controller {
  static targets = [ "name", "output" ]

  connect() {
    console.log('部落格列表')
  }

  greet() {
    this.outputTarget.textContent =
      this.nameTarget.value === '' ? 'Hello, 輸入框沒有填入值' : `Hello, ${this.nameTarget.value}!`
  }
}

我們將官方的範例稍微做改寫,若沒有值,則會回傳輸入框沒有填入值。操作完官網上的範例後,接下來我們講講admin--blogs的命名規則怎麼來。

下列為官網提到的 controller 的命名規則,因此我們可以推敲,當我們把檔案在javascript/controllers/admin/blogs_controllercontroller的名稱為admin--blogs

If your controller file is named… its identifier will be…
clipboard_controller.js clipboard
date_picker_controller.js date-picker
users/list_item_controller.js users--list-item
local-time-controller.js local-time

接著我們再講click->admin--blogs#greet是什麼?

click->admin--blogs#greet為點擊動作時,觸發admin--blogsgreet動作,而這邊可以省略成admin--blogs#greet

以下為官網提到的預設事件

Element Default Event
a click
button click
form submit
input input
input type=submit click
select change
textarea input

value

若要實現getter, setter,我們可以使用value 作為兩個值之間的媒介。

import { Controller } from 'stimulus';

export default class extends Controller {
  static targets = [ "name", "output", "searchedContent"]
  static values = { testId: Number }

  connect() {
    console.log('部落格列表')
    this.testIdValue = 1
  }

  greet() {
    this.testIdValue += 10

    this.outputTarget.textContent =
      this.nameTarget.value === '' ?
        `Hello, 輸入框沒有填入值 ${this.testIdValue}` :
        `Hello, ${this.nameTarget.value}! ${this.testIdValue}`
  }
}

上述的例子為,將this.testIdValue設定初始值=1,並且每按一次,this.testIdValue就會 +10

除了當作getter,setter外,還可以在畫面上綁定Value。我們將指定 controller 的位置指定value,並且在connect()內部將值印出來

= tag.div data: { controller: 'admin--blogs', 'admin--blogs-view-id-value': 40 }
  /! 內容
import { Controller } from 'stimulus';

export default class extends Controller {
  static values = { viewId: Number }

  connect() {
    console.log('部落格列表')
    console.log('this.viewIdValue', this.viewIdValue)
  }
}

https://ithelp.ithome.com.tw/upload/images/20210922/201158541VaZCcgCS2.png

我們也可以帶入Rails物件進去,如params等。

= tag.div data: { controller: 'admin--blogs',
        'admin--blogs-view-id-value': 40,
        'admin--blogs-reload_at-value': Time.current.strftime('%F %T') }
import { Controller } from 'stimulus';

export default class extends Controller {
  static values = { viewId: Number, reloadAt: String }

  connect() {
    console.log('部落格列表')
    console.log('this.viewIdValue', this.viewIdValue)
    console.log('this.reloadAtValue', this.reloadAtValue)
  }
}

https://ithelp.ithome.com.tw/upload/images/20210922/20115854Z7Mu2fylzR.png

結論

Day26-28Stimulus的系列文

  • 今天介紹了基本的Stimulus的設定、三大元素target, value, action
  • 明天我們會介紹Stimulus如何搭配Ajax使用
  • 後天的話會介紹另外一個主題Datatable

這系列的文章,會需要比較熟悉Javascript的基本用法,如果有什麼想詢問的話,歡迎在下方的留言區聯絡。

參考資料


上一篇
Day25. Form 裡面還有 Form 怎麼辦?- 表單 part3
下一篇
Day27. Stimulus 與非同步處理 - Ajax 的更優雅寫法
系列文
初階 Rails 工程師的養成34

尚未有邦友留言

立即登入留言