【问题标题】:backbone, javascript mvc - styling views with javascript主干,javascript mvc - 使用 javascript 样式化视图
【发布时间】:2011-09-15 03:41:48
【问题描述】:

我的一些视图需要将它们的文本区域转换为富文本编辑器。

我使用 jwysiwyg 作为编辑器。它要求它所附加的元素在编辑器初始化时在页面中,即当我调用 $(this.el).wysiwyg() 时,this.el 已经在文档中。

我的大多数视图实际上并没有附加到 dom - 他们的渲染方法只是使用应用程序模板引擎设置他们的元素 html 内容,例如$(this.el).html(this.template(content)

在实际将这些子视图插入页面后,视图/控制器进一步向上查看。同时,视图会在模型发生变化时重新渲染自己。

如何确保每次渲染时都将编辑器附加到元素上,并且仍然确保在元素已经在页面中之前不附加编辑器?

显然我可以一起破解一些适用于这种特殊情况的东西,但我想要一个适用于所有情况的优雅解决方案。

任何帮助将不胜感激。

编辑:这里的要点是解决方案必须优雅地缩放以覆盖渲染后必须设置样式的多个元素,并且在它们位于 DOM 之前不得设置样式

编辑:如果我进行自上而下渲染,这不是问题,但这很慢,我想要一个解决方案,我可以从下向上渲染,然后在顶部一次性插入完整视图

编辑:

结合使用下面建议的一些技术,我正在考虑执行以下操作。任何 cmets/批评将不胜感激。

app/views/base_view.js:

initialize: function() {
  // wrap the render function to trigger 'render' events
  this.render = _.wrap(this.render, function() {
    this.trigger('render')
  });

  // bind this view to 'attach' events. 
  // 'attach' events must be triggered manually on any view being inserted into the dom
  this.bind('attach', function() {
    this.attached();
    // the refreshed event is only attached to the render event after the view has been attached
    this.bind('render', this.refreshed())
    // each view must keep a record of its child views and propagate the 'attach' events
    _.each(this.childViews, function(view) {
      view.trigger('attach')
    })
  })
}

// called when the view is first inserted to the dom
attached: function() {
  this.style();
}

// called if the view renders after it has been inserted
refreshed: function() {
  this.style();
}

style: function() {
  // default styling here, override or extend for custom
}

【问题讨论】:

  • 结果如何?找到合理的解决方案了吗?
  • 好吧,我最终使用了上面编辑中的代码,它可以正常工作。我将把赏金奖励给strongriley,因为他的答案最接近我最终得到的答案。尽管我不确定自己的解决方案,但会暂时搁置这个问题
  • 很公平。我很好奇您是否尝试过我看起来最干净的答案。我不想在每个可能有文本区域的视图中放置包装代码;基本上,我希望它“正常工作”。无论如何,好问题,喜欢它。
  • 经过仔细检查 - 你是绝对正确的!这实际上是一个非常棒的插件。让我感到羞耻,但我实际上并没有检查出来,因为你提到它没有经过测试,我记得一段时间前曾尝试过一个非常相似的任务,它只是以与 jquery 的现场活动类似的方式运行。对赏金感到抱歉,因为这可以在一行代码中解决问题。
  • 没问题;很高兴您找到了适合您的解决方案。

标签: javascript backbone.js javascriptmvc


【解决方案1】:

要解决的大问题!不太确定我已经掌握了整个 jist,但是......你也许可以摆脱左边的“construction_yard”(我刚刚编造了这个词),在那里建造和放置物品,然后移动当它们准备好放置时。大致如下:

.construction_yard {
    position: absolute;
    left: -10000000000px;
}

此解决方案可能会解决几个可能出现的问题。例如,“隐藏”的东西的 jquery 高度和宽度属性为 0,所以如果你按照这些线进行样式设置,你必须等到它被放置,这更复杂,而且会混乱。

然后您的视图将需要按照(伪代码)的方式做一些事情:

//parent
//do all your view-y stuff...
foreach (child = this.my_kids) {
  if child.is_ready() {
    put_that_child_in_its_place();
  }
}

同样,对于孩子,你会做类似的事情:

//child
foreach(parent = this.my_parents) {
  if parent.isnt_ready() {
    this.go_play_in_construction_yard();
  } else {
    this.go_to_parents_house();
  }
}

...而且,由于主干很容易扩展,您可以使用以下方法将其包装在一个更通用的类中:

var ParentsAndChildrenView = Backbone.View.extend({blah: blah});

然后

var Wsywig = ParentsAndChildrenView.extend({blah: blah});

希望有帮助!

差点忘了注明出处: http://jqueryui.com/demos/tabs/#...my_slider.2C_Google_Map.2C_sIFR_etc._not_work_when_placed_in_a_hidden_.28inactive.29_tab.3F

【讨论】:

  • 不要对这个答案投反对票以保持礼貌并尊重努力。但是,将对象扩展基于对 textarea 处理的需要似乎是非常错误的。老实说,只有当我得到答案的结尾时,我才确定这个答案是针对这个问题的。
  • 感谢您的礼貌! :) 我对 jquery / js / 相当陌生,但在骨干方面有很好的经验。您能否详细说明为什么这个答案似乎是错误的?正如我所看到的,我们正在在这里讨论视图。我有一种感觉,我试图理解的一些东西因为我的“伪代码”而丢失了。无论如何......我的意思是......如果 jquery 插件团队建议做类似的事情,那不会错吗?
  • 嘿...我还不够酷,无法评论 Bill Eisenhaur 的答案,所以我将其放在这里。我不同意将 javascript 与您的模板混合,因为这违背了职责分离和不显眼的 js 的想法。将 js 扔到由 js 呈现的模板中似乎是可维护性的倒退。但是,他提到的插件(加上示例)似乎是最好的答案(恕我直言)。对于那些因为类似原因而绊倒的人:它确实复制了一些内置的 '.live()' 功能 (api.jquery.com/live)...
  • 放在视图或模板中,没有区别。我认为如果你有 Javascript 来做与 DOM 相关的事情以留在模板中,这实际上是可以的,但无论哪种方式都可以。您所说的内置功能实际上可能与 LiveQuery 插件相同或至少非常相似。
  • 是的,".live()" 允许您将回调绑定到现在或将来存在的任何匹配器的事件(未来部分与“.bind()”不同)。但是,它不会(不能?)绑定到出现的“新”选择器,插件会这样做。不过,您可以通过使用“.live()”并在视图渲染上触发“.live()”绑定事件来获得相同的功能。希望我有时间研究答案!我真的很喜欢这个问题!
【解决方案2】:

如果您使用JQuery LiveQuery Plugin 附加编辑器会怎样?此类代码可能是您模板代码的一部分,但不是 HTML,而是与模板关联的 Javascript。或者您可以全局添加它。代码可能如下所示(假设您已包含插件本身):

$('textarea.wysiwyg').livequery(function() {
   $(this).wysiwyg();
});

我没有测试过这段代码,但理论上它应该匹配一个 textarea 元素的实例,当它出现在 DOM 中时,它应该具有一个“所见即所得”的类,并调用所见即所得函数来应用编辑器。

【讨论】:

  • 这太好了,我以前怎么不知道呢!您知道性能影响是什么吗?
  • 我认为它并不重要。我们在我们的应用程序的几个地方使用这种技术来分配日期和时间选择器,我们并没有真正注意到性能消耗。我们成功地使用了这种技术,这就是我评论这么多的原因。所有这些其他答案对我来说似乎都不是最理想的(包括赢得赏金的答案!)。
【解决方案3】:

为了遵守 DRY 原则并获得优雅的解决方案,您需要一个专用于确定 textarea 是否具有所见即所得的函数,例如 wysiwygAdder 并在必要时添加它。然后您可以使用下划线的wrap 函数将您的所见即所得加法器附加到渲染函数的末尾。

var View = Backbone.View.extend({
    el: '#somewhere',

    initialize: function(){
        _.bind(this, "render");
        this.render = _.wrap(this.render, wysiwygAdder);
    },

    render: function(){
        //Do your regular templating
        return this;//allows wysiwygAdder to pick up context
    }
});

function wysiwygAdder(context){
    $('textarea', context).doYourStuff();
    //check for presence of WYSIWYG, add here
}

当视图初始化时,它会用你的渲染函数覆盖你的渲染函数,然后是所见即所得的Adder。确保 return this; 从渲染中提供上下文。

【讨论】:

  • 这里的问题是,如果一个视图在父视图位于 DOM 之前将自身呈现为父视图的一部分,则它无法初始化 RTE - 这必须在其父视图插入之后发生页面
  • 这赢得了赏金,但需要在其 DOM 具有 textarea 的每个视图中使用特定代码。我建议人们看看我的解决方案,该解决方案适用于分配了适当类的任何文本区域。该解决方案不需要比提供的单行代码更多的代码。
【解决方案4】:

一种解决方案是使用event delegation 并绑定焦点事件来检查富文本编辑器是否已加载。这样,用户将在需要时获得文本编辑器(通过延迟加载,性能稍有改进),否则您不必加载它。它还无需担心何时附加富文本编辑器以及依赖于呈现链。

如果您担心 FOUC(无样式内容的闪烁),您可以简单地设置未修改文本区域的样式,以包含一个带有背景图像的元素,看起来就像所见即所得的控件,并让您的焦点绑定切换一个类在富文本编辑器接管后隐藏外观。

这是我的想法的一个示例:

var View = Backbone.View.extend({
  el: '#thing',
  template: _.template($("#template").html()),

  render: function() {
    // render me
    $(this.el).html(this.template(context));

    // setup my textareas to launch a rich text area and hide the facade
    $(this.el).delegate('focus', 'textarea', function() {
      if(!$(this).hasRichTextEditor()) { // pseudocode
        $(this).wysiwyg();
        $(this).find('.facade').toggle();
      }
    });

  }
});

【讨论】:

  • 我喜欢这个,但不幸的是我不能为每个要处理的项目制作背景。例如jquery 菜单在初始化时也必须在 dom 中。此外,当页面已经成为焦点时,视图可能会重新呈现自己。
猜你喜欢
  • 2011-08-17
  • 2011-11-26
  • 1970-01-01
  • 2023-04-03
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
相关资源
最近更新 更多