jQuery事件回调只运行一次(类似Angular的框架开发)

时间:2014-07-28 17:32:06

标签: javascript jquery angularjs callback

我正在构建一个JS框架来模拟AngularJS模型,仅用于教育目的。

问题是:我在更新模型(输入)时指定一个回调来运行,但是在它们第一次运行之后,它们会消失"。

在尝试使用jQuery之前,我尝试使用querySelectorAll并遇到同样的问题。

这是:http://jsfiddle.net/YmY2w/

HTML

<div class="container" jd-app="test">
    <input type="text" jd-model="name" value="foo" /><br />
    <input type="text" jd-model="email" value="foo@foo" />
    <hr />
    <p>Name: {{ name }}</p>
    <p>Email: {{ email }}</p>
</div>

JAVASCRIPT

(function($, window, document, undefined) {
    'use strict';

    // registering models
    (function() {
        var $app = $('[jd-app]');
        var $models = $('[jd-model]', $app);

        $models.each(function(index) {
            UpdateModel.apply(this);
        });

        function UpdateModel() {
            var model = { name: $(this).attr('jd-model'), value: this.value }
            var re    = new RegExp('{{\\s+('+ model.name +')\\s+}}', 'gm');

            $('*', $app).each(function(index) {
                var $this = $(this);
                $this.text( $this.text().replace(re, model.value) );
            });

            $(this).on('keyup', UpdateModel);
        }
    })();

})(jQuery, window, document);

我做错了什么?有没有更好的方法来实现这一目标?

1 个答案:

答案 0 :(得分:0)

您遇到的问题是,当您的脚本第一次看到{{name}}时,它会将其转换为模型“name”的值。但是在你的html中,你有文本“foo”而不是{{name}}(你试图搜索/替换的东西),所以你无法更新显示的文本。

您需要做的是跟踪各个DOM节点(附加到特定模型),其中包含最初具有“{{}}”的文本以及正确的模型名称。

我在这里想出了一种丑陋的原型:

http://jsfiddle.net/YmY2w/11/

我不确定在识别正确的模板位置方面有多灵活,但它可以作为我正在谈论的实现类型的演示。另外 - 我猜不太高效。 (但后来这两个人都没有......)

(function($, window, document, undefined) {
    'use strict';

    // From http://stackoverflow.com/questions/298750/how-do-i-select-text-nodes-with-jquery
    function getTextNodesIn(node, includeWhitespaceNodes) {
        var textNodes = [], nonWhitespaceMatcher = /\S/;

        function getTextNodes(node) {
            if (node.nodeType == 3) {
                if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) {
                    textNodes.push(node);
                }
            } else {
                for (var i = 0, len = node.childNodes.length; i < len; ++i) {
                    getTextNodes(node.childNodes[i]);
                }
            }
        }

        getTextNodes(node);
        return textNodes;
    }

    // registering models
    (function() {
        var $app = $('[jd-app]');
        var $models = $('[jd-model]', $app);
        var models = [];

        $models.each(function(index) {
            registerModel.apply(this);
        });

        function registerModel() {
          var model = { name: $(this).attr('jd-model'), value: this.value, domElements: [] };            
          var re    = new RegExp('{{\\s+('+ model.name +')\\s+}}', 'gm');
          $app.contents().each(function(index) {
          if ($(this).text().match(re)) {
            var textNodes = getTextNodesIn(this, false);
            console.log(textNodes);
            $.each(textNodes, function(index, elem) {
              if (elem.nodeValue.match(re)) {
                var text = elem.nodeValue;
                var myArray = re.exec(text);
                var match = myArray[0];

                var firstIndex = text.indexOf(match);

                var newElem = elem.splitText(firstIndex);

                newElem.splitText(match.length);

                model.domElements.push(newElem);
             }
           });
         }
      });

      models.push(model);

      $(this).on('keyup', updateModel);
      $(this).trigger('keyup');
    }


        function updateModel() {
            var $input = $(this);
            $.each(models, function(index, model) {
                if (model.name === $input.attr('jd-model')) {
                    var newVal = $input.val();
                    $.each(model.domElements, function(index, elem) {
                        elem.nodeValue = newVal;
                    });
                }
            });
        }

    })();

})(jQuery, window, document);