2

ツリーのような設定があり、各ノードには、親ノードのテンプレートにラップされている可能性のある独自のMustacheテンプレートが含まれています。

var templates = {
    secondTmpl: Mustache.compile("<i>Yet another template.. Here's some text: {{text}}</i>     {{date}}"),
    template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}}            </li>{{/list}}</ul> {{test}}")
};

var tree = [
    {
        template: "template",
        data: { val: "yup!!", list: [1,2,3,4,5], test: function() { return new Date(); } },
        children: [
            {
                view: "Main",
                template: "secondTmpl",
                data: { text: "Some Value", date: function() { return new Date(); } }
            }
        ] 
    }
];

function MainView(options) {
    this.template = options.template;
    this.data = options.data;
    this.childViews = options.childViews;
    this.el = document.createElement("div");
}

MainView.prototype.render = function() {
    View.prototype.render.call(this);
    this.postRender();
    return this;
};

MainView.prototype.postRender = function() {
    this.el.getElementsByTagName("i")[0].style.border = "1px dotted red";
};

function View(options) {
    this.template = options.template;
    this.data = options.data;
    this.childViews = options.childViews;
    this.el = document.createElement("div");
}

View.prototype.render = function(renderChildren) {
    if(this.childViews) {
        this.data.outlet = "<div class=\"outlet\"></div>";
    }

    this.el.innerHTML = this.template(this.data);

    if(this.childViews) {
        this.childViews.forEach(function(view) {
            this.el.getElementsByClassName("outlet")[0].appendChild(view.render().el);
        }, this);
    }

    return this;
};

function traverse(node) {
    var viewOptions = {
        template: templates[node.template],
        data: node.data
    };

    if(node.children) {
        viewOptions.childViews = node.children.map(function(n) {
            return traverse(n);
        });
    }

    return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}

function init() {
    tree.forEach(function(node) {
        var view = traverse(node);
        document.body.appendChild(view.render().el);
    });
}

window.onload = init;​

ここでの例:http://jsfiddle.net/b4fTB/

ツリーにデータがある理由は、ネストされたテンプレートがユーザーデータによって異なり、多くのテンプレートが異なるテンプレートにラップされている可能性があるためです。

ここで行っていることがばかげているかどうかはわかりませんが、C#からテンプレートをレンダリングすることもできます。これは非常に便利です。

だから-質問(上記へのコメントはもちろん大歓迎です)。ネストされたテンプレートを使用してテンプレートを処理する場合は、ネストされたテンプレートのdom要素ではなく、実際のテンプレートに関連するdom要素のみを返す単純な関数があると便利です。これも可能ですか?そして、深くネストされたテンプレートを可能にし、パフォーマンスを大幅に低下させない方法で可能ですか?つまり、2つのテンプレートがあり、そのうちの1つがjsfiddleのもう1つのテンプレート内にネストされています。domを処理するときに、親ビューのネストされたビューについて心配する必要がないのは素晴らしいことです。

4

1 に答える 1

0

さて、私は自分で方法を見つけたと思います。

次のコードには、mustachejscomposejsが必要です。

var noop = function() {};

var templates = {
    secondTmpl: Mustache.compile("<i>Yet another template..  {{{outlet}}}Here's some text: {{text}}</i> {{date}}"),
    template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}}</li>{{/list}}</ul> {{test}}")
};

var tree = [
    {
        view: "Main",
        template: "template",
        data: { val: "yup!!", list: [1, 2, 3, "Four", 5], test: function() { return new Date(); } },
        children: [
            {
                template: "secondTmpl",
                data: { text: "Some Value", date: function() { return new Date(); } }
            },
            {
                view: "Test",
                template: "secondTmpl",
                data: { text: "ANOTHER TEMPLATE", date: function() { return new Date(); } },
                children: [
                    {
                        template: "template",
                        data: { val: "Pretty nested template", list: [56, 52, 233, "afsdf", 785], test: "no datetime here" }
                    }
                ]
            }
        ] 
    }
];

var View = Compose(function(options) {
    Compose.call(this, options);
    this.el = document.createElement(this.tag);
}, {
    tag: "div",
    render: function() {
        if(this.childViews) {
            this.data.outlet = "<div class=\"outlet\"></div>";
        }

        this.el.innerHTML = this.template(this.data);

        this.didRender();

        if(this.childViews) {
            var lastEl;

            this.childViews.forEach(function(view) {
                if(!lastEl) {
                    var outlet = this.el.getElementsByClassName("outlet")[0];
                    lastEl = view.render().el;
                    outlet.parentNode.replaceChild(lastEl, outlet);
                } else {
                    var el = view.render().el;
                    lastEl.parentNode.insertBefore(el, lastEl.nextSibling);
                    lastEl = el;
                }
            }, this);
        }

        this.didRenderDescendants();

        return this;
    },
    didRender: noop,
    didRenderDescendants: noop
});

var TestView = View.extend({
    didRender: function() {
        var nodes = this.el.querySelectorAll("*");
        for(var i = 0; i < nodes.length;i++)
            nodes[i].style.border = "2px dotted red";
    }
});

var MainView = View.extend({
    didRender: function() {
        var nodes = this.el.querySelectorAll("*");
        for(var i = 0; i < nodes.length;i++)
            nodes[i].style.backgroundColor = "lightgray";
    }
});

function traverse(node) {
    var viewOptions = {
        template: templates[node.template],
        data: node.data
    };

    if(node.children) {
        viewOptions.childViews = node.children.map(function(n) {
            return traverse(n);
        });
    }

    return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}

function init() {
    tree.forEach(function(node) {
        var view = traverse(node);
        window["view"] = view;
        document.body.appendChild(view.render().el);
    });
}

window.onload = init;

秘訣は、div.outletを追加するのではなく、最初の子ビューに置き換えることです。次に、他の子ビューを隣り合わせに挿入します。

于 2012-09-23T18:37:54.810 に答える