<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>搞事情</title>
<link rel="stylesheet" href="lib/normalize.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="main">
<div class="navbar">
<h1>表事情</h1>
</div>
<div class="header">
开黑了么就写作业?
</div>
<form @submit.prevent="merge" id="task-form">
<div class="wrap">
<input v-model="current.title" id="task-input" type="text" autocomplete="off">
<div v-if="current.id" class="detail">
<textarea v-model="current.desc"></textarea>
<input v-model="current.alert_at" type="datetime-local">
<button class="primary" type="submit">submit</button>
</div>
</div>
</form>
<div class="task-list">
<div class="wrap">
<div class="segment-title">未完成</div>
<task :todo="todo"
v-if="!todo.completed"
v-for="(todo, index) in list"
></task>
</div>
</div>
<div class="task-list">
<div class="wrap">
<div class="segment-title">已完成</div>
<div v-if="todo.completed" v-for="(todo, index) in list" class="item completed">
<div @click="toggle_complete(todo.id)" class="toggle-complete"></div>
{{todo.title}}
<button @click="remove(todo.id)">删除</button>
</div>
</div>
</div>
</div>
<audio id="alert-sound">
<source src="./sound/alert.mp3">
</audio>
<template id="task-tpl">
<div class="item">
<div @click="action('toggle_complete', todo.id)" class="toggle-complete"></div>
<span class="title">{{todo.title}}</span>
<button @click="action('remove', todo.id)">删除</button>
<button @click="action('set_current', todo)">更新</button>
<button @click="action('toggle_detail', todo.id)">详情</button>
<div v-if="todo.show_detail" class="detail">
{{todo.desc || '暂无详情'}}
</div>
</div>
</template>
<script src="https://cdn.bootcss.com/vue/2.4.4/vue.min.js"></script>
</body>
</html>
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
position: relative;
}
body {
color: #444;
}
input, button, textarea {
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 3px;
padding: 5px 10px;
}
input, textarea {
outline: none;
display: block;
width: 100%;
margin-bottom: 10px;
-webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, .1);
-moz-box-shadow: 0 2px 3px rgba(0, 0, 0, .1);
box-shadow: 0 2px 3px rgba(0, 0, 0, .1);
}
input:focus, textarea:focus {
border: 1px solid #db4c3f;
}
button.primary {
background: #db4c3f;
color: #f7f3ea;
}
.wrap {
max-width: 500px;
margin: 0 auto;
padding-left: 10px;
padding-right: 10px;
}
.navbar, .header {
text-align: center;
}
.navbar {
background: #db4c3f;
color: #f7f3ea;
padding: 10px 0;
}
.navbar h1 {
font-size: 24px;
margin: 0;
}
.header {
padding: 20px 0;
color: #555;
font-size: 18px;
}
#alert-sound {
display: none;
}
.task-list .item {
padding: 5px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.task-list .item button {
display: none;
font-size: 80%;
background: #fff;
}
.task-list .item:hover {
background: rgba(0, 0, 0, .03);
}
.task-list .item:hover button {
display: inline-block;
}
.task-list .item .title {
padding: 10px;
}
.task-list .item .detail {
display: block;
font-size: 80%;
color: #666;
}
.task-list .item > * {
padding: 5px;
display: inline-block;
line-height: 1.2;
vertical-align: middle;
}
.toggle-complete {
width: 30px;
height: 30px;
background: #50beff;
border: 1px solid #46a9e4;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
}
.toggle-complete:hover {
background: #3e9bd2;
border-color: #3587b7;
}
.completed .toggle-complete {
background: #ccc;
border-color: #bbb;
}
.segment-title {
color: #aaa;
margin-top: 15px;
margin-bottom: 5px;
font-weight: lighter;
}
/* myStorage.js */
;(function () {
window.ms = {
set: set,
get: get,
};
function set(key, val) {
localStorage.setItem(key, JSON.stringify(val));
}
function get(key) {
var json = localStorage.getItem(key);
if (json) {
return JSON.parse(json);
}
}
})();
/* main.js */
;(function () {
'use strict';
var Event = new Vue();
var alert_sound = document.getElementById('alert-sound');
function copy(obj) {
return Object.assign({}, obj);
}
Vue.component('task', {
template: '#task-tpl',
props: ['todo'],
methods: {
action: function (name, params) {
Event.$emit(name, params);
}
}
})
new Vue({
el: '#main',
data: {
list: [],
last_id: 0,
current: {}
},
mounted: function () {
var me = this;
this.list = ms.get('list') || this.list;
this.last_id = ms.get('last_id') || this.last_id;
setInterval(function () {
me.check_alerts();
}, 1000);
Event.$on('remove', function (id) {
if (id) {
me.remove(id);
}
});
Event.$on('toggle_complete', function (id) {
if (id) {
me.toggle_complete(id);
}
});
Event.$on('set_current', function (id) {
if (id) {
me.set_current(id);
}
});
Event.$on('toggle_detail', function (id) {
if (id) {
me.toggle_detail(id);
}
});
},
methods: {
check_alerts: function () {
var me = this;
this.list.forEach(function (row, i) {
var alert_at = row.alert_at;
if (!alert_at || row.alert_confirmed) return;
var alert_at = (new Date(alert_at)).getTime();
var now = (new Date()).getTime();
if (now >= alert_at) {
alert_sound.play();
var confirmed = confirm(row.title);
Vue.set(me.list[i], 'alert_confirmed', confirmed);
}
})
},
merge: function () {
var is_update, id;
is_update = id = this.current.id;
if (is_update) {
var index = this.find_index(id);
Vue.set(this.list, index, copy(this.current));
} else {
var title = this.current.title;
if (!title && title !== 0) return;
var todo = copy(this.current);
this.last_id++;
ms.set('last_id', this.last_id);
todo.id = this.last_id;
this.list.push(todo);
}
this.reset_current();
},
toggle_detail: function (id) {
var index = this.find_index(id);
Vue.set(this.list[index], 'show_detail', !this.list[index].show_detail)
},
remove: function (id) {
var index = this.find_index(id);
this.list.splice(index, 1);
},
next_id: function () {
return this.list.length + 1;
},
set_current: function (todo) {
this.current = copy(todo);
},
reset_current: function () {
this.set_current({});
},
find_index: function (id) {
return this.list.findIndex(function (item) {
return item.id == id;
})
},
toggle_complete: function (id) {
var i = this.find_index(id);
Vue.set(this.list[i], 'completed', !this.list[i].completed);
}
},
watch: {
list: {
deep: true,
handler: function (n, o) {
if (n) {
ms.set('list', n);
} else {
ms.set('list', []);
}
}
}
}
});
})();
登录后评论