TODOリスト
オンラインスキルアップのサンプルコード
by wintyo
HTML
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>
<script src="https://unpkg.com/vue-types"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
SCSS
* {
box-sizing: border-box;
}
.list {
position: relative;
padding: 0;
}
.item {
position: relative;
display: flex;
align-items: center;
width: 100%;
transition: all 0.5s;
padding: 10px;
margin-top: 10px;
border: solid 1px #ddd;
border-radius: 5px;
box-shadow: 0 0 10px 0 rgba(#000, 0.1);
cursor: pointer;
&__text {
flex: 1 1 0;
padding: 0 5px;
}
}
.flip {
// 要素が動くときにtransitionを設定する(.itemでtransitionを設定しているため-moveで書く必要はない)
// &-move {
// transition: transform 0.5s;
// }
// 要素が入るときのアニメーション
&-enter {
&-active {
opacity: 0;
transform: translate3d(0, -30px, 0);
}
&-to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
// 要素が消える時のアニメーション
&-leave {
&-active {
position: absolute;
}
&-to {
opacity: 0;
transform: translate3d(0, -30px, 0);
}
}
}
JavaScript
/**
* 入力フォームコンポーネント
*/
const InputForm = {
data() {
return {
text: ''
};
},
methods: {
/**
* 送信時
* @param {event} event - DOMのイベント
*/
onSubmit(event) {
event.preventDefault();
this.$emit('submit', this.$data.text);
this.$data.text = '';
}
},
template: `
<form @submit="onSubmit">
<input v-model="$data.text" type="text" placeholder="TODO" />
<button type="submit" :disabled="$data.text === ''">送信</button>
</form>
`
};
/**
* TODOリストコンポーネント
*/
const TodoList = {
props: {
todoList: VueTypes.arrayOf(VueTypes.shape({
id: VueTypes.number.isRequired,
isDone: VueTypes.bool.isRequired,
text: VueTypes.string.isRequired
})).isRequired
},
methods: {
/**
* 削除ボタンをクリックした時
* @param {event} event - DOMのイベント
* @param {number} todoId - TODOのID
*/
onDeleteTodo(event, todoId) {
event.stopPropagation();
this.$emit('delete', todoId);
}
},
template: `
<transition-group tag="ul" class="list" name="flip">
<template v-for="item in $props.todoList">
<li
:key="item.id"
class="item"
@click="$emit('check', item.id)"
>
<input type="checkbox" :checked="item.isDone" />
<span class="item__text">{{ item.text }}</span>
<button @click="onDeleteTodo($event, item.id)">削除</button>
</li>
</template>
</transition-group>
`
};
new Vue({
el: '#app',
components: {
InputForm,
TodoList
},
data() {
// 初期のTodoリストを用意する
const todoList = [
{
isDone: false,
text: '未着手タスク'
},
{
isDone: true,
text: '終了タスク'
}
];
return {
// idを順番につける
todoList: todoList.map((item, index) => ({ ...item, id: index })),
// 次のTODOに降るID番号
nextTodoId: todoList.length
};
},
methods: {
/**
* 送信された時
* @param {string} text - テキスト
*/
...