Todoリスト #2

前回のviewからvueの機能を追加して完成させましょう。

リストを表示する

Todoリストの表示を行なっていきましょう

前回は

<ul>
  <li>
    <span>Todo1</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo2</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo3</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
</ul>

上記のcodeをv-forを使用したcodeに変えていきましょう

そのためにApp.vueからComplete.vueにリストを渡しましょう。

<div>
  <p>imcomplete</p>
  <div>
    <Incomplete :list="imcompleteList" />
  </div>
</div>

そしてdataにimcompleteListを定義しましょう

data() {
  return {
    imcompleteList: []
  };
}

受け取る側

props: {
    list: {
      type: Array,
      default: () => []
    }
},

そしてtemplate側で

<ul>
    <li v-for="(item, i) in list" :key="i">
      <span>{{ item }}</span>
      <button>Return</button>
      <button>Delete</button>
    </li>
  </ul>

とします

仮にlistに

['Todo1', 'Todo2', 'Todo3']

となっていた場合はv-forにて

<ul>
  <li>
    <span>Todo1</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo2</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo3</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
</ul>

な結果となります

li配下をループして各中身をitem, indexをiとしてます

こちらをIncomplete, Complete両方に適応させましょう。

  • dataの配列は別々にしてtemplate側でも渡す値を別にしましょう script
data() {
  return {
    imcompleteList: [],
    completeList: []
  };
}

template

<div>
  <p>complete</p>
  <div>
    <Complete :list="completeList" />
  </div>
</div>

Inputで入力した値を反映させる

今のままだと、inputに入力した値はどこにも反映されません。

なので入力した値を反映させます

inputタグにはv-modelを利用することによりscript側で値を取得することができます。

<input v-model="todo" type="text">

script側にも

data() {
    return {
      todo: "",
      imcompleteList: [],
      completeList: []
    };
  },

次にAdd Todoボタンを押したら、入力した値をimcompleteListに追加しましょう

template側のボタンではv-on:clickもしくは@clickを使用して、ボタンをclickした時を検知します

<button @click="addTodo">Add Todo</button>

この時にaddTodoというのはscript側に定義してあります。

methods: {
  addTodo() {
    this.imcompleteList.push(this.todo);
    // reset
    this.todo = "";
  }
}

this.todoというのはdata内のtodoのことです

imcompleteListに追加した後にtodoをリセットすることによりinput内の入力された値を消してます

imcompleteListに追加したことにより、Incompleteが再描画されて追加されているかと思います

imcompleteListを完了に持っていく

Completeボタンを押したら対象のTodoをCompleteに移動させます

まずはCompleteボタンを押したら発火するmethodを作成しましょう

<li v-for="(item, i) in list" :key="i">
  <span>{{ item }}</span>
  <button @click="completeTodo(i)">Complete</button>
  <button>Delete</button>
</li>

script

methods: {
    completeTodo(i) {
      this.$emit("complete", i);
    },
}

emitという新しいものが出てきました

emitは子コンポーネントから親コンポーネントに対して、eventを送ることができます

コンポーネントであるApp.vueをこのようにしてみましょう

<Incomplete :list="imcompleteList" @complete="completeTodo" />

script

methods: {
  completeTodo(i) {
      // 対象のTodoを取得
      const todo = this.imcompleteList[i];
      // 対象のTodoをcompleteListに追加
      this.completeList.push(todo);
      // imcompleteListから対象のTodoを削除
      this.imcompleteList.splice(i, 1);
    },
}

emitの第1引数にevent名, そのあとは引数を入れることができます

こちら同じ要領でComplete TodoからImcomplete Todoに移してみましょう

Todoを削除する

最後に削除機能を追加します

今までのことを活かしてみましょう

Deleteボタンを押した際に発火するmethodを定義します

<li v-for="(item, i) in list" :key="i">
        <span>{{ item }}</span>
        <button @click="imcompleteTodo(i)">Return</button>
        <button @click="deleteTodo(i)">Delete</button>
</li>

script

methods: {
  deleteTodo(i) {
      this.$emit("delete", "complete", i);
    }
}

App側で受け取る記述をしましょう

<Complete :list="completeList" @imcomplete="imcompleteTodo" @delete="deleteTodo"/>

script

methods: {
  deleteTodo(type, i) {
      if (type === "imcomplete") {
        this.imcompleteList.splice(i, 1);
      } else if (type === "complete") {
        this.completeList.splice(i, 1);
      }
    }
}

以上である程度の機能は作れたかと思います。

サンプルはこちらになります

admiring-euclid-48ow8 - CodeSandbox

Todoリスト #1

まずviewから作成します。

 => vueの機能をあまり使用せずに見た目を作成します。

ファイル構成

今回はシンプルにします。

components --- Complete.vue      // 完了したTodoリスト
            |- Imcomplete.vue  // 未完了のTodoリスト
App.vue

こちらの2ファイルを使用します。

App.vueにTodoを入力するInputを作成

<div>
  <input type="text">
  <button>Add Todo</button>
</div>

各componentにTodoリストを作成

3つほどTodoを作成してみましょう

components/Complete.vue

<ul>
  <li>
    <span>Todo1</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo2</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo3</span>
    <button>Return</button>
    <button>Delete</button>
  </li>
</ul>

components/Imcomplete.vue

<ul>
  <li>
    <span>Todo1</span>
    <button>Complete</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo2</span>
    <button>Complete</button>
    <button>Delete</button>
  </li>
  <li>
    <span>Todo3</span>
    <button>Complete</button>
    <button>Delete</button>
  </li>
</ul>

App.vueから各componentを呼び出す

<template>
  <div id="app">
    <div>
      <input type="text">
      <button>Add Todo</button>
    </div>
    <div class="flex">
      <div>
        <p>imcomplete</p>
        <div>
          <Incomplete />
        </div>
      </div>
      <div>
        <p>complete</p>
        <div>
          <Complete />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Incomplete from "./components/Imcomplete";
import Complete from "./components/Complete";

export default {
  name: "App",
  components: {
    Incomplete,
    Complete
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.flex {
  display: flex;
  justify-content: space-around;
}
.flex > div {
  width: 45%;
}
</style>

ここまででviewの部分は完成しました。

次回はvueの機能を使いながら完成を目指していきましょう。

.vueファイルの書き方

.vueファイルの書き方

<template>
  // ここにHTMLを記述
</template>

<script>
export default {
  // ここにVue Scriptを記述
}
</script>

<style>
  // ここにCSSを記述
</style>

別の.vueファイルを読み込む

<script>
import VueFile from "相対パス"

export default {
  components: { VueFile }
}
</script>

ファイルが増える場合はコンマ区切りで追加していく

Todoリストを作ってみる

CodeSandboxでTodoリストを作ってみましょう

Vueの基礎 - Vue.js勉強記

ここで学んだことを活かせれば作れるはず

大まかな仕様

・input tagにTodoを入力する

・Add Todo ボタンをクリックしたらimcomplete領域に表示する

・imcomplete領域にあるTodoのComplete ボタンをクリックしたら、

 そのTodoをcomplete領域に移動する

・complete領域にあるTodoのReturn ボタンをクリックしたら、

 そのTodoをimcomplete領域に移動する

・Delete ボタンをクリックしたら、そのTodoを削除する

Vue的な仕様

・imcomplete, complete領域にあるTodoリストはそれぞれ別Componentを作成してみる

かなりシンプルなTodoリストですが、基礎には良い感じになると思います

ポイント

・input tagに入力されたTodoのdataを取得

・各ボタンのイベントを発火する

・TodoリストをLoopさせて表示させる

・Todoリストの追加や削除に伴うdataの扱い

次回から解説しながら作っていきます

Vue CLI

自分のPCに入れたくない人はここで開発するのが良いかも

CodeSandbox: Online IDE for Rapid Web Development

Vue CLIのインストール

$ npm install -g @vue/cli

プロジェクト作成

$ vue create vue-project

色々質問があるけど、今回は適当に

$ cd vue-project
$ npm run serve
http://localhost:8080

にアクセス

Vueの基礎

Hello World

https://jsfiddle.net/shogo_t2525/w5m9qLd8/

・elオプションにDOMを指定

・dataオプションにリアクティブにするオブジェクト

リアクティブ

https://jsfiddle.net/shogo_t2525/w5m9qLd8/

オブジェクトの変更を検知してhtmlの表示を更新する

dataにあるもの => リアクティブ

constなど => 非リアクティブ

ディレクティブ

https://jsfiddle.net/shogo_t2525/Ls7o8mrb/

・v-から始まる特別な属性

・ディレクティブを使うことで様々な機能が利用可能

v-bind, v-for, v-if, v-onなど...

v-bind は省略可能

v-on は @に省略可能

コンポーネント

コンポーネント => 部品と思ってもらえればOK

毎回記述するのは面倒なので部品化しちゃいましょうって話

https://jsfiddle.net/shogo_t2525/6hscb41y/

・データの受け渡し

・親コンポーネントと子コンポーネントの関係性

 親コンポーネントから子コンポーネントはpropsにてデータを渡すことができる

 子コンポーネントから親コンポーネントに何かしたい場合はemitを使用する

computed

算出プロパティ => わかりにくい...

https://jsfiddle.net/shogo_t2525/0vzf2Lk3/

つまり

・computedで宣言されたものはcacheして保持する

・computed内のリアクティブなdataが変更された場合に再計算を行う