是否可以在加载后在页面的其他部分加载后克隆图像?

时间:2016-08-20 06:18:50

标签: javascript jquery html css image

我遇到了一个简单的问题。假设我的用户通过一个简单的<img data-image='1' src="myimg1.jpg"> <img data-image=2' src="myimg2.jpg">等等来加载大约150张图片

当用户将鼠标悬停在其中一个图像上时。我希望在屏幕底部的小菜单中显示此myimg-thisimage.jpg。截至目前,我将菜单中的src属性更改为:

$('#info-poster').attr("src","myimage-thisimage.jpg");

注意: myimage-thisimage.jpg是当前悬停在图片上方。

但是,当我这样做的时候。浏览器正在重新加载图像(因为,有一个小的延迟)。是否有任何方法可以绕过此加载,因为用户已经使用克隆DOM元素的巧妙方式加载了图像?

PS:启用浏览器图片缓存。因此,缓存不是问题。

编辑:我知道一种方法是创建300个图像元素并隐藏其他150个图像元素。但在一个场景(绝对可能)中,有近500张图像,我将不得不创建大约1000个DOM元素,这将是一个很大的性能问题。

7 个答案:

答案 0 :(得分:6)

您可以使用画布元素来显示缩略图,这样就可以复制图像并在本地缩放 。在下面的片段中我添加了两个画布,在第一个画面中缩放图像同时保持宽高比(我需要时使用Letterboxing和Pillarboxing技术);在第二个图像被拉伸。我还在底部添加了另一个被忽略的图像,因为它没有data-image属性。

重要的是不要使用drawImage的缩放算法,因为当你大量减少图像时会产生不平滑的结果。要实现此目的,请设置画布的逻辑大小以匹配图像的自然大小。然后通过调用drawImage方法将图像复制到画布。最后将画布的显示大小设置为所需的大小。这样浏览器就可以使用更好的算法来缩放图像。

以下是 drawImage()方法的 specification 的一些优秀引文:

  • 您可以确定不会重新加载图片,并且您必须使用图片的自然尺寸以避免使用drawImage进行缩放:
  

如果原始图像数据是位图图像,则通过过滤原始图像数据来计算在目标矩形中的点处绘制的值。

  • 浏览器决定使用哪种缩放算法。在写这篇文章的那一刻:Edge,Chrome和Firefox并没有比双线性或最近邻算法更好用。这可能会在未来发生变化:
  

用户代理可以使用任何过滤算法(例如双线性插值或最近邻居)。

function initCanvas(id,image,naturalWidth,naturalHeight){
    var canvas = document.getElementById(id);
    var ctx = canvas.getContext("2d");
    // Set the logical size of the canvas to match the 
    // natural size of the image, this way we don't use
    // the scaling algorithm of drawImage (It isn't good
    // for reducing big images as it produces unsmooth results).
    $(canvas).attr("width",naturalWidth) ;
    $(canvas).attr("height",naturalHeight) ;
    // Copy the image:
    ctx.drawImage(image,0,0,naturalWidth,naturalHeight);
    return canvas ;
}
function clearCanvas(id){
    var canvas = document.getElementById(id);
    var ctx = canvas.getContext("2d");
    ctx.clearRect(0,0,canvas.width,canvas.height);
}
$(window).on("load", function( ){
    var images = $("img").filter(function(){
        var dataImage = $(this).data("image") ;
        if( typeof dataImage != "number" ) return false ;
        var number = parseInt(dataImage,10) ;
        return number > 0 && dataImage === number ;
    }) ;
    images.on("mouseenter", function( ){
        var naturalWidth = $(this).prop("naturalWidth") ;
        var naturalHeight = $(this).prop("naturalHeight") ;

        // Scaled thumbnail:
        // Copy the image to canvas-scaled and get a reference to it:
        var scaledCanvas = initCanvas("canvas-scaled",this,naturalWidth,naturalHeight);
        // Calculate the display size of the canvas:
        var hwfactor = naturalHeight/naturalWidth ;
        var whfactor = naturalWidth/naturalHeight ;
        var scaledWidth, scaledHeight ;
        if( hwfactor >= 1 ){ // Pillarboxing
            scaledHeight = "100px" ;
            scaledWidth = (100*whfactor)+"px" ;
        }
        else{ // Letterboxing
            scaledWidth = "100px" ;
            scaledHeight = (100*hwfactor)+"px" ;
        }
        // Now we change the display size of the canvas.
        // A better scaling algorithm will be used.
        $(scaledCanvas).css("width",scaledWidth);
        $(scaledCanvas).css("height",scaledHeight);

        // Stretched thumbnail:
        // Copy the image to canvas-stretched. The display size
        // of canvas-stretched is already set in the style section.
        initCanvas("canvas-stretched",this,naturalWidth,naturalHeight);
    });
    images.on("mouseleave", function( ){
        clearCanvas("canvas-scaled");
        clearCanvas("canvas-stretched");
    });
});
body{
    background: #000;
}
.wrapper img{
    width: 100px ;
    height: auto ;
}
#banner{
    display: block ;
    width: 100% ;
    height: 40px ;
    padding-top: 1pt ;
}
#canvas-stretched{
    width: 100px ;
    height: 100px ;
}
.canvas-wrapper{
    display: -webkit-inline-flex ;
    display: inline-flex ;
    -webkit-justify-content: space-around ;
    justify-content: space-around ;
    -webkit-align-items: center ;
    align-items: center ;
    vertical-align: bottom ;
    border: 1px solid #888 ;
    width: 100px ;
    height: 100px ;
    overflow: hidden ;
}
.viewer{
    display: inline-block ;
}
.viewer span{
    color: #ddd ;
    font-family: sans-serif ;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

<span class="wrapper">
    <img data-image="1" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/550px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg"/>
    <img data-image="2" src="https://upload.wikimedia.org/wikipedia/en/8/81/Megadrive_another_world.png"/>
    <img data-image="3" src="https://upload.wikimedia.org/wikipedia/en/e/ee/TheKlingonHamlet.jpg"/>
</span>
<span class="viewer">
    <span>scaled</span><br>
    <div class="canvas-wrapper">
        <canvas id="canvas-scaled"></canvas>
    </div>
</span>
<span class="viewer">
    <span>stretched</span><br>
    <div class="canvas-wrapper">
        <canvas id="canvas-stretched"></canvas>
    </div>
</span>
<img id="banner" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/The_southern_plane_of_the_Milky_Way_from_the_ATLASGAL_survey.jpg/320px-The_southern_plane_of_the_Milky_Way_from_the_ATLASGAL_survey.jpg"/>

答案 1 :(得分:3)

这一行是问题所在:

$('#info-poster').attr("src","myimage-thisimage.jpg");

浏览器正在重新加载图像,因为您重新设置了(不良做法)&#34; src&#34;属性。
相反,您可以使用CSS选项来显示/隐藏&#34; myimage-thisimage.jpg&#34;。

由于您使用jQuery,我们可以使用这些方法:hide/show

你提到&#34;克隆&#34;,我不认为你是HTML elements clonning

示例:(live on JS Bin

<img id="dummy" width="200" height="150" data-image='1' src="http://europunkt.ro/wp-content/uploads/2016/06/romania.jpg">

<!-- Hidden by default -->
<img style="display:none" id="info-poster"  width="200" height="150">



<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script>
  var $dummy      = $("#dummy");
  var $infoPoster = $("#info-poster");

  var infoPosterHasLoaded = false;

  $dummy.on("mouseenter", function() {
    // add the src attribute ONLY once
    if(infoPosterHasLoaded === false){
      $infoPoster.attr("src", "http://www.ilovemaramures.com/wp-content/uploads/2012/05/Pasul-Prislop.jpg")
      infoPosterHasLoaded = true;
    }
    $infoPoster.show();
  });

  $dummy.on("mouseleave", function() {
    $infoPoster.hide();
  });
</script>

更加花哨的&#34;隐藏/显示&#34;你可以查看jQuery Effects


修改 - 在我阅读您的评论之后

如果您想使用&#34;数据图像&#34;来自悬停元素的属性,请检查以下对象:event.targetevent.currentTargetthis

新的JS Bin版本。

答案 2 :(得分:2)

您可以将服务器上的图像请求转换为使用base64字符串进行响应,该字符串可以存储在您自己的缓存中。

以下示例代码:

<强> HTML

  <img id="image1Id" src="" />
  <input type="button" onclick='javascript:loadSomeThing("image1", "", "image1Id");' value="Load Image1" />

<强>脚本

var imageArray = [];

function loadSomeThing(key, someUrl, elementId) {
  var imageData = imageArray[key];
  if (!imageData) {
    imageData = ajaxGetImageData(someUrl);
    imageArray[key] = imageData;
  }
  document.getElementById(elementId).src = imageData;
}

function ajaxGetImageData(url) {
  //Code to get base64 image string
  return "data:image/jpeg;base64,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";
}

<强>演示

jsFiddle

答案 3 :(得分:1)

我相信使用jQuery .clone().append()函数可以实现您的需求。请参阅下面的示例。

jQuery.clone()

jQuery.append()

$(function() {
  $('img#ToClone').click(function(){
    var imageClone = $('#ToClone').clone();
    var cloneDestination = $('#CloneTo');
    cloneDestination.append(imageClone);
  });
});
                     
div
{
  padding:2px;
  background:blue;
}
div#CloneTo
{
  background:green;
}
img{
  height:50px;
  width:50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <p>Click on the red square to clone it below.</p>
  <img id="ToClone" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGlSURBVHhe7dCxTQQAEMRACiGk/86o4UmMxEpY/KW8R5ddtH575GnFOijWQbEOinVQrINiHRTroFgHxTr4Pdbbq2K/KNZgvyjWYL8o1mC/KNZgv3gq1uf7x389Fn5jvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgv3gq1utgvyjWYL8o1mC/KNZgvyjWYL/4452finVQrINiHRTroFgHxToo1kGxDor1tMfjC8KHtIEDA9XCAAAAAElFTkSuQmCC" />
</div>
<div id="CloneTo">
  <p>Clone should appear here.</p>
  <!-- The cloned image should appear here. -->
</div>

答案 4 :(得分:0)

您应该让浏览器执行缓存处理。 我建议您可以使用<img id="info-poster" src="myimage-thisimage.jpg" class="hide-on-load"/>,因此如果您的浏览器要加载图片的新副本,则会在用户将鼠标悬停在其他图片上之前执行此操作。 (如果它是一个小/可接受的图像,用户可能必须在每次加载页面时下载它)

然后你可以简单地绑定$("img.bind-event").on("mouseenter", function() { $("#info-poster").show(); });$("img.bind-event").on("mouseleave", function() { $("#info-poster").hide(); });

答案 5 :(得分:0)

IDEA

初始标记

<img data-src='myimg1.jpg' data-image='1' src='placeholder.jpg'>

myimg1.jpg动态加载后(*)

<img data-image='1' src='blob:asdfasdfasdfasdfadfa'>

然后在'mouseenter'上

infoPosterEl.src = thisImageEl.src 
// update image src to an object url(e.g. "blob:") will not bother http comm.

(*)

// Fetch acutal image as blob 
// Create object url for the blob
// Update this <img> src to the object url

答案 6 :(得分:0)

您可以存储数组中每个图像的路径,使用Array.prototype.forEach()迭代数组,使用background设置每个<img>元素的url("/path/to/image");在使用mouseover,{{1}的集合中的h <img>元素索引的每个background-size设置100% 100%菜单元素的<img> Array.prototype.slice() }}。该方法应该最多一次从服务器请求每个图像,切换菜单元素处显示的图像以对应于悬停图像。

Array.prototype.splice()
var urls = ["http://placehold.it/100x100?text=1"
            , "http://placehold.it/100x100?text=2"
            , "http://placehold.it/100x100?text=3"
            , "http://placehold.it/100x100?text=4"
            , "http://placehold.it/100x100?text=5"]

, sources = []

, sizes = []

, imgs = document.querySelectorAll(".img")

, menu = document.querySelector(".menu");

function toggleImage(index) {
  this.onmouseover = function() {
    
    var curr = sizes.slice(0);
    curr.splice(index, 1, "100% 100%");
    menu.style.backgroundSize = curr.join(",");
  }
}

urls.forEach(function(path, index) {
  sources.push("url(" + path + ")");
  sizes.push("0% 0%");
  imgs[index].style.background = sources[index];
  toggleImage.call(imgs[index], index);
});

menu.style.background = sources.join(",");
menu.style.backgroundSize = sizes.join(",");
.menu {
  left: calc(100vw / 2 - 50px);
  position: relative;
  width: 75px;
  height: 75px;
  display: block;
}