我希望我的操作改变它所附加的DOM元素

I want my action to alter the DOM element it is attached to

本文关键字:DOM 元素 我的 操作 改变 我希望      更新时间:2023-09-26

我说的改变是指改变颜色/字体大小等。

这是控制器中的动作

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。

另一种方法是通过ViewComponent实现,这样你就可以为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,并允许你在该组件或视图中注入动画或其他类型的操作。但是我认为它在某种程度上为命令式风格的改变留下了空间(没有绑定到任何逻辑/规则,这会变得难以维护)。

我相信有更好的方法:p

最好的方法是将DOM节点的class属性绑定到控制器属性,如下所示:

<div {{bind-attr 'class' myClass}}>blah blah</div>

和在你的行动:

actions: {
    changeColor: function() {
        this.set('myClass', 'someCssClass');
    }
}

如果您宁愿直接处理样式(不推荐),那么您可以对style属性绑定做同样的事情。