2012-09-22 6 views
2

나는 각 노드가 부모 노드의 템플릿에 싸여있을 수있는 자신의 콧수염 템플릿을 포함하는 나무 같은 설정을 가지고있다. 여기콧수염과 중첩 된 템플릿

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 요소 만 반환하는 간단한 함수를 사용하는 것이 좋습니다. 이것은 가능한가? 깊이 중첩 된 템플릿을 허용하고 많은 성능을 잃지 않는 것이 가능합니까? 다른 말로하면, 두 개의 템플릿 중 하나가 jsfiddle의 다른 템플릿 안에 중첩되어있는 두 개의 템플릿이 있습니다. DOM을 다룰 때 상위 뷰에서 중첩 된 뷰를 걱정하지 않아도됩니다.

+0

jsFiddle에서 코드를 편집했습니다. 때로는 바이올린 링크가 내려갑니다. – Andrey

답변

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을 교체하는 것입니다. 그런 다음 다른 자식 뷰를 서로 옆에 삽입하는 문제입니다.