Javascript MVC: сбросить вид до состояния по умолчанию - PullRequest
3 голосов
/ 30 апреля 2019

У меня есть вид, который меняет стиль и показывает / скрывает элементы в ответ на действия пользователя.Как я могу вернуть представление к его состоянию по умолчанию?

Например:

class Model {
    constructor() {}
}

class Controller {
    constructor(model) {
        this.model = model;
    }

    respondToButton() {
        $('#context-box').css('color', 'red');
        alert("Cannot do baz.");
    }

    respondToSelect(e) {
        if ($(e.target).val() == "foo") {
            $('#context-area').hide();
        } else {
            $('#context-area').show();
        }
    }
}

class View {
    constructor(controller) {
        this.controller = controller;
        this.bindEvents();
    }

    bindEvents() {
        $('#button').on('click', this.controller.respondToButton);
        $('#select').on('change', this.controller.respondToSelect);
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<html>
<head></head>
<body>
    <select id="select">
        <option value="foo">Foo</option>
        <option value="bar">Bar</option>
    </select>

    <div hidden id="context-area">
        <span id="context-box">Baz</span>
        <button id="button">Do Baz?</button>
    </div>
</body>

<script>
    $(document).ready(function() {
        var model = new Model();
        var controller = new Controller(model);
        var view = new View(controller);
    });
</script>
</html>

Как только context-box был изменен, он остается таким же, даже если внешний контекст изменяется.Я хотел бы, чтобы он вернулся в исходное состояние «при загрузке».

Один из вариантов - просто перезагрузить страницу, но перезагрузить страницу в ответ на изменение выбора не очень приятно ивероятно, требуется "Вы уверены?"событие unload.

Для этого небольшого примера я мог просто сбросить css в событии select change, но по мере того, как context-area усложняется, количество элементов для сброса увеличивается.Это также расстраивает будущие изменения, поскольку каждое изменение также требует соответствующего сброса.

Опция, которую я сейчас использую, заключается в клонировании context-area при загрузке страницы, а затем в удалении и восстановлении узлав ответ на изменение контекста.Это работает нормально, но я обнаружил, что удаляю и восстанавливаю узел в ответ на каждое изменение модели на всякий случай, если это необходимо.

Есть ли лучший способ справиться с этим?Как это делается в рамках MVC (я еще не научился)?

Ответы [ 2 ]

2 голосов
/ 30 апреля 2019

Я думаю, что классический способ сделать это - отправить ajax-запрос, чтобы снова получить страницу, и обновить только ту часть, которую вы хотите, используя html, который вы получите в ответ.

Но ваша идея сохранить узел под нагрузкой, а затем восстановить его в любое время, кажется самой быстрой!

РЕДАКТИРОВАТЬ: Для запроса Ajax я думал о чем-то вроде этого:

function resetDiv() {
  let myRequest = new XMLHttpRequest();
  myRequest.open('GET', "YOUR DEFAULT PAGE PATH");
  myRequest.responseType = "document";
  myRequest.onreadystatechange = function () { 
      if (myRequest.readyState === 4) {
      	  let doc = myRequest.response;
          document.getElementById('context-area').innerHTML = doc.getElementById('context-area').innerHTML;
      }
  };
  myRequest.send();
}

function showContext(element) {
	if(element.value == "bar") {
  	$('#context-area').show();
  } else {
  	$('#context-area').hide();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="select" onchange="showContext(this);">
    <option value="foo">Foo</option>
    <option value="bar">Bar</option>
</select>
<div hidden id="context-area">
    <span id="context-box">Baz</span>
</div>
<button id="reset" onclick="resetDiv();">
reset
</button>
2 голосов
/ 30 апреля 2019

На MVC существует несколько школ мысли, так что дальнейшее будет вопросом мнения.Я бы обратил связь между View и Controller, чтобы только Controller знал о двух других компонентах.Возможно, модель также должна знать о представлении, но поскольку в вашем примере для этого нет сценария использования, я его проигнорирую.

Мне также кажется, что jQuery следует использовать только в представлении, а не вКонтроллер: роль jQuery состоит в том, чтобы (легко) взаимодействовать с DOM, который является ролью View.

Для вашего конкретного вопроса я бы реализовал метод reset в классе View, который другие компонентыможет позвонить, когда это уместно.Класс View также будет вызывать его сам в конструкторе:

class Model {
    constructor() {}
}

class Controller {
    constructor(model, view) {
        this.model = model;
        this.view = view;
        view.onButton(this.processAction.bind(this));
        view.onSelect(this.processChoice.bind(this));
    }

    processAction() {
        this.view.highlight = true;
        this.view.message("Cannot do baz.");
    }

    processChoice(value) {
        if (value === "foo") {
            this.view.reset();
        } else {
            this.view.showContext = true;
        }
    }
}

class View {
    constructor() {
        this.reset();
    }
    
    reset() {
        this.highlight = false;
        this.showContext = false;
    }
    
    onButton(listener) {
        $('#button').on('click', listener);
    }
    
    onSelect(listener) {
        $('#select').on('change', function (e) {
            listener($(e.target).val());
        });
    }
    
    set highlight(highlighted) {
        $('#context-box').css('color', highlighted ? 'red' : 'initial');
    }
    
    set showContext(visibility) {
        $('#context-area').toggle(visibility);
    }
    
    message(msg) {
        alert(msg);
    }
}

$(function() {
    new Controller(new Model(), new View());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="select">
    <option value="foo">Foo</option>
    <option value="bar">Bar</option>
</select>

<div hidden id="context-area">
    <span id="context-box">Baz</span>
    <button id="button">Do Baz?</button>
</div>

Чтобы продвинуться немного дальше, представление действительно должно нести ответственность за исходный HTML, что означает, что вы начнете с пустой страницы и представленияЭкземпляр будет заполнять его:

class Model {
    constructor() {}
}

class Controller {
    constructor(model, view) {
        this.model = model;
        this.view = view;
        view.onButton(this.processAction.bind(this));
        view.onSelect(this.processChoice.bind(this));
    }

    processAction() {
        this.view.highlight = true;
        this.view.message("Cannot do baz.");
    }

    processChoice(value) {
        if (value === "foo") {
            this.view.reset();
        } else {
            this.view.showContext = true;
        }
    }
}

class View {
    constructor() {
        this.reset();
    }
    
    reset() {
        $(() => $("body").empty().append(
            this.$select = $("<select>").append(
                $("<option>").val("foo").text("Foo"),            
                $("<option>").val("bar").text("Bar")
            ),
            this.$contextArea = $("<div>").append(
                 this.$contextBox = $("<span>").text("Baz"),
                 this.$button = $("<button>").text("Do Baz?")
            ).hide()
        ));
    }
    
    onButton(listener) {
        $(() => $(document).on("click", e => 
            this.$button.is(e.target) && listener()
        ));
    }
    
    onSelect(listener) {
        $(() => $(document).on("change", e => 
            this.$select.is(e.target) && listener(this.$select.val())
        ));
    }
    
    set highlight(highlighted) {
        $(() => this.$contextBox.css('color', highlighted ? 'red' : 'initial'));
    }
    
    set showContext(visibility) {
        $(() => this.$contextArea.toggle(visibility));
    }
    
    message(msg) {
        alert(msg);
    }
}

new Controller(new Model(), new View());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

В управляемом сервером веб-приложении компоненты MVC будут существовать на стороне сервера, и вы будете использовать возможности генерации HTML, предлагаемые такой серверной технологией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...