Javascript MVC:将视图重置为默认状态

时间:2019-04-30 14:55:02

标签: javascript model-view-controller

我有一个视图,该视图可以更改样式并根据用户操作显示/隐藏元素。如何将视图恢复为默认状态?

例如:

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>

上下文框一旦被修改,即使外部上下文发生变化,它也将保持这种方式。我希望它恢复到原始的“加载”状态。

一种选择是仅重新加载页面,但是响应选择更改而重新加载页面感觉并不好,可能需要输入“您确定吗?”卸载事件。

对于这个小例子,我可以在select change事件中重置css,但是随着 context-area 变得越来越复杂,要重置的元素数量也随之增加。这也使将来的更改令人沮丧,因为每个更改还需要进行相应的重置。

我当前使用的选项是在页面加载时克隆 context-area ,然后根据上下文的更改删除并还原该节点。这样做可以,但是我发现自己会根据每个模型更改删除并还原该节点,以防万一需要它。

是否有更好的方法来处理?在MVC框架中是如何做到的(我还没有学过)?

2 个答案:

答案 0 :(得分:2)

关于MVC有几种流派,所以接下来的事情将只是一个见解。我将颠倒View与Controller之间的连接,以便只有Controller知道其他两个组件。可能模型也应该知道View,但是由于您的示例没有用例,因此我将忽略它。

我还觉得jQuery应该只在View中使用,而不是在Controller中使用:jQuery的作用是(轻松地)与DOM交互,而DOM是View的角色。

对于您的特定问题,我将在View类中实现方法reset,其他组件可以在适当时调用该方法。 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>

再进一步说明一下,实际上应该让View负责初始HTML,这意味着您将从一个空白页开始,然后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() {
        $(() => $("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>

在服务器驱动的Web应用程序中,MVC组件将存在于服务器端,并且您将使用生成这种服务器技术提供的HTML的功能。

答案 1 :(得分:2)

我猜经典的做法是发送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>