【angular】TodoList小项目(已开源)

参考:https://segmentfault.com/a/1190000013519099

文章目录

效果:

准备工作

创建项目:ng new my-app

导航到workspace 文件夹:cd my-app

启动这个项目:ng serve --open

创建组件:ng generate component component/todoList

组件的路径是:

创建了组件后,要把它在根组件配置(app.module.ts):

根据TS文件todo-list.component.ts,我们创建的todoList这个组件的名字叫做:app-todo-list。把组件引入到总页面中(app.component.html),启动服务看看。成功!到这里我们已经知道组件怎么创建和引用了。

接下来开始写TodoList!

效果:

html 复制代码
<!-- todo-list.component.html -->
<header>
    <section>
        <label for="title">TodoList</label>
        <input type="text" placeholder="添加ToDo">
    </section>
</header>
css 复制代码
/* todo-list.component.css */
header {
    height: 70px;
    background-color: #333;
}

header section{
    display: flex;
    justify-content: space-between;
}

section {
    margin: 0 auto;
    width: 70vw;
    
}

header section label {
    font-size: 28px;
    color: #fff;
    line-height: 70px;
}

header section input {
    width: 35%;
    margin: 10px 0;
    padding-left: 15px;
    border-radius: 10px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.24), 0 1px 6px rgba(0,0,0,0.45) inset;
}

Todo、Doing、Done

样式(HTML+CSS)

效果大致是这样:


一些细节

复选框与文字对齐

参考:css复选框和文字对齐-CSDN博客

css 复制代码
.item .listItem input[type=checkbox] {
    width: 23px;
    height: 23px;
    /* 复选框与文字对齐 */
    display: inline-block;
    vertical-align: middle;
    margin: 0 10px 2px;
}

给Done的item设置阴影

在item外面套一层mask,设置背景黑色。item设置opacity即可。

参考:css为图片添加一层蒙版_css给图片加一层蒙版-CSDN博客

html 复制代码
<div class="item done">
    <h2>Done</h2>
    <div class="list">
        <!-- 外面的阴影 -->
        <div class="mask">
            <div class="listItem">
                <input type="checkbox">吃饭3
            </div>        
        </div>
    </div>
</div>
css 复制代码
.done .listItem {
    box-shadow: -5px 0 0 0 #999999;
    opacity: 0.7;
}

.done .mask {
    background: #000;
}

最终代码

html 复制代码
<!-- todo-list.component.html -->
<header>
    <section>
        <label for="title">TodoList</label>
        <input type="text" placeholder="添加ToDo">
    </section>
</header>

<section>
    <div class="item todo">
        <h2>Todo</h2>
        <div class="list">
            <div class="listItem">
                <input type="checkbox">吃饭1
            </div>
            <div class="listItem">
                <input type="checkbox">睡觉1
            </div>
            <div class="listItem">
                <input type="checkbox">喝水1
            </div>
        </div>
    </div>
    <div class="item doing">
        <h2>Doing</h2>
        <div class="list">
            <div class="listItem">
                <input type="checkbox">吃饭2
            </div>
            <div class="listItem">
                <input type="checkbox">睡觉2
            </div>
            <div class="listItem">
                <input type="checkbox">喝水2
            </div>
        </div>
    </div>
    <div class="item done">
        <h2>Done</h2>
        <div class="list">
            <!-- 外面的阴影 -->
            <div class="mask">
                <div class="listItem">
                    <input type="checkbox" checked="checked">吃饭3
                </div>        
            </div>
        </div>
    </div>
</section>
css 复制代码
/* todo-list.component.css */
header {
    height: 70px;
    background-color: #333;
}

header section {
    display: flex;
    justify-content: space-between;
}

section {
    margin: 0 auto;
    width: 70vw;

}

header section label {
    font-size: 28px;
    color: #fff;
    line-height: 70px;
}

header section input {
    width: 35%;
    margin: 10px 0;
    padding-left: 15px;
    border-radius: 10px;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset;
}

.item {
    margin: 20px 0;
}

.item h2 {
    color: #000;
    font-size: 28px;
    font-weight: 700;
    margin-bottom: 20px;
}

.item .listItem {
    background-color: #dbdbdb;
    margin: 15px 0;
    height: 40px;
    line-height: 40px;
    font-size: 16px;
}

.todo .listItem {
    box-shadow: -5px 0 0 0 #ede719;
}

.doing .listItem {
    box-shadow: -5px 0 0 0 yellowgreen;
}

.done .listItem {
    box-shadow: -5px 0 0 0 #999999;
    opacity: 0.7;
}

.done .mask {
    background: #000;
}


.item .listItem input[type=checkbox] {
    width: 23px;
    height: 23px;
    /* 复选框与文字对齐 */
    display: inline-block;
    vertical-align: middle;
    margin: 0 10px 2px;
}

功能(TS)

将输入框内容加入todoList(addTodo)

定义数据,写addTodo方法。

typescript 复制代码
//todo-list.component.ts
export class TodoListComponent {
    public todo: any = '' //在input栏,即将加入todoList
    public todoList = [] as any;
    public doingList = [] as any;
    public doneList = [] as any;


	// 添加代办时间到todo
    addTodo(e: any) {
	    // 回车
	    if (e.keyCode == 13) {
	        this.todoList.push(this.todo)
	        this.todo = ''
	    }
    }
}

在html中绑定数据和时间:

输入框:

html 复制代码
<!-- todo-list.component.html -->
<header>
    <section>
        <label for="title">TodoList</label>
        <input type="text" (keydown)="addTodo($event)" [(ngModel)]='todo' placeholder="添加ToDo">
    </section>
</header>

todoList:

html 复制代码
<div class="item todo">
    <h2>Todo</h2>
    <div class="list">
        <div class="listItem" *ngFor="let item of todoList">
            <input type="checkbox">{{item.todo}}
        </div>
    </div>
</div>

遇到的问题与解决:

写addTodo方法:
TypeScript 错误 property does not exist on type Object - 掘金 (juejin.cn)
Parameter 'xxx' implicitly has an 'any' type的解决_implicitly has an 'any' type-CSDN博客

在绑定(ngModel)='todo':解决Angular报错 Can't bind to 'ngModel' since it isn't a known property of 'input'-CSDN博客

将todoObj push进todoList:类型"{ name: any; value: string; }"的参数不能赋给类型"never"的参数。_类型"any"的参数不能赋给类型"never"的参数_干饭了干饭了1的博客-CSDN博客

将todo事件改到doing

功能:todo打勾(点击事件),它就加到doingList中。doing到done、done到todo以此类推。

typescript 复制代码
// todo 改为doing
todoChange(key: any) {
    this.doingList.push(this.todoList[key])
    this.todoList.splice(key,1)
}
html 复制代码
<div class="item todo">
    <h2>Todo</h2>
    <div class="list">
        <div class="listItem" *ngFor="let item of todoList;let key=index">
            <input type="checkbox" (click)="todoChange(key)">{{item}}
        </div>
    </div>
</div>

刷新一下,发现页面中的数据都没了。如果想要保存页面数据,我们需要做以下操作。

服务

参考:angularcli 第七篇(service 服务) - 撑死的喵~ - 博客园 (cnblogs.com)

在控制台创建服务:

复制代码
ng g service services/storage

app.module.ts中引入创建的服务:

在要使用的页面引入和注入服务:

具体服务:

可能的报错:ts报错:类型"string | null"的参数不能赋给类型"string"的参数。 不能将类型"null"分配给类型"string"。-CSDN博客

typescript 复制代码
// storage.service.ts
import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
})
export class StorageService {

    constructor() { }

    setItem(key: any, value: any) {
        localStorage.setItem(key, JSON.stringify(value));
    }
    getItem(key: any) {
        return JSON.parse(localStorage.getItem(key) || '')
    }
}

在每个会修改todoList、doingList、doneList的代码下面加上对应的this.storage.setItem('xx',this.xx),把数据存放在本地中。

typescript 复制代码
// 添加代办时间到todo
addTodo(e: any) {
    // 回车
    if (e.keyCode == 13) {
        this.todoList.push(this.todo)
        this.todo = ''
        this.storage.setItem('todoList',this.todoList)
    }
}

// todo 改为doing
todoChange(key: any) {
    this.doingList.push(this.todoList[key])
    this.todoList.splice(key,1)
    this.storage.setItem('todoList',this.todoList)
    this.storage.setItem('doingList',this.doingList)
}

// doing 改为done
doingChange(key: any) {
    this.doneList.push(this.doingList[key])
    this.doingList.splice(key,1)
    this.storage.setItem('doneList',this.doneList)
    this.storage.setItem('doingList',this.doingList)
}

// done 改为todo
doneChange(key: any) {
    this.todoList.push(this.doneList[key])
    this.doneList.splice(key,1)
    this.storage.setItem('todoList',this.todoList)
    this.storage.setItem('doneList',this.doneList)
}

大功告成!

参考

Angular - Angular 文档简介

angularjs - 和我一起入坑,Angular入门,Angular版的ToDoList - 个人文章 - SegmentFault 思否

css复选框和文字对齐-CSDN博客

box-shadow 设置单边、多边阴影 - 掘金 (juejin.cn)

css为图片添加一层蒙版_css给图片加一层蒙版-CSDN博客

js 键盘监听(回车)_js监听键盘回车-CSDN博客

TypeScript 错误 property does not exist on type Object - 掘金 (juejin.cn)

Parameter 'xxx' implicitly has an 'any' type的解决_implicitly has an 'any' type-CSDN博客

angularcli 第七篇(service 服务) - 撑死的喵~ - 博客园 (cnblogs.com)

ts报错:类型"string | null"的参数不能赋给类型"string"的参数。 不能将类型"null"分配给类型"string"。-CSDN博客

开源

https://gitee.com/karshey/angular-todo-list

相关推荐
卸任9 小时前
Vibe coding工具使用心得
前端·ai编程
brien99 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance10 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M10 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写10 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李10 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易10 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding10 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马10 小时前
前沿视界
前端
kyriewen10 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员