maodouio / meteor-master-classes

毛豆网Meteor在线师徒班
http://www."培养国内第一批Meteor布道者".com
15 stars 7 forks source link

View组件和events不在同一个template中 #6

Open leetschau opened 9 years ago

leetschau commented 9 years ago

点击用户按钮事件定义在template layout中, 用户按钮组件是定义lists.html中的, 问题: 为什么html组件和它的事件可以不在同一个template中定义? 这两个template需要满足什么样的关系?

kevingzhang commented 9 years ago

我不太清楚你指的是哪个按钮, 如果是 title 上的那些左边的 Back, 右边的:Edit 按钮的话, 那么这样设计就是对的. 因为 title 属于 layoutTemplate, 并不属于 lists.html 中. 你在 lists.html 使用的是 contentFor 的方法去定义一个属于其他 template 的内容的. 你可以指定内容但是无法指定 event 的响应在本 template 中.

如果你说的不是这种情况请说明代码位置, 我再看

leetschau commented 9 years ago

原来问题的详细说明:

lists.html中,<button class="button button-clear" id="showProfileMenu">这个按钮在lists template中, 这个按钮的点击事件是layout.coffee中的'click #showProfileMenu': (event, t)->,这行代码属于Template.layout.events,所以是layout template的事件,为什么lists template中的组件(按钮showProfileMenu)的事件没有定义在Template.lists.events中,却在Template.layout.events中?

您的回答中提到:

你在 lists.html 使用的是 contentFor 的方法去定义一个属于其他 template 的内容的

是否可以理解为:

<template name="lists">
  ...
  {{#contentFor "headerButtonRight"}}
    <button class="button button-clear" id="showProfileMenu">
      ...
    </button>
  {{/contentFor}}
  ...
</template>

其中的button showProfileMenu由于被包在{{#contentFor "headerButtonRight"}}中,所以不属于template lists? 那么它应该属于哪个template?

另外,Meteor中template A中的组件的事件,是否必须定义在Template.A.events中?

seanjsong commented 9 years ago

呵呵我昨天看这到段代码的时候就猜到你可能是问的这个,我也有过同样的疑问。

我是这样理解的:Template.layout.events这个调用里的selector可以选中layout template里面的child element,#showProfileMenu虽然是在lists那个template里面,但不可否认lists也是layout的child element,所以当然可以选中。那么为什么非要在layout里做这件事,而不在lists里做呢?这样岂不是有违模块化设计?这是因为我们在event handler中需要layout这个template的template instance:

    t.ActionSheetButtons = []

    if Meteor.user()?
      t.ActionSheetButtons.push {actionId:'addPost', text: 'New Post <i class="icon ion-ios-compose"></i>'}
      t.ActionSheetButtons.push {actionId:'logout', text: 'Logout <i class="icon ion-log-out"></i>'}
    else
      t.ActionSheetButtons.push {actionId:'login', text: 'Login <i class="icon ion-log-in"></i>'}

我没仔细研究过这个ActionSheetButtons,但我试过把Template.layout.events改成Template.lists.events,也就是试着把ActionSheetButtons加到lists那个template instance上是不灵的。

seanjsong commented 9 years ago

我也被弄糊涂了,我试了即使这么简单的event handler也不灵:

Template.lists.events
  'click #showProfileMenu': (event, t)->
    alert "hello"

看来真的是因为被包在{{#contentFor "headerButtonRight"}}中的element不属于template lists?这也太不合理啦。

ennea8 commented 9 years ago

有参考价值的讨论

view中的内容才是当前模板的内容 之外的内容都是对layout 比如标题 导航等的配置 会动态插入到所有模板共用的layout的footer或header

最简单的方法就是直接看dom结构 是否保含特定元素。 这是ionic的设计,使用blaze实现 与meteor或blaze无关 即使ionic的angular版本也是这样配置的

那为什么不把{{#contentFor “headerButtonRight”}}直接就写在模板外面?写在模板里面,生成的DOM却不在模板里面,很混乱啊?

因为每个页面的标题都不一样 需要定制

这里关键是理解模板代码是有逻辑的代码 不是静态的内容 静态内容取决于最后真正生成在页面的 这样就会习惯的 感觉这样的设计是为了避免冗余 每个模板都有自己独立的header就会有很多重复代码

contentFor 从命名来说就是这里在指定一个地方的内容,但这个内容不一定属于这个模板

qdsang commented 9 years ago

同求答案~

kevingzhang commented 9 years ago

上面不是已经有十分清晰的答案了啊, 你问的是同一个问题么?

qdsang commented 9 years ago

@kevingzhang

<template name="lists">
  ...
  {{#contentFor "headerButtonRight"}}
    <button class="button button-clear">
      ...
    </button>
  {{/contentFor}}
  ...
</template>

如果想监听 headerButtonRight 中的button点击事件该怎么写?

ennea8 commented 9 years ago

写在Template.layout.events 里,layout是布局模板名 Template.layout.events({ 'click cssSelector',function(){/***/} })

qdsang commented 9 years ago

@ennea8 非常感谢,我比较担心都写在layout会冲突

qdsang commented 9 years ago

目前我在用到的模板中这么写得, 看着有些奇怪

Template.ionNavBar.events({
  'click [data-action=binding-done]': function (event, template){
  }
});
ennea8 commented 9 years ago

这个事件绑定问题有另一种处理方法 去掉 layout中的 {{> ionNavBar class="bar-positive"}} 然后每个模板中添加自己的 bar-header,甚至不加,若不需要, 然后事件绑定就可以写到各自的模板js文件里了,互不冲突. 这样做的好处header的内容和样式可以随意定制,灵活性更大

ennea8 commented 9 years ago

附加一个info 供了解 从资源损耗角度,把事件写在layout里是代价最小的,发现meteor的事件绑定内部都使用代理的方式进行了优化。 也就是不论往layout上绑了多少个click,其实从浏览器角度只绑了一个,有一个函数处理队列(数组),目前的了解是这样 https://github.com/meteor/meteor/wiki/Using-Blaze 文章的底部有对delegate的一些描述

@qdsang 你那种把事件写ionNavBar的方式应该比layou应该更易读更模块化些