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