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

问题描述 投票:0回答:1

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

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>
javascript model-view-controller es6-class
1个回答
0
投票

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

onToDoListChanged

看起来不错,但是如果您检查字符代码,将会看到不同之处:

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

因此解决方案是使用:

onToDoListChanged

并且一切都会好的(实际上不是-因为您还需要检查渲染逻辑)

© www.soinside.com 2019 - 2024. All rights reserved.