JavaScript 中的 MVC,如何在模型中拍摄变化



大家好,我正在尝试了解MVC模型。起初我用清晰的JS香草制作了Todo List,但现在我尝试使用ES6和MVC来做到这一点。我 https://www.taniarascia.com/javascript-mvc-todo-app/遵循本指南,当我想要显示更改时,我陷入了困境。如何从模型调用某些内容已更改为视图?部分方式不起作用

class Model {
constructor() {
this.onToDoListChanged
this.todos = [
{ id: 1, text: 'TEST', complete: false },
]
}
bindTodoListChanged(callback) {
console.log(callback);
this.onToDoListChanged = callback
console.log(this.onToDoListChanged);
}
addTodo(todoText) {
const todo = {
id: this.todos.length > 0 ? this.todos[this.todos.length - 1].id + 1 : 1,
text: todoText,
complete: false,
}
this.todos.push(todo)
this.onTodoListChanged(this.todos)
}
editTodo(id, updatedText) {
this.todos = this.todos.map(todo => todo.id === id ? { id: todo.id, text: updatedText, complete: todo.complete } : todo
)
}
deleteTodo(id) {
this.todos = this.todos.filter(todo => todo.id !== id)
this.onTodoListChanged(this.todos)
}
toggleTodo(id) {
this.todos = this.todos.map(todo => todo.id === id ? { id: todo.id, text: todo.text, complete: !todo.complete } : todo)
this.onTodoListChanged(this.todos)
}
}
class View {
constructor() {
this.app = this.getElement('#root')
// Title
this.title = this.createElement('h1')
this.title.textContent = 'Todos'
this.form = this.createElement('form')
this.input = this.createElement('input')
this.input.type = 'text'
this.input.placeholder = 'Add todo'
this.input.name = 'todo'
this.input.autocomplete = 'off'
this.submitButton = this.createElement('button')
this.submitButton.textContent = 'Submit'
this.todoList = this.createElement('ul', 'todo-list')
this.form.append(this.input, this.submitButton)
this.app.append(this.title, this.form, this.todoList)
}
get _todoText() {
return this.input.value
}
_resetInput() {
this.input.value = ''
}
createElement(tag, className) {
const element = document.createElement(tag)
if (className) element.classList.add(className)
return element
}
getElement(selector) {
const element = document.querySelector(selector)
return element
}
displayTodos(todos) {
while (this.todoList.firstChild) {
this.todoList.removeChild(this.todoList.firstChild)
}
if (todos.length === 0) {
const p = this.createElement('li')
p.textContent = 'Nothing to do! Add a task?'
this.todoList.append(p)
} else {
todos.forEach(todo => {
const li = this.createElement('li')
li.id = todo.id
const checkbox = this.createElement('type')
checkbox.type = 'checkbox'
checkbox.checked = todo.complete
const span = this.createElement('span')
// span.contentEditable = true
// span.classList.add('editable')
if (todo.complete) {
const strike = this.createElement('s')
strike.textContent = todo.text
span.append(strike)
} else {
span.textContent = todo.text
}
const deleteButton = this.createElement('button', 'delete')
deleteButton.textContent = 'Delete'
li.append(checkbox, span, deleteButton)
this.todoList.append(li)
})
}
}
bindAddTodo(handler) {
this.form.addEventListener('submit', event => {
event.preventDefault()
if (this._todoText) {
handler(this._todoText)
this._resetInput()
}
})
}
bindDeleteTodo(handler) {
this.todoList.addEventListener('click', event => {
if (event.target.className === 'delete') {
const id = parseInt(event.target.parentElement.id)
handler(id)
}
})
}
bindToggleTodo(handler) {
this.todoList.addEventListener('change', event => {
if (event.target.type === 'checkbox') {
const id = parseInt(event.target.parentElement.id)
handler(id)
}
})
}
}
class Controller {
constructor(model, view) {
this.model = model
this.view = view
this.model.bindTodoListChanged(this.onToDoListChanged)
this.view.bindAddTodo(this.handleAddTodo)
this.view.bindDeleteTodo(this.handleDeleteTodo)
this.view.bindToggleTodo(this.handleToggleTodo)
this.onToDoListChanged(this.model.todos)
}
onToDoListChanged = todos => {
this.view.displayTodos(todos)
}
handleAddTodo = todoText => {
this.model.addTodo(todoText)
}
// handleEditTodo = (id, updatedText) => {
//     this.model.editTodo(id, updatedText)
// }
handleDeleteTodo = id => {
this.model.deleteTodo(id)
}
handleToggleTodo = id => {
this.model.toggleTodo(id)
}
}
const app = new Controller(new Model(), new View());
*,
*::before,
*::after {
box-sizing: border-box
}
html {
font-family: sans-serif;
font-size: 1rem;
color: #444;
}
#root {
max-width: 450px;
margin: 2rem auto;
padding: 0 1rem;
}
form {
display: flex;
margin-bottom: 2rem;
}
[type="text"],
button {
display: inline-block;
-webkit-appearance: none;
padding: .5rem 1rem;
font-size: 1rem;
border: 2px solid #ccc;
border-radius: 4px;
}
button {
cursor: pointer;
background: #007bff;
color: white;
border: 2px solid #007bff;
margin: 0 .5rem;
}
[type="text"] {
width: 100%;
}
[type="text"]:active,
[type="text"]:focus {
outline: 0;
border: 2px solid #007bff;
}
[type="checkbox"] {
margin-right: 1rem;
font-size: 2rem;
}
h1 {
color: #222;
}
ul {
padding: 0;
}
li {
display: flex;
align-items: center;
padding: 1rem;
margin-bottom: 1rem;
background: #f4f4f4;
border-radius: 4px;
}
li span {
display: inline-block;
padding: .5rem;
width: 250px;
border-radius: 4px;
border: 2px solid transparent;
}
li span:hover {
background: rgba(179, 215, 255, 0.52);
}
li span:focus {
outline: 0;
border: 2px solid #007bff;
background: rgba(179, 207, 255, 0.52)
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div id="root"></div>
<script src="app.js"></script>
</body>
</html>

问题是你在命名时犯了一个错误。

onToDoList已更改

看起来不错,但是如果您检查字符代码,您将看到差异:

票价:111、110、84、111、68、111、76、105、

115、116、67、104、97、110、103、101、100 元

票价:111、110、84、111、100、111、76、105、115、116、67、104、97、110、103、101、100 元

所以解决方案是使用:

onToDoList已更改

一切都会好起来的(实际上没有 - 因为您还需要检查渲染逻辑(

最新更新