gpt4 book ai didi

Backbone.js 'swallows' 如果另一个事件触发重新渲染,则单击事件

转载 作者:行者123 更新时间:2023-12-03 06:15:21 27 4
gpt4 key购买 nike

我想要实现的是,在表单更改时,整个 View 应该重新渲染。这是为了提供刚刚编辑的数据的预览,并在勾选复选框时隐藏表单中的某些元素。

当用户编辑字段并单击按钮而不离开字段时,会同时触发前两个事件:更改、单击。更改处理程序首先更新模型,这会触发表单的重新呈现。当点击事件发生时,什么也没有发生。我想这与重新渲染有关,因为当我注释掉

@model.on 'change', @render, @

两个事件处理程序都按其应有的方式执行。

也许点击处理程序没有执行,因为点击目标已从 dom 中删除,并且添加了新按钮?我该如何解决这个问题?我以为我写的代码是“惯用的”Backbone.js,但我仍在学习:-)

这是我的代码的简化版本,显示了问题: jsbin

最佳答案

让我们添加一些内容,以便我们可以看到发生了什么。首先,我们将使用唯一的 ID 标记保存按钮:

render: ->
id = "b#{Math.floor(Math.random() * 1000)}"
console.log('button id = ', id)
#...

然后我们可以看到哪个按钮被按下:

save: ->
console.log('pressed = ', @$('button').attr('id'))
#...

我们还将添加一个全局点击处理程序来监视 <button>主干之外的东西:

$(document).on('click', 'button', ->
console.log('global click = ', @id)
)

直播版本:http://jsbin.com/oviruz/6/edit

稍微尝试一下该版本,您可能会看到发生了什么:

  1. 更改 <input> 的内容.
  2. 尝试点击“保存”。
  3. 一旦 <input>失去焦点,更改事件被触发。
    1. 该事件调用 fieldChanged @model.set(...) .
    2. @model.set调用会触发 Backbone 的事件,特别是 @model.on(...)从 View 的initialize .
    3. Backbone 事件将我们带入 render其作用是 @$el.html(...)它取代了 <input><button> .
    4. html 调用会杀死 View el 内的所有 DOM 元素。但是,这是一个很大的但是,浏览器需要在此过程完成之前再次获得控制权。
  4. 现在我们回到事件队列来处理保存的点击。但是<button>我们点击的是僵尸,因为浏览器的工作队列如下所示:处理点击事件,替换3.4中的DOM元素。这里 3.4 的工作尚未完成,因此 <button>您点击的内容一半在 DOM 中,一半处于死状态,不会响应任何事件。

你有两个事件队列互相争斗;你的 Backbone 事件正在浏览器背后更改 DOM,并且由于 JavaScript 是单线程的,浏览器正在丢失并变得困惑。

如果您延迟@$el.html调用足够长的时间让浏览器跟上:

set_html = =>
@$el.html """
<input type="text" id="text" value="#{@model.get('foo')}"/>
<button class="save" id="#{id}">Save</button>
"""
setTimeout(set_html, 1000) # Go higher if necessary.

您将得到您所期望的行为。但这是一个可怕的、可怕的、肮脏的、可耻的拼凑。

当您仍在处理 DOM 元素上的事件时,对 DOM 进行摆弄是充满危险的,而且无异于一种伤害自己的复杂方式。

如果您想在字段更改时验证字段并绑定(bind) View 的render"change"模型上的事件,那么我认为您必须手动进行验证并使用静默 set调用:

fieldChanged: (e) ->
field = @$(e.currentTarget)
@model.set({ foo: field.val() }, { silent: true })
// @model.validate(@model.attributes) and do something with the return value

如果您执行@model.save()保存按钮的回调中,静默更改将被集体验证并发送到服务器。像这样的:http://jsbin.com/oviruz/7/edit

或者您跳过 @model.set里面fieldChanged只需使用 @model.validate :

fieldChanged: (e) ->
val = @$(e.currentTarget).val()
// @model.validate(foo: val) and do something with the return value

并保留 save 的所有设置内容:

save: ->
@model.save(foo: @$('#text').val())

类似这样的:http://jsbin.com/oviruz/8/edit

关于Backbone.js 'swallows' 如果另一个事件触发重新渲染,则单击事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12762111/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com