I have following JavaScript code that I put into the header of my page to defer load images on my page.
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-defer')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-defer'));
} } }
window.onload = init;
and here is my html
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-defer="image.jpg"/>
But unfortunately it takes too long to execute, in other words it takes long time to change the src value in img tag.
What I am doing wrong here, let me know if there exists some efficient way to defer images.
Regards.
Related
I have a lot of images (of 5 categories) in my website which make it load slowly.
I set every image with Attribute "data-src" containing its real source, and I update its source attribute with this "data-src" attribute for every image in this categroy (inside a for loop), whenever the relevant category is chosen (clicked).
HTML:
<img loading="lzay" class="post_image" data-src="https://i.ibb.co/FswR5KB/Pics-Art-06-22-07-48-49.jpg" src="https://i.ibb.co/FswR5KB/Pics-Art-06-22-07-48-49.jpg">
JAVASCRIPT:
for(i = 0; i< selection.length; i++){
let data_src = selection[i].children[2].getAttribute("data-src");;
selection[i].children[2].src = data_src;
}
How can I tell when all of the images of a category was loaded to the site?
(some code continue to run after the for loop is done, yet not all the images loaded and I wish the rest of the code will fire only after they are loaded to page).
Try this. I didn't have much time to come up with it, but it might work. Sorry if it doesn't.
index.html
<img id="img1" src="https://i.ibb.co/FswR5KB/Pics-Art-06-22-07-48-49.jpg"/>
<img id="img2" src="https://i.ibb.co/FswR5KB/Pics-Art-06-22-07-48-49.jpg"/>
<img id="img3" src="https://i.ibb.co/FswR5KB/Pics-Art-06-22-07-48-49.jpg"/>
<script type="text/javascript" src="script.js"></script>
script.js
const img1 = document.getElementById("img1");
const img2 = document.getElementById("img2");
const img3 = document.getElementById("img3");
const imgArray = [
img1,
img2,
img3
]
let imgsLoaded = 0;
for (let i = 0; i < imgArray.length; i++) {
imgArray[i].onload = function () {
imgsLoaded++;
}
if (imgsLoaded >= imgArray.length) {
// all images are loaded
}
}
I want to get the SRC from every <IMG> in twitter.
let n = document.getElementsByTagName("img");
for(tip of n){
console.log(tip.src);
}
and it works for other pages, but it doesn't for twitter. Finally I did this;
let n = document.getElementsByTagName("img");
function example(){
for(tip of n){
if(tip.src == "https://abs-0.twimg.com/emoji/v2/svg/1f1ea-1f1f8.svg"){
tip.src = "https://abs-0.twimg.com/emoji/v2/svg/1f3f3-fe0f-200d-1f308.svg";
}
}
}
setInterval(example, 100);
With setInterval it works, also, twitter loads stuff dynamically so with setInterval I can get all those new results. (How I could do that without using setInterval?)
Also, for some weird reason, the picture doesn't change. It doesn't update.
Update:
function example(){
let n = document.getElementsByTagName("div");
for(tip of n){
console.log(tip.style['background-image']);
if(tip.style['background-image'] == 'url("https://abs-0.twimg.com/emoji/v2/svg/1f1ea-1f1f8.svg")'){
tip.style['background-image']= 'url("https://abs-0.twimg.com/emoji/v2/svg/1f3f3-fe0f-200d-1f308.svg")';
}
}
}
setInterval(example, 10000);
Now it works perfectly, but how could I get the new data without using setInterval eeeeeeevery time and only call to the function when it's necessary?
You have to load image every time you want to iterate them, to get "fresh" img elements
Try this
function example(){
let n = document.getElementsByTagName("img"); // Moved here
for(tip of n){
if(tip.src == "https://abs-0.twimg.com/emoji/v2/svg/1f1ea-1f1f8.svg"){
tip.src = "https://abs-0.twimg.com/emoji/v2/svg/1f3f3-fe0f-200d-1f308.svg";
}
}
}
setInterval(example, 100);
It is not always that the images are shown with img tag.
If you see some cases on twitter, img tag's sibling is an element with img src in its styles. That element is showing the image. Obviously, this is not the case with every single image on twitter.
But for such a case, you change it's background by
let n = document.getElementsByTagName("img");
for(tip of n){
r.previousSibling.style.backgroundImage='YourImage.png'
}
Also, you have to use some kind of interval to get results that are loaded later. Or you could detect DOM changes using Mutation Observer and only fire your function on DOM change.
I try to combine 2 defer functions init to 1 Java script.
I actually try now combine another one but he make conflict and the JS very heavy. this is 2 different script + 1 is not so important (but if you guys succeed help me combine all of them perfectly is be better).
This the code I try put after I edit him 2( 2 functions init ):
function init() {
var imgDefer = document.querySelectorAll('div[data-src]');
var style = "background-image: url({url})";
for (var i = 0; i < imgDefer.length; i++) {
imgDefer[i].setAttribute('style', style.replace("{url}", imgDefer[i].getAttribute('data-src')));
}
imgDefer = document.getElementsByTagName('img');
for (var i = 0; i < imgDefer.length; i++) {
if (imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src', imgDefer[i].getAttribute('data-src'));
}
}
}
window.onload = init;
I make him a short too... he defers the images but slower the site:
function init(){for(var t=document.querySelectorAll("div[data-src]"),e=0;e<t.length;e++)t[e].setAttribute("style","background-image: url({url})".replace("{url}",t[e].getAttribute("data-src")));t=document.getElementsByTagName("img");for(e=0;e<t.length;e++)t[e].getAttribute("data-src")&&t[e].setAttribute("src",t[e].getAttribute("data-src"))}window.onload=init;
(you can look the code is deferred on the website: locksmithunit.com)
but he very slow on the page load.
and this all the original codes... these codes are for deferring images
and the last one is for "frame"
the frame not so important. and if you can give me him separately because
have pages I don't have iframe.
please help me guys, i very lost.
I most combine at least the first 2 scripts from all the 3 I send now:
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
<script>
<script>
function init() {
var imgDefer = document.querySelectorAll('div[data-src]');
var style = "background-image: url({url})";
for (var i = 0; i < imgDefer.length; i++) {
imgDefer[i].setAttribute('style', style.replace("{url}", imgDefer[i].getAttribute('data-src')));
}
}
window.onload = init;
</script>
<script>
function init() {
var vidDefer = document.getElementsByTagName('iframe');
for (var i=0; i<vidDefer.length; i++) {
if(vidDefer[i].getAttribute('data-src')) {
vidDefer[i].setAttribute('src',vidDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>
ok. so I try to defer images on my website... on 120 pages...
now, when i start, i was able to defer only images.
after that, I succeed defer the background-image: url().
but it is different JS as you see on the example I post before.
I succeed combine them but still, the JS no give full power.
after that, I start to fix again pages and i notice have google maps iframe
in couple of pages. ( something like 40 pages).
and I try to defer the iframe as well but it was too much for the javascript and the website loses the page load...
the JS needs to rewriting again...
i try a couple of variations as I post before, but none of them really improve the page load.
if we sucssed fix the Javascript at least put the 2 functions inside JS, JS of the background and images you will save me because I already edit all the 120 pages and the JS work and defer, but damage the page load because the JS is not written well.
(iframe is not so important like the images and the background)
Based on Patrick Sexton tutorial, I would like to defer background images in the same way I do here with img:
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>
How can I do the same using backgrounds?
<div style="background:url(your-image-here)"></div>
Changes needed are only how we select the element
document.querySelectorAll('div[data-src]');
and how we set the value (here instead of setting the src attribute, we need to set the style attribute).
EDIT: I would even avoid the attribute check (in the JavaScript) here since our selector would do it.
Mark-up (Edit code here: http://codepen.io/anon/pen/rryxoK)
function init() {
var imgDefer = document.querySelectorAll('div[data-src]');
var style = "background-image: url({url})";
for (var i = 0; i < imgDefer.length; i++) {
imgDefer[i].setAttribute('style', style.replace("{url}", imgDefer[i].getAttribute('data-src')));
}
}
window.onload = init;
.deferImage {
width: 800px;
height: 600px;
}
<div class="deferImage" data-src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Domestic-crested-duck-CamdenME.jpg/800px-Domestic-crested-duck-CamdenME.jpg"></div>
EDIT: To select by class name
You can just do the same idea but instead of source you change the background in the init function
<div id='my-div' style="" data-src="your-image-here"></div>
<script>
function init() {
var backgroundDefer = document.getElementById('my-div');
if(backgroundDefer.getAttribute('data-src')) {
backgroundDefer.style.background="url("+backgroundDefer.getAttribute('data-src')+")";
}
}
window.onload = init;
</script>
I tried to use getElementsByClassName() and also ended up getting the backgroundDefer.getAttribute is not a function error. So I ended up inject id attribute, as well as the data-src attribute to be used as a placeholder for image URI and used the above code to defer background image.
I also have to first of all make an empty string in the background URI image.
<div id="my-div" class="parallax-background" data-stellar-background-ratio="0.7" data-src="https://d5y2y5rl4e57i.cloudfront.net/GWL_atl-108.jpg" style="background-image:url('')"></div>
<script>
function init() {
var backgroundDefer = document.getElementById('my-div');
//have to use document.getElementById in order to use getAttribute() function
if(backgroundDefer.getAttribute('data-src')) {
backgroundDefer.style="background-image:url("+backgroundDefer.getAttribute('data-src')+")";
}
}
window.onload = init;
</script>
If all You want to do is set background after page load in pure JS use:
window.onload="myFunction()";
Where myFunction do the loading.
I would like to load a bunch of iframes at different times, not all at the same time but one after another like one at 300000ms, then 209000ms, then 257000ms, etc. They will all need to be loaded at different times after each other and I need to be able to change them later if needed. I would like it to be when I click a button not as an onload event. I have little experience in javascript.
Please no jQuery.
Thanks!
Edit: I want the iframes to load on top of one another, or replace one another, not load a bunch of them in a list. I will only be putting up around 5 iframes total. Sorry for not being specific enough. Something like this, except for the time working:
<a target='page' href='http://framedsite1'>#1 (visible for 300000ms)</a>
<a target='page' href='http://framedsite2'>#2 (visible for 209000ms)</a>
<a target='page' href='http://framedsite3'>#3 (visible for 257000ms)</a>
<iframe id='page' name='page' src=''></iframe>
Except for auto playing through them all, not as a bunch of links but by being clicked on and loaded into the iframe after a set amount of time after the previous frames time has gone by, kind of like a playlist. They will all need to be displayed for different amounts of time then load the next iframe, I am emphasizing that they all will be different amounts of time.
You can use setInterval() and loop through to set the source for each iframe:
var iframes = document.getElementsByTagName("iframe"); //retrieves a NodeList of iframes
var i = 0;
var interval = window.setInterval(function(){
if(i < iframes.length){
iframes[i].src = "//example.com"; //source of the iframes
i++;
}else{
window.clearInterval(interval);
}
}, 3000); //interval to load each iframe in milliseconds
Demo
If you want to trigger it with a button click, just wrap it in a function and attach an event listener:
document.getElementById("idOfButton").addEventListener("click", function(){
var iframes = document.getElementsByTagName("iframe"); //retrieves a NodeList of iframes
var i = 0;
var interval = window.setInterval(function(){
if(i < iframes.length){
iframes[i].src = "//example.com"; //source of the iframes
i++;
}else{
window.clearInterval(interval);
}, 3000); //interval to load each iframe in milliseconds
});
Demo
<html>
<head>
<script>
var iframes;
var loadIframes = function(){
iframes = document.getElementsByClassName('custom-iframe');
for(var i=0; i<iframes.length; i++){
var iframe = iframes[i],
seconds = iframe.getAttribute('data-seconds'),
src = iframe.getAttribute('data-src');
run(i, src, seconds);
}
}
var run = function(i, src, seconds){
setTimeout(function(){
iframes[i].src = src;
}, seconds);
}
</script>
</head>
<body>
<button onclick="loadIframes()">Load iframes</button>
<iframe class="custom-iframe" data-seconds="3000" data-src="http://example.com"></iframe>
<iframe class="custom-iframe" data-seconds="900" data-src="http://google.com"></iframe>
</body>
</html>
Just change "data-seconds" and "data-src" attributes in each iframe, and put "custom-frame" class in the iframe elements.
When you click the button, they will run based on the iframe custom configs.
<html>
<head>
<script>
var buttons = document.getElementsByClassName('iframe-button');
var iframe = document.getElementById('my-iframe');
for(var i=0; i < buttons.length; i++){
var button = buttons[i];
button.addEventListener("click", function(){
var src = button.getAttribute('data-src');
iframe.src = src;
});
}
</script>
</head>
<body>
Example.com
Google.com
<iframe id="my-iframe"></iframe>
</body>
Just need to repeat those <a> elements. Put "iframe-button" class on them, and "data-src" attribute if the URL value.