【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

相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen12 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马13 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu13 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss