我说的改变是指改变颜色/字体大小等。
这是控制器中的动作
actions {
changeColor: function() {
this.$().css('background-color', '#f1f1f2'); //error!
}
}
<span {{action 'changeColor' this}} > </span>
this.$()
正在导致错误。我应该用什么代替呢?
动作必须在控制器中
当你说{{action 'someAction' this}}
时,在这种意义上,template
中的this
指的是模板的模型/内容,而不是动作的DOM元素。
这是另一个建议。我不确定这是否是最佳实践。
假设我们在索引模板中工作,并且有一个span的动作:
//index template
<span>Change my background</span>
现在索引模板有一个view
是支持它称为IndexView。在这个视图中,我们可以使用一个DOM事件。在下面的代码中,我们使用click
Dom事件,它将发送一个事件,我们可以使用该事件来抓取目标,然后发送给控制器。
//App.IndexView
click: function(evt) {
//get the evt target
var target = evt.target
//send a action the controller
this.get('controller').send('handleBackgroundChange', target);
}
现在在indexController:
//indexController
actions: {
handleBackgroundChange: function(target) {
$(target).css({'background': 'green'});
}
}
如果你想用jQuery做这个改变,你可以做下面的事情:
// You'd have to know the selector of that view or the css class wrapping it
// in order to do this in the controller, since the "this"
// is not a pointer to your view at this point (I think)
Ember.$('selector goes here selector').css({'color': '#00F'});
这将是更容易形成一个视图,而不是一个控制器,因为你可以做这样的事情(注意this
关键字):
this.$().css('color': '#0F0');
此代码将在具有this
关键字的视图中工作,而不需要选择器,因为此时它是指向view
的指针。所以this.$()
在视图中的意思就是$("#ember416")
是分配给该视图的id
Ember。
另一种方法是通过View
或Component
实现,这样你就可以为style
使用attributeBindings
,并且对正在发生的事情有更多的控制。您可以根据业务需求将规则应用于特定的css属性,并利用绑定来始终重新计算样式。使用这种方法,您不需要使用$.css()
来更改样式,因为它已经为您构建并应用。
所以…假设你创建了一个style
属性,在你的类中监视其他属性(例如颜色,边框,大小等),并最终组成样式字符串。通过这种方式,您可以program
每个属性,然后通过attributeBindings
将给定组合的结果直接绑定到视图。例子:
// JS
App = Em.Application.create();
App.LeToggleButtonComponent = Ember.Component.extend({
// I want an input
tagName: 'input',
// of the type button
type: 'button',
// that has a `clicked` flag
clicked: false,
// When I change the `clicked` flag, I want my to force any
// properties depending on `clicked` to re-evaluate their values
changeColor: function() {
this.toggleProperty('clicked');
}.on('click'),
// Then I want the color attribute to re-evaluate itself
// based on the `clicked` property, switching it from red to blue
color: function() {
return "color: %@;".fmt((this.get('clicked')) ? "#00F" : "#F00");
}.property('clicked'),
// And I also want the border attribute to re-evaluate itself
// based on the `clicked` property, switching it from red to blue
border: function() {
return "border: %@;".fmt((this.get('clicked')) ? "1px solid #00F" : "1px solid #F00");
}.property('clicked'),
// Then I want to combine all css related properties
// into a single string, composing the style of this component
style: function() {
return '%@1%@2'.fmt(this.get('border'), this.get('color'));
}.property('border', 'color')
// finally, I want to bind some attributes to the view
// so the styles get updated automatically when
// any of them change. The real important one, is the `style` prop
attributeBindings: ['type', 'value', 'style'],
});
// Handlebars
<script type="text/x-handlebars" data-template-name='index'>
{{le-toggle-button value='Click Here'}}
</script>
<script type="text/x-handlebars" data-template-name='application'>
<h2>button test</h2>
{{outlet}}
</script>
(见jsbin)
可以提出一个论点(我同意),在大多数情况下,应该使用类而不是内联样式。当你有非常具体的规则和/或复杂的样式组合,可能会创建重复的/难以维护的css类时,这个建议的方法是很好的。
<标题> 更新我想满足我自己对如何通过控制器或路由发送和处理css更改的好奇心,然后继续阅读。我想出了第二个解决方案,允许直接在控制器或路由中进行更改:
// JS
App = Ember.Application.create();
App.Router.map(function() {
this.route('other');
});
App.IndexRoute = Em.Route.extend({
actions: {
changeColor: function(selector) {
console.log("Index > Ember.$('%@')".fmt(selector), Ember.$(selector));
// now I can simply call jQuery to
// change the style of the view in
// this particular route
Ember.$(selector).css({
'color': '#F00',
'font-weight': 'bold'
});
}
}
});
App.OtherRoute = Em.Route.extend({
actions: {
changeColor: function(selector) {
console.log("Other > Ember.$('%@')".fmt(selector), Ember.$(selector));
// or on this one
Ember.$(selector).css({
'height': '80px'
});
}
}
});
App.LeOtherButtonComponent = Ember.Component.extend({
tagName: 'input',
type: 'button',
target: Ember.computed.alias('route'),
// within the action handler, you can
// call this.triggerAction, passing the
// action name, context and target.
// in this case, i didn't pass the target
// with the hash, but left as the default
// target of the view, and also changed
// it's default value to the route just
// as an example
changeColor: function(e) {
var selector = '#%@'.fmt(this.get('elementId'));
this.triggerAction({
action: 'changeColor',
actionContext: selector
});
}.on('click'),
attributeBindings: ['type', 'value' ]
});
// Markup
<script type="text/x-handlebars" data-template-name='index'>
{{le-other-button value='Click Here - Index'}}
</script>
<script type="text/x-handlebars" data-template-name='other'>
{{le-other-button value='Click Here - Other'}}
</script>
<script type="text/x-handlebars" data-template-name='application'>
<div class="more">
{{#link-to 'index'}}Index{{/link-to}} |
{{#link-to 'other'}}Other{{/link-to}}
</div>
{{outlet}}
</script>
(见jsbin)
我真的不知道我是否喜欢这个解决方案,因为它真的很容易与内联样式不同步,而不是你的视图/组件应该处于的状态和在那一点上看起来像。第一个假设组件的方法很好,因为您可以准确地判断将要更改的内容,而不需要使用jQuery。另一方面,你必须创建一个计算属性,并将其添加为样式的依赖项,每次你想在该字符串中添加一个新的样式属性,使第二个假设的组件看起来更灵活,允许每个控制器/路由实现自己的changeColor
,并允许你在该组件或视图中注入动画或其他类型的操作。但是我认为它在某种程度上为命令式风格的改变留下了空间(没有绑定到任何逻辑/规则,这会变得难以维护)。
最好的方法是将DOM节点的class
属性绑定到控制器属性,如下所示:
<div {{bind-attr 'class' myClass}}>blah blah</div>
和在你的行动:
actions: {
changeColor: function() {
this.set('myClass', 'someCssClass');
}
}
如果您宁愿直接处理样式(不推荐),那么您可以对style
属性绑定做同样的事情。