Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use vanjs #7

Merged
merged 1 commit into from Aug 16, 2023
Merged

use vanjs #7

merged 1 commit into from Aug 16, 2023

Conversation

kawamataryo
Copy link
Owner

@kawamataryo kawamataryo commented Aug 16, 2023

Fix to use VanJS in DOM construction

@kawamataryo kawamataryo changed the title refactor use vanjs use vanjs Aug 16, 2023
@kawamataryo kawamataryo self-assigned this Aug 16, 2023
@kawamataryo kawamataryo merged commit 3d3d510 into main Aug 16, 2023
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
new file mode 100644
index 0000000..a14ed3e
--- /dev/null
+++ b/articles/1ad6e51eed13ae.md
@@ -0,0 +1,297 @@
+---
+title: "VanJSで素のDOM操作をリファクタリングしたら最高だった"
+emoji: "🍦"
+type: "tech" # tech: 技術記事 / idea: アイデア
+topics: ["vanjs", "javascript"]
+published: false
+---
+
+VanJSを試してみたら開発体験が良かったので紹介します。
+
+# 🍦 VanJSとは?
+
+[VanJS](https://vanjs.org/)は、数ヶ月前にメジャーバージョンがリリースされた新しいReactive UIフレームワークです。軽量、非依存、トランスパイル不要、シンプルなAPIという特徴があります。
+
+https://vanjs.org/
+
+gzip圧縮で**0.9kbと非常に軽量**で、バンドルサイズの肥大化を機にすることなく手軽に導入できます。
+
+![](/images/1ad6e51eed13ae/2023-08-17-07-34-28.png)
+*他のUIフレームワークと比較しても圧倒的に軽量*
+
+UIもJSXを使わず、関数ベースのAPIで宣言的に構築できます。
+
+@[codepen](https://codepen.io/kawamataryo/pen/dywbjOm)
+
+# 🛠️ リファクタリング対象
+
+Sky Follower BridgeというX(Twitter)のFollower一覧から[Bluesky](https://bsky.app/)のユーザーを検索するChrome拡張機能を個人開発しています。今回はその拡張機能のcontent scriptの部分をVanJSでのリファクタリング対象としました。
+
+https://www.youtube.com/watch?v=XcRcWjStIMc
+
+https://github.com/kawamataryo/sky-follower-bridge
+
+
+この拡張機能はX(Twitter)のDOM要素を基準に動的にBlueskyのユーザーセルのDOMを追加するのですが、対象要素にReactやVueのインスタンスを都度マウントするのも何か違和感があるなと、開発当初は素のDOM操作で実装していました。
+
+![](/images/1ad6e51eed13ae/2023-08-17-08-54-41.png)
+
+しかし、機能が増えるにつれ複雑化し可読性が悪くなっていました。そこで、軽量でシンプルなVanJSを使いリファクタリングしてみることにしました。
+
+
+# 📝 結果
+
+Blueskyのユーザーセルの挿入箇所を例にリファクタリング結果を紹介します。
+なお実際のVanJSの導入のPRは以下です。
+
+kawamataryo/sky-follower-bridge#7
+
+## Before
+
+リファクタリング前のコードは以下のようになっていました。
+`insertAdjacentHTML`で条件に合わせたDOMを構築、`addEventListener`でアクションボタンのclickイベントと、hoverイベントを登録しています。
+
+DOM APIで直接クラスの付け変えやテキストの書き換えを行なっているので、UIとイベントの関連が分かりにくく書いた本人ながらあまり触りたくないコードです😅
+
+[sky-follower-bridge/blob/main/src/lib/domHelpers.ts](https://github.com/kawamataryo/sky-follower-bridge/blob/782b75c8fc9fb54547eb44ffd8962a7729533a65/src/lib/domHelpers.ts#L57-L143)
+
+```ts:src/lib/domHelpers.ts
+export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortController, followAction, unfollowAction }: {
+  dom: Element,
+  profile: ProfileView,
+  statusKey: keyof ViewerState,
+  btnLabel: UserCellBtnLabel,
+  abortController: AbortController,
+  followAction: () => void,
+  unfollowAction: () => void
+}) => {
+  const avatarEl = profile.avatar ? `<img src="${profile.avatar}" width="48" />` : "<div class='no-avatar'></div>"
+  const actionBtnEl = profile.viewer[statusKey] ? `<button class='follow-button follow-button__following'>${btnLabel.progressive} on Bluesky</button>` : `<button class='follow-button'>${btnLabel.add} on Bluesky</button>`
+  dom.insertAdjacentHTML('afterend', `
+  <div class="bsky-user-content">
+    <div class="icon-section">
+      <a href="https://bsky.app/profile/${profile.handle}" target="_blank" rel="noopener">
+        ${avatarEl}
+      </a>
+    </div>
+    <div class="content">
+      <div class="name-and-controller">
+        <div>
+          <p class="display-name"><a href="https://bsky.app/profile/${profile.handle}" target="_blank" rel="noopener">${profile.displayName ?? profile.handle}</a></p>
+          <p class="handle">@${profile.handle}</p>
+        </div>
+        <div>
+          ${actionBtnEl}
+        </div>
+      </div>
+      ${profile.description ? `<p class="description">${profile.description}</p>` : ""}
+    </div>
+  </div>
+  `)
+  const bskyUserContentDom = dom.nextElementSibling as Element
+
+  // register a click action
+  bskyUserContentDom?.addEventListener('click', async (e) => {
+    const target = e.target as Element
+    const classList = target.classList
+
+    // follow action
+    if (classList.contains('follow-button') && !classList.contains('follow-button__following')) {
+      target.textContent = "processing..."
+      target.classList.add('follow-button__processing')
+      await followAction()
+      target.textContent = `${btnLabel.progressive} on Bluesky`
+      target.classList.remove('follow-button__processing')
+      target.classList.add('follow-button__following')
+      target.classList.add('follow-button__just-followed')
+      return
+    }
+
+    // unfollow action
+    if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
+      target.textContent = "processing..."
+      target.classList.add('follow-button__processing')
+      await unfollowAction()
+      target.textContent = `${btnLabel.add} on Bluesky`
+      target.classList.remove('follow-button__processing')
+      target.classList.remove('follow-button__following')
+      return
+    }
+  }, {
+    signal: abortController.signal
+  })
+
+  bskyUserContentDom?.addEventListener('mouseover', async (e) => {
+    const target = e.target as Element
+    const classList = target.classList
+    if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
+      target.textContent = `${btnLabel.remove} on Bluesky`
+    }
+  }, {
+    signal: abortController.signal
+  })
+  bskyUserContentDom?.addEventListener('mouseout', async (e) => {
+    const target = e.target as Element
+    const classList = target.classList
+    if (classList.contains('follow-button__just-followed')) {
+      target.classList.remove('follow-button__just-followed')
+    }
+    if (classList.contains('follow-button') && classList.contains('follow-button__following')) {
+      target.textContent = `${btnLabel.progressive} on Bluesky`
+    }
+  }, {
+    signal: abortController.signal
+  })
+}
+```
+
+## After
+
+VanJSでのリファクタリング後は、対象のDOMへのマウント処理は、対象のDOMに`van.add`でコンポーネントをマウントするのみ。VanJSのコンポーネント側も、親しみあるVueやReactのようにコンポーネントを分割し宣言的にUIを構築できたため、だいぶ可読性は高くなった気がします。今後の機能拡張のモチベーションも上がりました💪
+
+・Mount
+
+```ts:src/lib/domHelpers.ts
+export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, addAction, removeAction }: {
+  dom: Element,
+  profile: ProfileView,
+  statusKey: keyof ViewerState,
+  btnLabel: UserCellBtnLabel,
+  addAction: () => Promise<void>,
+  removeAction: () => Promise<void>
+}) => {
+  van.add(dom.parentElement, BskyUserCell({
+    profile,
+    statusKey,
+    btnLabel,
+    addAction,
+    removeAction,
+  }))
+}
+```
+
+・ActionButton
+
+```ts:src/components/BskyUserCell.ts
+const ActionButton = ({ statusKey, profile, btnLabel, addAction, removeAction }: {
+  profile: ProfileView,
+  statusKey: keyof ViewerState,
+  btnLabel: UserCellBtnLabel,
+  addAction: () => Promise<void>,
+  removeAction: () => Promise<void>
+}) => {
+  const label = van.state(`${profile.viewer[statusKey] ? btnLabel.progressive : btnLabel.add} on Bluesky`)
+
+  const isStateOfBeing = van.state(profile.viewer[statusKey])
+  const isProcessing = van.state(false)
+  const isJustApplied = van.state(false)
+
+  const beingClass = van.derive(() => isStateOfBeing.val ? "action-button__being" : "")
+  const processingClass = van.derive(() => isProcessing.val ? "action-button__processing" : "")
+  const justAppliedClass = van.derive(() => isJustApplied.val ? "action-button__just-applied" : "")
+
+  const onClick = async () => {
+    if (isProcessing.val) return
+    isProcessing.val = true
+    label.val = "Processing..."
+
+    if (isStateOfBeing.val) {
+      await removeAction()
+      label.val = `${btnLabel.add} on Bluesky`
+      isStateOfBeing.val = false
+    } else {
+      await addAction()
+      label.val = `${btnLabel.progressive} on Bluesky`
+      isStateOfBeing.val = true
+      isJustApplied.val = true
+    }
+
+    isProcessing.val = false
+  }
+
+  const onMouseover = () => {
+    if(
+      isProcessing.val ||
+      isJustApplied.val ||
+      !isStateOfBeing.val
+    ) return
+
+    label.val = `${btnLabel.remove} on Bluesky`
+  }
+
+  const onMouseout = () => {
+    if (isJustApplied.val) {
+      isJustApplied.val = false
+    }
+    if(!isStateOfBeing.val) return
+
+    label.val = `${btnLabel.progressive} on Bluesky`
+  }
+
+  return () => button({
+    class: `action-button ${beingClass.val} ${processingClass.val} ${justAppliedClass.val}`,
+    onclick: onClick,
+    onmouseover: onMouseover,
+    onmouseout: onMouseout,
+  },
+    label.val,
+  )
+}
+```
+
+・BskyUserCell
+
+```ts:src/components/BskyUserCell.ts
+const Avatar = ({ avatar }: { avatar?: string }) => {
+  return avatar ? img({ src: avatar, width: "40" }) : div({ class: "no-avatar" })
+}
+
+export const BskyUserCell = ({
+  profile,
+  statusKey,
+  btnLabel,
+  addAction,
+  removeAction,
+}: {
+  profile: ProfileView,
+  statusKey: keyof ViewerState,
+  btnLabel: UserCellBtnLabel,
+  addAction: () => Promise<void>,
+  removeAction: () => Promise<void>
+}) => {
+  return div({ class: "bsky-user-content" },
+    div({ class: "icon-section"},
+      a({ href: `https://bsky.app/profile/${profile.handle}`, target: "_blank", rel: "noopener" },
+        Avatar({ avatar: profile.avatar }),
+      ),
+    ),
+    div({ class: "content" },
+      div({ class: "name-and-controller" },
+        div(
+          p({ class: "display-name" },
+            a({ href: `https://bsky.app/profile/${profile.handle}`, target: "_blank", rel: "noopener" },
+              profile.displayName ?? profile.handle,
+            ),
+          ),
+          p({ class: "handle" },
+            `@${profile.handle}`,
+          ),
+        ),
+        div(
+          ActionButton({
+            profile,
+            statusKey,
+            btnLabel,
+            addAction,
+            removeAction,
+          })
+        ),
+      ),
+      profile.description ? p({ class: "description" }, profile.description) : "",
+    ),
+  )
+}
+```
+
+# おわりに
+VanJSは `VanJS is a very thin layer on top of Vanilla JavaScript and DOM,`  という説明の通り、素のDOM APIのような手軽さで、VueやReactのような宣言的にUIが構築できて最高でした。今回の例のようなChrome Extensionのcontent scriptや、静的サイトのちょっとしたUIの実装などピンポイントでReactiveを実現したい時には、とても良い選択肢になると思います。ぜひ使って見てください!
diff --git a/images/1ad6e51eed13ae/2023-08-17-07-34-28.png b/images/1ad6e51eed13ae/2023-08-17-07-34-28.png
new file mode 100644
index 0000000..4bf1cee
Binary files /dev/null and b/images/1ad6e51eed13ae/2023-08-17-07-34-28.png differ
diff --git a/images/1ad6e51eed13ae/2023-08-17-08-54-41.png b/images/1ad6e51eed13ae/2023-08-17-08-54-41.png
new file mode 100644
index 0000000..9ffeb55
Binary files /dev/null and b/images/1ad6e51eed13ae/2023-08-17-08-54-41.png differ
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
index ad89ba6..693e7e4 100644
--- a/articles/1ad6e51eed13ae.md
+++ b/articles/1ad6e51eed13ae.md
@@ -40,13 +40,13 @@ https://github.com/kawamataryo/sky-follower-bridge

 ![](/images/1ad6e51eed13ae/2023-08-17-08-54-41.png)

-しかし、機能が増えるにつれ複雑化し可読性が悪くなっていました。そこで、軽量でシンプルなVanJSを使いリファクタリングしてみることにしました。
+しかし、機能が増えるにつれコードが複雑化し可読性が悪くなっていました。そこで、軽量でシンプルなVanJSを使いリファクタリングしてみることにしました。

 # 📝 結果

 Blueskyのユーザーセルの挿入箇所を例にリファクタリング結果を紹介します。
-なお実際のVanJSの導入のPRは以下です。
+なお実際のVanJSの導入のPRはこちらです。

 kawamataryo/sky-follower-bridge#7

@@ -55,7 +55,7 @@ kawamataryo/sky-follower-bridge#7
 リファクタリング前のコードは以下のようになっていました。
 `insertAdjacentHTML`で条件に合わせたDOMを構築、`addEventListener`でアクションボタンのclickイベントと、hoverイベントを登録しています。

-DOM APIで直接クラスの付け変えやテキストの書き換えを行なっているので、UIとイベントの関連が分かりにくく書いた本人ながらあまり触りたくないコードです😅
+DOM APIで直接クラスの付け変えやテキストの書き換えを行なっているので、UIとイベントの関連が分かりにくく、書いた本人ながらあまり触りたくないコードです😅

 [sky-follower-bridge/blob/main/src/lib/domHelpers.ts](https://github.com/kawamataryo/sky-follower-bridge/blob/782b75c8fc9fb54547eb44ffd8962a7729533a65/src/lib/domHelpers.ts#L57-L143)

@@ -151,7 +151,9 @@ export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortCo

 ## After

-VanJSでのリファクタリング後は、対象のDOMへのマウント処理は、対象のDOMに`van.add`でコンポーネントをマウントするのみ。VanJSのコンポーネント側も、親しみあるVueやReactのようにコンポーネントを分割し宣言的にUIを構築できたため、だいぶ可読性は高くなった気がします。今後の機能拡張のモチベーションも上がりました💪
+VanJSでのリファクタリング後です。
+
+対象のDOMへのマウント処理は、対象のDOMに`van.add`でコンポーネントをマウントするのみ。VanJSのコンポーネント側も、親しみあるVueやReactのようにコンポーネントを分割し宣言的にUIを構築できました。イベントとUIの関連が一目でわかるので、だいぶ可読性は良くなった気がします。今後の機能拡張のモチベーションも上がりました💪

 ・Mount
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
index 1cf9ece..f998876 100644
--- a/articles/1ad6e51eed13ae.md
+++ b/articles/1ad6e51eed13ae.md
@@ -1,5 +1,5 @@
 ---
-title: "VanJSで素のDOM操作をリファクタリングしたら最高だった"
+title: "VanJS で素のDOM操作をリファクタリングしたら最高だった"
 emoji: "🍦"
 type: "tech" # tech: 技術記事 / idea: アイデア
 topics: ["vanjs", "javascript"]
@@ -14,7 +14,7 @@ VanJSを試してみたら開発体験が良かったので紹介します。

 https://vanjs.org/

-gzip圧縮で**0.9kbと非常に軽量**で、バンドルサイズの肥大化を機にすることなく手軽に導入できます。
+gzip圧縮で**0.9kbと非常に軽量**で、バンドルサイズの肥大化を気にすることなく手軽に導入できます。

 ![](/images/1ad6e51eed13ae/2023-08-17-07-34-28.png)
 *他のUIフレームワークと比較しても圧倒的に軽量*
@@ -29,7 +29,7 @@ https://vanjs.org/about

 # 🛠️ リファクタリング対象

-[Sky Follower Bridge](https://chrome.google.com/webstore/detail/sky-follower-bridge/behhbpbpmailcnfbjagknjngnfdojpko)というX(Twitter)のFollower一覧から[Bluesky](https://bsky.app/)のユーザーを検索するChrome拡張機能を個人開発しています。今回はその拡張機能のcontent scriptの部分をVanJSでのリファクタリング対象としました。
+[Sky Follower Bridge](https://chrome.google.com/webstore/detail/sky-follower-bridge/behhbpbpmailcnfbjagknjngnfdojpko)というX(Twitter)のFollower一覧から[Bluesky](https://bsky.app/)のユーザーを検索するChrome拡張を個人開発しています。今回はその拡張機能のcontent scriptの部分をリファクタリング対象としました。

 https://www.youtube.com/watch?v=XcRcWjStIMc

@@ -40,7 +40,7 @@ https://github.com/kawamataryo/sky-follower-bridge

 ![](/images/1ad6e51eed13ae/2023-08-17-08-54-41.png)

-しかし、機能が増えるにつれコードが複雑化し可読性が悪くなっていました。そこで、軽量でシンプルなVanJSを使いリファクタリングしてみることにしました。
+しかし、機能が増えるにつれコードが複雑化し可読性に問題が出てきました。そこで、軽量でシンプルなVanJSを使いリファクタリングしてみることにしました。

 # 📝 結果
@@ -55,9 +55,12 @@ kawamataryo/sky-follower-bridge#7
 リファクタリング前のコードは以下のようになっていました。
 `insertAdjacentHTML`で条件に合わせたDOMを構築、`addEventListener`でアクションボタンのclickイベントと、hoverイベントを登録しています。

-DOM APIで直接クラスの付け変えやテキストの書き換えを行なっているので、UIとイベントの関連が分かりにくく、書いた本人ながらあまり触りたくないコードです😅
+Reactiveな動作は主にボタンに集中しています。
+
+![](/images/1ad6e51eed13ae/button.gif)
+
+このボタンの挙動を実現するためにDOM APIで直接クラスの付け変えやテキストの書き換えを行なっているのですが、UIとイベントの関連が分かりにくく、書いた本人ながらあまり触りたくないコードです😅

-[sky-follower-bridge/blob/main/src/lib/domHelpers.ts](https://github.com/kawamataryo/sky-follower-bridge/blob/782b75c8fc9fb54547eb44ffd8962a7729533a65/src/lib/domHelpers.ts#L57-L143)

 ```ts:src/lib/domHelpers.ts
 export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortController, followAction, unfollowAction }: {
@@ -153,7 +156,11 @@ export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortCo

 VanJSでのリファクタリング後です。

-対象のDOMへのマウント処理は、対象のDOMに`van.add`でコンポーネントをマウントするのみ。VanJSのコンポーネント側も、親しみあるVueやReactのようにコンポーネントを分割し宣言的にUIを構築できました。イベントとUIの関連が一目でわかるので、だいぶ可読性は良くなった気がします。今後の機能拡張のモチベーションも上がりました💪
+対象のDOMへのマウント処理は、対象のDOMに`van.add`でコンポーネントをマウントするのみ。VanJSのコンポーネント側も、親しみあるVueやReactのようにコンポーネントを分割し宣言的にUIを構築できました。
+
+Reactiveな挙動を持つボタンも、`van.state`で`van.derive`状態を管理することでイベントとUIの関連が一目でわかるので、だいぶ可読性は良くなった気がします。
+
+今後の機能拡張のモチベーションも上がりました💪

 ・Mount

@@ -300,6 +307,6 @@ export const BskyUserCell = ({
 ```

 # 👋 おわりに
-VanJSは `VanJS is a very thin layer on top of Vanilla JavaScript and DOM,`  という説明の通り、素のDOM APIのような手軽さで、VueやReactのような宣言的にUIが構築できて最高でした。
+VanJSは `VanJS is a very thin layer on top of Vanilla JavaScript and DOM`  という説明の通り、素のDOM APIのような手軽さで、VueやReactのような宣言的にUIが構築できて最高でした。

-今回の例のようなChrome Extensionのcontent scriptや、静的サイトのちょっとしたUIの実装などピンポイントでReactiveを実現したい時には、とても良い選択肢になると思います。ぜひ使って見てください!
+今回の例のようなChrome Extensionのcontent scriptや、静的サイトのちょっとしたUIの実装などピンポイントでReactiveな動きを実現したい時には、とても良い選択肢になると思います。ぜひ使って見てください。
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
index 564b2e2..14b5969 100644
--- a/articles/1ad6e51eed13ae.md
+++ b/articles/1ad6e51eed13ae.md
@@ -46,7 +46,7 @@ https://github.com/kawamataryo/sky-follower-bridge
 # 📝 結果

 Blueskyのユーザーセルの挿入箇所を例にリファクタリング結果を紹介します。
-なお実際のVanJSの導入のPRはこちらです。
+実際のVanJSの導入のPRはこちらです。

 kawamataryo/sky-follower-bridge#7

diff --git a/images/1ad6e51eed13ae/button.gif b/images/1ad6e51eed13ae/button.gif
new file mode 100644
index 0000000..d24d3f7
Binary files /dev/null and b/images/1ad6e51eed13ae/button.gif differ
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
index efaf3d1..e549737 100644
--- a/articles/1ad6e51eed13ae.md
+++ b/articles/1ad6e51eed13ae.md
@@ -46,7 +46,7 @@ https://github.com/kawamataryo/sky-follower-bridge
 # 📝 結果

 Blueskyのユーザーセルの挿入箇所を例にリファクタリング結果を紹介します。
-実際のVanJSの導入のPRはこちらです。
+実際のVanJSの導入PRはこちらです。

 kawamataryo/sky-follower-bridge#7
kawamataryo added a commit to kawamataryo/zenn-articles that referenced this pull request Aug 17, 2023
diff --git a/articles/1ad6e51eed13ae.md b/articles/1ad6e51eed13ae.md
index e549737..a30242b 100644
--- a/articles/1ad6e51eed13ae.md
+++ b/articles/1ad6e51eed13ae.md
@@ -53,14 +53,6 @@ kawamataryo/sky-follower-bridge#7
 ## Before

 リファクタリング前のコードは以下のようになっていました。
-`insertAdjacentHTML`で条件に合わせたDOMを構築、`addEventListener`でアクションボタンのclickイベントと、hoverイベントを登録しています。
-
-Reactiveな動作は主にボタンに集中しています。
-
-![](/images/1ad6e51eed13ae/button.gif)
-
-このボタンの挙動を実現するためにDOM APIで直接クラスの付け変えやテキストの書き換えを行なっているのですが、UIとイベントの関連が分かりにくく、書いた本人ながらあまり触りたくないコードです😅
-

 ```ts:src/lib/domHelpers.ts
 export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortController, followAction, unfollowAction }: {
@@ -152,6 +144,15 @@ export const insertBskyProfileEl = ({ dom, profile, statusKey, btnLabel, abortCo
 }
 ```

+`insertAdjacentHTML`で条件に合わせたDOMを構築、`addEventListener`でアクションボタンのclickイベントと、hoverイベントを登録しています。
+
+Reactiveな動作は主にボタンに集中しています。
+
+![](/images/1ad6e51eed13ae/button.gif)
+
+このボタンの挙動を実現するためにDOM APIで直接クラスの付け変えやテキストの書き換えを行なっているのですが、UIとイベントの関連が分かりにくく、書いた本人ながらあまり触りたくないコードです😅
+
+
 ## After

 VanJSでのリファクタリング後です。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant