青训营前端实践 | 青训营

88 阅读7分钟

青训营前端实践笔记

二.使用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)

// 获取DOM元素
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 = newTask.querySelector('.deleteButton');
        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));
}

// 添加任务到DOM
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 = '';
    }
});

// 获取本地存储中的任务列表并渲染到DOM
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的派发,通常用于处理异步操作和副作用。