Appearance
Todo List
todo-list-v2
@/pages/40-lrn/20-vue3/90-demos/20-todo-list/components/TodoListV2.vue
待办
vue
<template>
<div>
<div v-if="isEditing" class="todo-edit">
<div>标题</div>
<div>
<input type="text" v-model="form.title" />
</div>
<div>内容</div>
<div>
<textarea v-model="form.content"></textarea>
</div>
<div>
<button @click="onCancelClick">返回</button>
<button @click="onSaveClick" :disabled="!form.title && !form.content">保存</button>
</div>
</div>
<div v-else class="todo-list">
<div>
待办
<button @click="onAddClick">+</button>
</div>
<div class="todo-list-items">
<div v-for="item in todoList" class="todo-list-item">
<h3>
<input
type="checkbox"
v-model="item.status"
@change="$event => onCheckChange($event, item)"
/>
{{ item.title }}
<span style="font-size: small;">{{ item.updatedAt || item.createdAt }}</span>
</h3>
<p>{{ item.content }}</p>
<div>
<button @click="onEditClick(item)">编辑</button>
<button @click="onDeleteClick(item)">删除</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue"
function newForm() {
return { id: undefined, title: undefined, content: undefined, createdAt: undefined, updatedAt: undefined, status: undefined, };
}
export default defineComponent({
name: 'TodoListV2',
data() {
return {
isEditing: false,
form: newForm(),
todoList: [],
}
},
methods: {
onCancelClick() {
this.isEditing = false;
this.form = newForm();
},
onSaveClick() {
this.isEditing = false;
if (!this.form.id) {
this.todoList.push({ ...this.form, id: Date.now(), createdAt: new Date().toLocaleString(), });
} else {
let oldIndex = this.todoList.findIndex(o => o.id === this.form.id);
if (oldIndex > -1) {
this.todoList.splice(oldIndex, 1, { ...this.form, updatedAt: new Date().toLocaleString(), });
} else {
this.todoList.push({ ...this.form, updatedAt: new Date().toLocaleString(), });
}
}
localStorage.setItem('todoListV2', JSON.stringify(this.todoList));
this.form = newForm();
},
onEditClick(item) {
this.form = { ...item, };
this.isEditing = true;
},
onAddClick() {
this.form = newForm();
this.isEditing = true;
},
onDeleteClick(item) {
let oldIndex = this.todoList.findIndex(o => o.id === item.id);
if (oldIndex > -1) {
this.todoList.splice(oldIndex, 1);
}
localStorage.setItem('todoListV2', JSON.stringify(this.todoList));
},
onCheckChange($event, item) {
item.status = $event.target.checked;
localStorage.setItem('todoListV2', JSON.stringify(this.todoList));
},
},
mounted() {
let _todoList = JSON.parse(localStorage.getItem('todoListV2') || '[]');
this.todoList.push(..._todoList);
},
})
</script>
<style scoped>
.todo-list-items {
max-height: 160px;
overflow: auto;
}
</style>
todo-list-v3
@/pages/40-lrn/20-vue3/90-demos/20-todo-list/components/TodoListV3.vue
待办
vue
<template>
<div>
<div v-if="isEditing" class="todo-edit">
<div>标题</div>
<div>
<input type="text" v-model="form.title" />
</div>
<div>内容</div>
<div>
<textarea v-model="form.content"></textarea>
</div>
<div>
<button @click="onCancelClick">返回</button>
<button @click="onSaveClick" :disabled="!form.title && !form.content">保存</button>
</div>
</div>
<div v-else class="todo-list">
<div>
待办
<button @click="onAddClick">+</button>
</div>
<div class="todo-list-items">
<div v-for="item in todoList" class="todo-list-item">
<h3>
<input
type="checkbox"
v-model="item.status"
@change="$event => onCheckChange($event, item)"
/>
{{ item.title }}
<span style="font-size: small;">{{ item.updatedAt || item.createdAt }}</span>
</h3>
<p>{{ item.content }}</p>
<div>
<button @click="onEditClick(item)">编辑</button>
<button @click="onDeleteClick(item)">删除</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, onMounted } from "vue"
export default defineComponent({
setup(props, ctx) {
// data
const form = reactive(newForm());
const isEditing = ref(false);
const todoList = reactive([newForm()].slice(1));
function newForm() {
return { id: undefined, title: undefined, content: undefined, createdAt: undefined, updatedAt: undefined, status: undefined, };
}
// methods
const onCancelClick = () => {
isEditing.value = false;
Object.assign(form, newForm());
};
const onSaveClick = () => {
isEditing.value = false;
if (!form.id) {
todoList.push({ ...form, id: Date.now(), createdAt: new Date().toLocaleString() });
} else {
let oldIndex = todoList.findIndex(o => o.id === form.id);
if (oldIndex > -1) {
todoList.splice(oldIndex, 1, { ...form, updatedAt: new Date().toLocaleString() });
} else {
todoList.push({ ...form, updatedAt: new Date().toLocaleString() });
}
}
localStorage.setItem('todoListV3', JSON.stringify(todoList));
Object.assign(form, newForm());
}
const onEditClick = (item) => {
Object.assign(form, item);
isEditing.value = true;
}
const onAddClick = () => {
Object.assign(form, newForm());
isEditing.value = true;
}
const onDeleteClick = (item) => {
let oldIndex = todoList.findIndex(o => o.id === item.id);
if (oldIndex > -1) {
todoList.splice(oldIndex, 1);
}
localStorage.setItem('todoListV3', JSON.stringify(todoList));
}
function onCheckChange($event, item) {
item.status = $event.target.checked;
localStorage.setItem('todoListV3', JSON.stringify(todoList));
}
onMounted(() => {
let _todoList = JSON.parse(localStorage.getItem('todoListV3') || '[]');
todoList.push(..._todoList);
});
return {
form,
isEditing,
todoList,
onCancelClick,
onSaveClick,
onEditClick,
onAddClick,
onDeleteClick,
onCheckChange,
}
},
})
</script>
<style scoped>
.todo-list-items {
max-height: 160px;
overflow: auto;
}
</style>
todo-list-v3-setup
@/pages/40-lrn/20-vue3/90-demos/20-todo-list/components/TodoListV3Setup.vue
待办
vue
<template>
<div>
<div v-if="isEditing" class="todo-edit">
<div>标题</div>
<div>
<input type="text" v-model="form.title" />
</div>
<div>内容</div>
<div>
<textarea v-model="form.content"></textarea>
</div>
<div>
<button @click="onCancelClick">返回</button>
<button @click="onSaveClick" :disabled="!form.title && !form.content">保存</button>
</div>
</div>
<div v-else class="todo-list">
<div>
待办
<button @click="onAddClick">+</button>
</div>
<div class="todo-list-items">
<div v-for="item in todoList" class="todo-list-item">
<h3>
<input type="checkbox" v-model="item.status" @change="$event => onCheckChange($event, item)" />
{{ item.title }}
<span style="font-size: small;">{{ item.updatedAt || item.createdAt }}</span>
</h3>
<p>{{ item.content }}</p>
<div>
<button @click="onEditClick(item)">编辑</button>
<button @click="onDeleteClick(item)">删除</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted } from "vue"
// data
const form = reactive(newForm());
const isEditing = ref(false);
const todoList = reactive([newForm()].slice(1));
function newForm() {
return { id: undefined, title: undefined, content: undefined, createdAt: undefined, updatedAt: undefined, status: undefined, };
}
// methods
const onCancelClick = () => {
isEditing.value = false;
Object.assign(form, newForm());
};
const onSaveClick = () => {
isEditing.value = false;
if (!form.id) {
todoList.push({ ...form, id: Date.now(), createdAt: new Date().toLocaleString() });
} else {
let oldIndex = todoList.findIndex(o => o.id === form.id);
if (oldIndex > -1) {
todoList.splice(oldIndex, 1, { ...form, updatedAt: new Date().toLocaleString() });
} else {
todoList.push({ ...form, updatedAt: new Date().toLocaleString() });
}
}
localStorage.setItem('todoListV3Setup', JSON.stringify(todoList));
Object.assign(form, newForm());
}
const onEditClick = (item) => {
Object.assign(form, item);
isEditing.value = true;
}
const onAddClick = () => {
Object.assign(form, newForm());
isEditing.value = true;
}
const onDeleteClick = (item) => {
let oldIndex = todoList.findIndex(o => o.id === item.id);
if (oldIndex > -1) {
todoList.splice(oldIndex, 1);
}
localStorage.setItem('todoListV3Setup', JSON.stringify(todoList));
}
function onCheckChange($event, item) {
item.status = $event.target.checked;
localStorage.setItem('todoListV3Setup', JSON.stringify(todoList));
}
onMounted(() => {
let _todoList = JSON.parse(localStorage.getItem('todoListV3Setup') || '[]');
todoList.push(..._todoList);
});
</script>
<style scoped>
.todo-list-items {
max-height: 160px;
overflow: auto;
}
</style>