Javascript

Vue.js学習してTodoアプリを作ってみた

次の作品を作る前に、Vue.jsを勉強する必要があったため
しばらくインプットにいそしむことに。

Vue.js学習の動機

今、ウェブカツでプログラミング学習をしていまして
その中でJavaScriptのフレームワークがいくつか出てくるんですよね。
出てくるのは良いんですが



毛根が死滅しそうな難易度

・・いやマジで。
私元々JavaScript自体にもの凄く苦手感があるというか

この20年のうちに2度JS独学で学習しようとして挫折し
去年作りたい物が出来たところで
3度目の挫折をしそうになったのでウェブカツに入った

という経緯があってかるーくトラウマじみたものがあるんです。

それでも何とかフレームワークの講義まではたどり着いたのですが
まぁ見事に

Backbone.jsで禿げ上がるほど悩み
Reactは分かったような分からないような気分で通り過ぎ

Reactのreduxとやらで毛根が瞬殺された


・・一体何だったんだあれは・・( ゚д゚)
まさに「何を言っているんだこれは・・」状態でしたorz

んで、まぁそんな中で唯一
「こ、これなら何か理解できそうな気がする!」となった
Vue.jsを、初めてのJSフレームワークとして学習することにしたのです。

学習に使った教材

  • ウェブカツのJS部上級に出てたコード
    動画は流し見で、結局コードを印刷してメモりつつ実際に動かして終了
  • 基礎から学ぶVue.js
    ねこさんが可愛いVue.jsの入門書。6章まで読了
    7章以降は実際にSPAとやらが必要になったら読もうかと


取りあえず上記2つを使って2日でざっくりインプット終了。
後は作りながら理解した方が早いはず、ということで。

Vue.jsでTodoアプリを作ってみた

基礎を確認する意味で、簡単なTodoアプリを作りました。
機能としては

  • 新規todoリスト作成
  • リスト削除
  • 実行済み、未実行をクリックで切り替える
  • 部分一致によるリスト検索
  • 削除時にアニメーションを入れる

詰まったところと解決策

実行済みと未実行の切り替えができねぇ!

・・何のことは無い、要素の指定方法がおかしかった。
リストのデータは配列で置き、その中にチェックされてるかどうかを判断するための
「isChecked」という要素をぶっ込んだんですね。

  data:  {
      items: [
        { id: 1, text: "sample todo1", isChecked: false },
        { id: 2, text: "sample todo2", isChecked: true }
      ],
  },

で、この「isCheckedを使ってmethodでtrueとfalse切り替えりゃいける!」と
リストの方はこんな感じで

            <li
              class="list__item"
              v-for="(item,index) in filteredItems"
              v-bind:key="item.id"
              v-bind:class="{'is-checked': .isChecked}"
            >
              <i
                class="fa fa-circle-thin icon-check"
                v-on:click="changeStatus(item)"
              ></i>
              <span>{{ item.text }}</span>

            </li>

切り替え用のmethodはこんな風に書いてみたら

methods: {
    changeStatus(item) {
      isChecked = isChecked ? false : true;
    },
}

・・押しても動かねぇ・・orz
devtoolで見たらv-onはちゃんと動いてるのに全く反映されねぇ・・

ここで詰まること2時間。
原因は

配列の中に入ってる要素なので、単に「isChecked」じゃなくて
配列名の「item」付けて「item.isChecked」にせな動かんわなそら!!

大体v-bind: keyのところでちゃんとitem.idって書いてるのに何故気づかなかった・・
そこを直すだけで動きました。
いやぁ思い込みって怖いですねぇホント(´・ω・`)

検索機能

まずはここを参考にして検索機能を付けてみました。
こういうときにcomputedを使うのね・・勉強になりました。

https://orizuru.io/blog/vue-js/search-function/

・・が、ここに書かれた方法を使うと
完全一致じゃないと上手いこといかない。
一部だけ一致で表示するってどうやって実装したらええんじゃー!

てことで「javascript 検索機能 一部一致」でググって出てきたのが

var text  = 'sampletext';
var keyword = 'ple';
if(text.indexOf(keyword) > -1){
  // 部分一致のときの処理
}

indexOf()を使うと、一致しなかったときに-1を返す、一致すると0以上の整数を返す。
なるほどこれが使えるな!
そしてこの機能は部分一致って言えばいいんだな!!←そこじゃない

これで部分一致になりました。

動作確認

これはコンポーネント化前のやつですが
コンポーネントにしてもちゃんと動いていました。

出来上がったやつのコード

もっと良い書き方があるんじゃないかと思いつつも
取りあえずこれで動いたので上げておきます。(CSSは省略)

コンポーネントとやらを使ってみたかったので
取りあえず全部一つのコンポーネントに放り込んでみたけど
これで良かったのか・・?

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>TODO</title>
    <link rel="stylesheet" href="dist/css/app.css" />
    <script src="https://use.fontawesome.com/e3ae05b8e6.js"></script>
  </head>
  <body>
    <div class="main">
      <h1 class="mainTitle">TODOS</h1>
      <div id="appTodo">
        <todo-item></todo-item>

      </div>
    </div>

    <script src="dist/js/bundle.js"></script>
  </body>
</html>
import Vue from "vue";

Vue.component("todo-item", {
  data: function() {
    return {
      items: [
        { id: 1, text: "sample todo1", isChecked: false },
        { id: 2, text: "sample todo2", isChecked: true }
      ],
      nextID: 3,
      todoItem: "",
      searchWord: ""
    };
  },
  computed: {
    filteredItems() {
      return this.searchItem(this.items, this.searchWord);
    }
  },
  methods: {
    addItem() {
      this.items.push({
        id: this.nextID++,
        text: this.todoItem,
        isChecked: false
      }),
        (this.todoItem = "");
    },
    doRemove(index) {
      this.items.splice(index, 1);
    },
    changeStatus(item) {
      item.isChecked = item.isChecked ? false : true;
    },
    searchItem(list, key) {
      return list.filter(function(item) {
        return item.text.indexOf(key) !== -1 || key === "";
      });
    }
  },
  template: `
  <div>
         <div class="form">
          <div class="inputArea">
            <input
              type="text"
              class="inputText"
              placeholder="something todo task"
              v-on:keydown.enter.shift="addItem"
              v-model="todoItem"
            />
          </div>
        </div>

        <div class="searchBox">
          <i class="fa fa-search searchBox__icon"></i>
          <input
            type="text"
            class="searchBox__input"
            placeholder="something keyword"
            v-model="searchWord"
          />
        </div>

        <ul class="list">
          <transition-group name="fade">
            <li
              class="list__item"
              v-for="(item,index) in filteredItems"
              v-bind:key="item.id"
              v-bind:class="{'is-checked': item.isChecked}"
            >
              <i
                class="fa fa-circle-thin icon-check"
                v-on:click="changeStatus(item)"
              ></i>
              <span>{{ item.text }}</span>
              <i
                class="fa fa-trash icon-trash"
                v-on:click="doRemove(index)"
              ></i>
            </li>
          </transition-group> 
        </ul>
</div>
`
});

new Vue({
  el: "#appTodo",
  data: {},
  computed: {},
  methods: {}
});

コメントはこちらから

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください