Aikの技術日記

技術的な進捗とか成果とかを細々と投稿するブログです。時々雑記も。

かの有名なサンバ踊りCSSに機能追加してみました

はじめに

私が日課となった技術系面白記事を発掘していたところ…。
つい最近に投稿された記事で、めったくっそ面白い記事を発見しちゃいました。 qiita.com

なぜ私がこのような物を作ったのか、突如インスピレーションしたのかもしれないし、
5月中旬の時の、私の精神状態がおかしかったのかもしれない。
ただ、同期の中では、想定外の事実に直面した時に思わず声をあげてしまうような人間がいたことや、
デバッグで頭がおかしくなってしまった時に、サンバを踊る文化があったことだけは事実である。

〜本家記事より抜粋〜

ちなみに本家の成果物は下記にございます。
Ctrl+Enterを押した後の衝撃は格別です…! yuichisemura.github.io

こんな面白い成果物に、せっかくなのでちょっと機能追加したいなと思い…。
GithubからForkボタンをポチーと押し作っちゃいました。

今回の記事では機能追加に至る道のりを書いていこうと思います。
ちなみに完成物はこちら: aik0aaac.github.io

ソースコードはこちら: github.com

((ちなみに筆者のFork経験はこれが初めてになります。
((勝手にやってしまってよかったのでしょうかね…暗黙の了解とかあるんでしょうか…。

機能拡張までの道のり

先に申し上げておきます。
今回機能追加と言っておきながら、大変申し訳ないことにコードの実装内容も大改編しちゃいました。
本当勝手に…ゴメンナサイ…。

Vue.jsの検討

対象となったリポジトリのコードを見ると、PureJSで全て記載されておりました。
jQueryで書かれていたら、まず間違いなくjQueryに甘えて機能追加していたでしょう…本当に感謝です。

ただ、例えばサンバを踊らせるための顔文字下記のコードですが:

<p class="left"></p><p class="face">(^p^)</p><p class="right"></p>
<p class="left"></p><p class="face">(^u^)</p><p class="right"></p>
<p class="left"></p><p class="face">(^s^)</p><p class="right"></p>
〜以下省略〜

…という風に書かれており…。
個人的に「Vue.jsのコンポーネントを利用すればスッキリ書けそう」と思い(後Vue.jsの勉強も兼ねて)、本コードにVue.jsを適用するところから考えてみました。

Vue.jsコンポーネント

ひとまずは先の部分をコンポーネント化しました。
Vue.js公式記事だったり他記事を見ながら勉強…。
出来上がったコードはこちらになります。

const SambaPerson = {
  props: ['mouth'],
  template: '<div class="samba-person">' +
    '<span class="left">\</span>' +
    '<span class="face">(^{{ mouth }}^)</span>' +
    '<span class="right">/</span>' +
    '</div>'
};

こうする事で<samba-person-component mouth="p"></samba-person-component>と書けば\(^p^)/が出る様に!
いやーコンポーネント化って神ですねまじ。

ちなみに、コンポーネント化するときはtemplateはrootとなるDOM要素が唯一1つ無ければならないらしく…。
(ルートエレメントは1つでないといけない)
例えば下記の様なHTMLをtemplate化しようとすると、Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.エラーがでます。

<span class="left"></span>
<span class="face">(^{{ mouth }}^)</span>
<span class="right"></span>

この仕様に気づかずエラーを連発しまくり非常に苦労しました…。
Vue.jsの根本を理解しておけばよかったのでしょうかな。むむむ…。

機能追加: カスタマイズ絵文字がサンバできる様に

さて本題、機能追加です。
私が思いついた機能は「自分で作ったカスタマイズ絵文字もサンバで踊れる様にすること」。
出来ればダンサーたちを増やしたかったりしたのですが…そこまでは手が回らず。

ひとまず下記の様な感じにできました。

"新規機能追加のプレビュー画像"
一緒に踊れるよ

上記処理に該当するコードは下記の様な感じ。
Vue.jsが保持するdatainputタグのValuev-modelでバインドさせてます。
このお陰で入力するたびに踊っている顔文字が変化していく様になりました!たまたまですけどね

<samba-person-component v-bind:mouth="customSambaPerson"></samba-person-component>
〜中略〜
<section id="samba_add_wrapper">
  <span>一緒に踊る:</span>
  <input type="text" v-model="customSambaPerson">
</section>
let sambaApp = new Vue({
  el: '#sambaApp',
  data: {
    customSambaPerson: '',
    sambaNowDoing: false,
  },
  components: {
    'samba-person-component': SambaPerson,
  },
…

命名規則、HTML構造、JS構造を整備

今回は、コード読解も兼ねて命名規則を自分好みに修正したり、HTML構造やJS構造を自分好みに整理したりと
人様の書いたコードの…特にパフォーマンスに影響しない項目にまで手を加えちゃうのに何とも言えない罪悪感を覚えながら…。
でも、自分が見やすいコードにするためには…と言い聞かせながら整備していきました。

命名規則については、例えば下記の様に:

  • yureshakeにしたり
  • yurezunot-shakeにしたり
  • leftleft-handにしたり…

HTML構造については、sectionタグやmainタグを積極的に用いる様にしただけです。
下手にいじるとCSSまで手を加えないといけないですからね…。
また、HTMLの骨組みは非常に美しいと思ったので、壊すのなんてとんでもない!と思ったのもあります。

JS構造については「共通化できる部分は共通化していく」「ただしコード行数が劇的に変化しないのであればそのままにしておく」という理念のもと、自分好みにしていきました。
例えばでいうと下記のコードを:

var tateList1 = document.getElementsByClassName("left");
for(var i = 0; i < tateList1.length; i++) {
    tateList1[i].classList.add('hurueruLeft');
}

こんな感じにしたりしました:

addClassToArrayByClassName('left-hand', 'shake-left');
〜中略〜
/**
 * 指定したクラス名を持つDOM要素に指定したクラス名を追加します。
 * @param {string} targetClassName 対象のDOM要素が持つクラス名
 * @param {string} addClassName 対象のDOM要素に追加したいクラス名
 */
function addClassToArrayByClassName(targetClassName, addClassName) {
  let array = document.getElementsByClassName(targetClassName);
  for (let i = 0; i < array.length; i++) {
    array[i].classList.add(addClassName);
  }
  return;
}

正直3行→1行になった程度なので、わざわざしなくてもよかったかもですね…。 本当勝手に色々弄ってしまって申し訳ないです…。

終わりに

振り返ってみれば結構改修しちゃった様な…。
でも意外と時間はかからなかったのは、自分自身がVue.jsやJavascriptへの理解を深めている証拠なのかもですかね。
また、今回の経験を通じVue.jsのコンポーネントという概念もちょっと理解できました。こんなに便利な概念だったとは…!

合わせて初のFork経験もできました!
本来はこっからプルリクエストが始まるらしいですが…。
私的には本件のプルリクエストを送信するつもりはないです。
元コードからだいぶ自分流に弄っちゃったので…これをプルリクエスト送信するのは憚られて…。

ともあれ色々とまた経験ができ、非常にホクホクです。
((ブログ記事もこうして書けましたし…
またもしビビッとくるものがあったらこうしてForkしたりなんだりしていけたらと思いますっ╭( ・ㅂ・)و

余談

今回の機能追加に伴い、GithubREADME.mdへ完成版のスクショを貼ろうとしたのですが…。
README.mdに画像を貼るにはどうしたら良いかわからず、色々調べた結果良さげな方法が見つかったので備忘録がわりにメモを。

cakecatz.hatenadiary.com こちらの記事にある様に、「スクショを置いておく専用のブランチ」を適当に切って、その中にスクショのみを入れていきます。
その後pushし、画像URLパスをMarkdownに下記の様に入力すればOK!
![alt文](画像URL)

※ちなみに画像URLのパスはこんな感じになります(2019/09/09現在):
https://raw.githubusercontent.com/[Githubアカウント名]/[リポジトリ名]/[ブランチ名]/[ファイル名]

ブランチを分けることで他のブランチが汚れることもなくなりますし、Githubサービス内で全てを完結可能になる…。
考えた人は間違いなく天才ですな( ゚д゚)ウム