青训营前端实践笔记
二.使用JavaScript实现待办事项
1.HTML部分
<!DOCTYPE html>
<html>
<head>
<title>Todo List</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>Todo List</h1>
<div id="wrapper">
<input type="text" id="taskInput" placeholder="Add a new task">
<button id="addButton">Add</button>
<ul id="taskList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
2.CSS部分(style.css)
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
}
h1 {
text-align: center;
}
#wrapper {
margin-top: 20px;
}
input[type="text"] {
padding: 10px;
font-size: 16px;
}
button {
padding: 10px 20px;
font-size: 16px;
}
#taskList {
list-style-type: none;
padding: 0;
}
.taskItem {
display: flex;
align-items: center;
}
.taskItem input[type="checkbox"] {
margin-right: 10px;
}
.taskItem input[type="text"] {
flex: 1;
padding: 5px;
font-size: 14px;
}
.taskItem .deleteButton {
padding: 5px 10px;
background-color: #ff0000;
color: #fff;
border: none;
cursor: pointer;
}
.completed {
text-decoration: line-through;
color: #888;
}
3.JavaScript部分(app.js)
const taskInput = document.getElementById('taskInput');
const addButton = document.getElementById('addButton');
const taskList = document.getElementByIdfunction addTask() {
const taskName = taskInput.value;
if (taskName) {
const newTask = document.createElement('li');
newTask.className = 'taskItem';
newTask.innerHTML = `
<input type="checkbox">
<input type="text" value="${taskName}">
<button class="deleteButton">Delete</button>
`;
taskList.appendChild(newTask);
taskInput.value = '';
deleteButton.addEventListener('click', deleteTask);
const checkbox = newTask.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', toggleComplete);
}
}
function deleteTask() {
const taskItem = this.parentElement;
taskList.removeChild(taskItem);
}
function toggleComplete() {
const taskItem = this.parentElement;
const taskText = taskItem.querySelector('input[type="text"]');
taskText.classList.toggle('completed');
}
addButton.addEventListener('click', addTask);
function getTasksFromLocalStorage() {
const tasks = JSON.parse(localStorage.getItem('tasks')) || [];
tasks.forEach(function(task) {
addTaskToDOM(task);
});
}
function saveTaskToLocalStorage(taskName) {
const tasks = JSON.parse(localStorage.getItem('tasks')) || [];
tasks.push(taskName);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
function deleteTaskFromLocalStorage(taskName) {
const tasks = JSON.parse(localStorage.getItem('tasks')) || [];
const updatedTasks = tasks.filter(function(task) {
return task !== taskName;
});
localStorage.setItem('tasks', JSON.stringify(updatedTasks));
}
function addTaskToDOM(taskName) {
const newTask = document.createElement('li');
newTask.className = 'taskItem';
newTask.innerHTML = `
<input type="checkbox">
<input type="text" value="${taskName}">
<button class="deleteButton">Delete</button>
`;
taskList.appendChild(newTask);
const deleteButton = newTask.querySelector('.deleteButton');
deleteButton.addEventListener('click', deleteTask);
const checkbox = newTask.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', toggleComplete);
}
addButton.addEventListener('click', function() {
const taskName = taskInput.value;
if (taskName) {
addTaskToDOM(taskName);
saveTaskToLocalStorage(taskName);
taskInput.value = '';
}
});
getTasksFromLocalStorage();
4.说明
这个项目实现了一个基本的待办事项应用。在文本框中输入任务,点击"Add"按钮可以将任务添加到待办事项列表中。每个任务都包含复选框和文本框,复选框用于标记任务是否已完成,文本框用于显示任务的内容。点击任务旁边的"Delete"按钮可以删除任务,点击复选框可以切换任务的完成状态。已完成的任务会被加上删除线效果。
创建函数getTasksFromLocalStorage()来从本地存储中获取任务列表,并使用forEach方法将每个任务添加到DOM中。在添加任务时添加了调用saveTaskToLocalStorage()函数来将任务添加到本地存储。该函数首先获取本地存储中的任务列表,将新任务添加到列表中,然后使用setItem()方法将更新后的任务列表保存到本地存储中。
当删除任务时,我们还需要从本地存储中删除相应的任务。通过调用deleteTaskFromLocalStorage()函数,该函数获取本地存储中的任务列表,根据任务名称过滤出更新后的任务列表,并将其保存回本地存储中。
通过以上改进,用户能够在刷新页面后保留之前添加的任务。
三.使用React实现待办事项
1.示例
import React, { useState } from 'react';
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
if (inputValue) {
const newTodo = {
id: Date.now(),
text: inputValue
};
setTodos([...todos, newTodo]);
setInputValue('');
}
};
const editTodo = (id, newText) => {
const updatedTodos = todos.map(todo => {
if (todo.id === id) {
todo.text = newText;
}
return todo;
});
setTodos(updatedTodos);
};
const deleteTodo = (id) => {
const updatedTodos = todos.filter(todo => todo.id !== id);
setTodos(updatedTodos);
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="text"
value={todo.text}
onChange={e => editTodo(todo.id, e.target.value)}
/>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
};
export default TodoList;
2.说明
在上述代码中,我们使用了React的useState hook来管理待办事项的状态。todos数组存储了所有的待办事项,inputValue用于保存输入框的值。addTodo函数用于添加新的待办事项,editTodo函数用于编辑已存在的待办事项,deleteTodo函数用于删除待办事项。
在return语句中,我们使用了JSX来渲染待办事项列表。输入框用于添加新的待办事项,使用onChange事件监听输入框的变化,并在addTodo函数中将新的待办事项添加到todos数组中。待办事项列表通过todos.map方法遍历todos数组,渲染每个待办事项的输入框和删除按钮。在输入框中使用onChange事件监听输入值的变化,并在editTodo函数中更新相应的待办事项。
四.前端框架设计模式
1.MVC(Model-View-Controller)模式
a.概述
MVC是一种将应用程序分为三个核心组件的设计模式。Model负责数据的处理和状态管理,View负责用户界面的展示和交互,Controller负责协调Model和View之间的通信和响应用户输入。
b.优点
代码结构清晰,模块化程度高,解耦合,可维护性好。
c.缺点
可能导致代码复杂化,特别是在大型应用中,Controller的逻辑可能会变得复杂。
d.使用案例
Angular.js使用了MVC模式,其中Controller的角色由Directive充当,Model和View分别对应数据绑定和模板。
2.MVVM(Model-View-ViewModel)模式
a.概述
MVVM是一种将应用程序分为三个核心组件的设计模式。Model负责数据的处理和状态管理,View负责用户界面的展示和交互,ViewModel负责协调Model和View之间的通信和响应用户输入,同时封装了View的状态和行为。
b.优点
界面与应用逻辑的解耦,View的状态和行为可复用,可维护性好,适合前后端分离开发。
c.缺点
对于小型应用来说,引入ViewModel可能增加不必要的复杂性。
d.使用案例
Vue.js使用了MVVM模式,其中Vue实例充当了ViewModel的角色,数据绑定和模板对应于View。
3.Flux模式:
a.概述
Flux是一种用于构建可预测性应用的设计模式。它强调单向数据流,将应用的状态保存在一个中央存储(称为Store)中,所有的数据变更通过Action和Dispatcher进行管理和派发,再由View来获取新的数据并重新渲染。
b.优点
代码结构清晰,易于理解和测试,可维护性好,易于追踪和调试数据变化。
c.缺点
Flux模式引入了许多新概念(例如Action、Dispatcher和Store),学习成本相对较高。
d.使用案例
React配合Flux架构中的Redux或MobX库,用于构建复杂的前端应用。
4.Redux模式
a.概述
Redux是一种用于管理应用状态的设计模式。它将整个应用的状态保存在一个单一的存储容器中,通过纯函数来修改状态,通过订阅和派发Action来实现状态变更和数据流动。
b.优点
可预测性,可追溯性,可测试性好,方便管理和维护大型应用的状态,解决了共享状态管理的问题。
c.缺点
引入了许多新概念(例如Reducer、Action和Middleware),使用起来相对复杂,对于简单的应用可能过于繁琐。
d.使用案例
Redux在React生态系统中被广泛使用,用于管理应用的状态。
5.Observer模式
a.概述
Observer模式是一种对象间的一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会收到通知并自动更新。
b.优点
解耦合,对象之间的关联变得松散,可在运行时动态添加和移除观察者对象。
c.缺点
可能会导致性能问题,如果通知频繁,观察者的通知顺序和依赖关系可能会变得混乱。
d.使用案例
Knockout.js使用了Observer模式,当ViewModel中的数据发生变化时,绑定在View上的观察者会自动进行更新。
6.Singleton模式
a.概述
Singleton模式确保一个类只有一个实例,并提供全局访问点来获取该实例。
b.优点
节省内存空间,确保全局唯一性,提供对唯一实例的集中化访问。
c.缺点
引入全局状态,可能导致模块间的耦合性增加,不易于测试。
d.使用案例
Redux store可以被认为是一个Singleton,应用中的所有组件都可以通过访问store来获取和修改应用的状态。
7.Decorator模式
a.概述
Decorator模式允许动态地给对象添加额外的功能,通过包装一个对象,可以在不改变原有结构的情况下,扩展其功能。
b.优点
遵循开闭原则,无需修改原有代码,可以通过包装类来添加新的功能。
c.缺点
可能会导致大量的装饰器类,增加代码复杂性。
d.使用案例
React的高阶组件(HOC)就是Decorator模式的一种实现方式,通过包装组件,可以添加新的功能(例如访问授权、日志记录等)。
8.Proxy模式
a.概述
Proxy模式通过创建一个代理对象,控制对原始对象的访问。可以用于拦截和改变对象的操作。
b.优点
可以实现对原始对象进行一些额外操作,例如权限验证、缓存、性能监控等。
c.缺点
引入额外的复杂性,可能导致性能下降。
d.使用案例
Redux中的中间件就是Proxy模式的一种应用,它可以拦截并改变action的派发,通常用于处理异步操作和副作用。