昨日の続きです。
RailsのTurboでAjaxで要素を削除したときにCSSアニメーションさせる方法2(Stimlus化)
画像の登録もTurbo/Stimulusで実施してなかったので修正してみます。
やってみる
css
fade-in用を追加。
.fade-in { animation: fade-in .4s linear; opacity: 1; } .fade-out { animation: fade-out .4s linear; opacity: 0; } @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes fade-out { 0% { opacity: 1; } 100% { opacity: 0; } }
html
登録用にturbo_frame_tagで囲います。animationを追加したいので、data属性にcontrollerも追加。
# show.html.haml = turbo_frame_tag :user_images, data: { controller: "stream-animations" } do = render partial: "image", collection: @user.images, locals: { user: @user }
Stimulsでアニメーション用のcssを取得できるようにdata属性にleaving_classを追加。
# users/_image.html.haml = turbo_frame_tag "user_image_#{image.id}", data: { entering_class: "fade-in", leaving_class: "fade-out" } do .image-wrapper.position-relative = image_tag image = link_to user_image_path(user, image), remote: true, data: { turbo_method: :delete, turbo_confirm: "Can I delete it?" }, class: "delete-image-link position-absolute top-0 end-0" do %span ×
Railsのcontroller
createでturbo_stream.appendを行います。
class Users::ImagesController < ApplicationController def create user = User.find(params[:user_id]) user.images.attach(params[:images]) image = user.images.last render turbo_stream: turbo_stream.append(:user_images, partial: "users/image", locals: { user:, image: }) end def destroy user = User.find(params[:user_id]) user.images.find(params[:id]).purge render turbo_stream: turbo_stream.remove("user_image_#{params[:id]}") end end
Stimlus
append用の処理を追加。
template, turboFrameElm の辺りが謎ですが、これで追加される要素が取得できます。
なので、これにアニメーション用のクラスを追加すればokです。
# stream_animations_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { connect() { document.addEventListener("turbo:before-stream-render", this.animate) } disconnect() { document.removeEventListener("turbo:before-stream-render", this.animate) } animate(e) { const turboStreamElm = e.target const { action, target } = turboStreamElm if (action === "append") { const template = turboStreamElm.firstElementChild const turboFrameElm = template.content.firstElementChild const { enteringClass } = turboFrameElm.dataset if (enteringClass) { turboFrameElm.classList.add(enteringClass) } } else if (action === "remove") { const turboFrameElm = document.getElementById(target) const { leavingClass } = turboFrameElm.dataset if (leavingClass) { e.preventDefault() turboFrameElm.classList.add(leavingClass) turboFrameElm.addEventListener("animationend", () => { e.target.performAction() }) } } } }
一応できましたが、、、
stimulsの処理自体は大した行数ではないですが、若干面倒に感じます。cssアニメーションはデフォルト機能として欲しいところ。
参考
See Also
・RailsのTurboでAjaxで要素を削除したときにCSSアニメーションさせる方法
・RailsのTurboでAjaxで要素を削除したときにCSSアニメーションさせる方法2(Stimlus化)