Javascript 函数在 Firefox 中运行多次,但在 Chrome 中只运行一次,为什么?

发布于 2025-01-04 22:46:45 字数 939 浏览 2 评论 0原文

我有一个文件上传字段,我添加了 jQuery 更改。

在 Chrome 中,它工作得很好,loadImage 函数用要上传的图片的渲染替换占位符图片。在firefox中,以下代码渲染3次(控制台中有3个“1”,但onchange处理程序中只有1个“2”),并且图像在添加后随后被删除。

为什么在 Firefox 中会发生这种情况,我该如何防止它?

Coffeescript(如果有人喜欢更好地阅读 js,我可以转换):

$('#project_display_pic').change (e) ->
  console.log "2"
  value = $(this).val()
  value = value.replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage(
    e.target.files[0],
    ( (img) -> 
      console.log "1"
      $('#display_pic_preview > img').remove()
      $('#display_pic_preview').append(img)
    ),
    {maxWidth: 212}
  )

Haml 如果有帮助的话(#project_display_pic 是文件字段的 id):

    #display_pic_preview
      = image_tag( @project.display_pic.medium.url, :class => "default_pic" )
    #display_pic_uploader
      %p Add display image
      = f.file_field :display_pic

I've got a file upload field which i added a jQuery change to.

In chrome it works great, the loadImage function replaces a placeholder pic with a render of the pic to be uploaded. In firefox the following code renders 3 times (there are 3 "1"'s in the console, but only one "2" from the onchange handler) and the image is subsequently removed after it is added.

Why does this happen in Firefox, and how can i prevent it?

Coffeescript (i can convert if anyone likes to read js better):

$('#project_display_pic').change (e) ->
  console.log "2"
  value = $(this).val()
  value = value.replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage(
    e.target.files[0],
    ( (img) -> 
      console.log "1"
      $('#display_pic_preview > img').remove()
      $('#display_pic_preview').append(img)
    ),
    {maxWidth: 212}
  )

Haml if that helps (#project_display_pic is the id of the filefield):

    #display_pic_preview
      = image_tag( @project.display_pic.medium.url, :class => "default_pic" )
    #display_pic_uploader
      %p Add display image
      = f.file_field :display_pic

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青柠芒果 2025-01-11 22:46:45

查看插件的代码,看来它会调用图像对象的 onloadonerror 事件的渲染回调。也许 Firefox 错误地将图像的缩放算作加载事件或其他事件?或者错误事件可能无缘无故地被触发。

不管怎样,快速修复可能是这样的:

# Builds a function to show the loaded image
# The function stores the last img object it received,
# and doesn't try to show the same one twice in a row
createRenderCallback = ->
  lastImg = null

  (img) ->
    return if img is lastImg # don't handle the same img twice
    # Note that if the image failed to load, `img` will be undefined
    # You may want to check for that before trying to append it
    $('#display_pic_preview > img').remove()
    $('#display_pic_preview').append(img)
    lastImg = img # remember the img

# Attach the file input's change handler (pretty much the same as before)
$('#project_display_pic').change (e) ->
  value = $(this).val().replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage e.target.files[0], createRenderCallback(), { maxWidth: 212 }

您可以在插件的代码中执行类似的操作,以避免它重新调用回调。或者您可以从插件中记录一些内容以准确查看发生了什么。


编辑:由于将图像插入到 DOM 中似乎会触发渲染回调,因此您可以尝试以下操作:

createRenderCallback = ->
  lastImg = null

  (img) ->
    return if img is lastImg
    lastImg = img # <-- Move this line to here, i.e. before inserting the image
    $('#display_pic_preview > img').remove()
    $('#display_pic_preview').append(img)

或者,您可以简单地删除事件侦听器,而不是保留记录lastImg

renderCallback = ->
  if img? # this function was called from an onload event
    img.onload = img.onerror = null

  else  # called from an onerror event
    @onload = @onerror = null

  $('#display_pic_preview > img').remove()
  $('#display_pic_preview').append(img) if img?

$('#project_display_pic').change (e) ->
  value = $(this).val().replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage e.target.files[0], renderCallback, { maxWidth: 212 }

Looking at the plugin's code, it appears that it invokes your render-callback for the image object's onload and onerror events. Perhaps Firefox erronously counts the scaling of the image as a load event or something? Or perhaps the error event is being triggered for no good reason.

Eitherway, a quick fix could be something like this:

# Builds a function to show the loaded image
# The function stores the last img object it received,
# and doesn't try to show the same one twice in a row
createRenderCallback = ->
  lastImg = null

  (img) ->
    return if img is lastImg # don't handle the same img twice
    # Note that if the image failed to load, `img` will be undefined
    # You may want to check for that before trying to append it
    $('#display_pic_preview > img').remove()
    $('#display_pic_preview').append(img)
    lastImg = img # remember the img

# Attach the file input's change handler (pretty much the same as before)
$('#project_display_pic').change (e) ->
  value = $(this).val().replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage e.target.files[0], createRenderCallback(), { maxWidth: 212 }

You could do something similar in the plugin's code, to avoid it re-calling the callback. Or you could log some stuff from the plugin to see precisely what's going on.


Edit: Since inserting the image into the DOM appears to trigger the render callback, you can try this:

createRenderCallback = ->
  lastImg = null

  (img) ->
    return if img is lastImg
    lastImg = img # <-- Move this line to here, i.e. before inserting the image
    $('#display_pic_preview > img').remove()
    $('#display_pic_preview').append(img)

Or, you can simply remove the event listeners instead of keeping a record of the lastImg

renderCallback = ->
  if img? # this function was called from an onload event
    img.onload = img.onerror = null

  else  # called from an onerror event
    @onload = @onerror = null

  $('#display_pic_preview > img').remove()
  $('#display_pic_preview').append(img) if img?

$('#project_display_pic').change (e) ->
  value = $(this).val().replace("C:\\fakepath\\","")
  $('#display_pic_uploader > p').text(value)
  loadImage e.target.files[0], renderCallback, { maxWidth: 212 }
谎言 2025-01-11 22:46:45

firefox 多次调用此函数并出现错误。此代码也应该有效(通过检查宽度属性来检查它是否是图像对象:

loadImage(file, function(image) {
        if(typeof(image.width) !== "number") { // make sure its an image and not an error
          return;
        }
}

firefox calls this function multiple times with an error. this code should also work (check if it is an image object by checking the width property:

loadImage(file, function(image) {
        if(typeof(image.width) !== "number") { // make sure its an image and not an error
          return;
        }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文