简体   繁体   中英

Rendering and executing <script> on pageload after injecting it from external .js file

I'm still a beginner with JavaScript and am trying to use it to make the Etsy Mini API responsive. I have two <script> s that need to be added to a <div> in order for the mini shop to appear:

<script type='text/javascript' src='https://www.etsy.com/assets/js/etsy_mini_shop.js'></script>
<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',4,3,0,'https://www.etsy.com');</script>

In the second <script> , I can specify the size of a thumbnail grid, (4x3 in the example above), but this grid is not responsive, so if it's loaded on a device with a smaller screen, or if a laptop's browser window is resized, the 4x3 grid might be too big. I want to use media queries in an external .js file to change this thumbnail grid, and this is where I'm running into problems.

Below is my current external .js file:

var products = document.getElementById("products-card");
var grid5x3 = "<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',5,3,0,'https://www.etsy.com');</script>";
var grid4x3 = "<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',4,3,0,'https://www.etsy.com');</script>";
var grid3x3 = "<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',3,3,0,'https://www.etsy.com');</script>";
var grid2x3 = "<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',2,3,0,'https://www.etsy.com');</script>";
var grid1x3 = "<script type='text/javascript'>new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',1,3,0,'https://www.etsy.com');</script>";

(function () {
    function resize() {
        var min_2500 = window.matchMedia('only screen and (min-width: 2500px)').addListener(function () {
            products.innerText = grid5x3;
        });
        var min_1900_max_2499 = window.matchMedia('only screen and (min-width: 1900px) and ' +
        '(max-width: 2499px)').addListener(function () {
            products.innerText = grid4x3;
        });
        var min_1200_max_1899 = window.matchMedia('only screen and (min-width: 1200px) and ' +
        '(max-width: 1899px)').addListener(function () {
            products.innerText = grid3x3;
        });
        var min_900_max_1199 = window.matchMedia('only screen and (min-width: 900px) and ' +
        '(max-width: 1199px)').addListener(function () {
            products.innerText = grid2x3;
        });
        var max_899 = window.matchMedia('only screen and (max-width: 899px)').addListener(function () {
            products.innerText = grid1x3;
        });
    }

    resize();
}());

And here is the .html:

<head>
  ...
  <script type='text/javascript' src='https://www.etsy.com/assets/js/etsy_mini_shop.js'></script>
</head>
<body>
  ...
  <div class="products-card" id="products-card"></div>
  ...
</body>

Problem 1: The script isn't executed, but rather the actual text, <script> tags included, appears in the <div> . How can I change my Javascript to make the script execute and render the mini shop?

Problem 2: The <div> is empty upon page load, but after the browser screen is resized and hits one of the cutoffs specified in the media queries, the text appears and changes properly according to the media queries. How can I make the shop render in the <div> on page load and not just when the browser window is resized?

UPDATE 1 So I discovered that using innerText/innerHTML does not allow any scripts to be executed/rendered when injected into the html file ( based on an answer here ). Here is my new .js file:

var products = document.getElementById("products-card");
var grid5x3 = "new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',5,3,0,'https://www.etsy.com');";
var grid4x3 = "new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',4,3,0,'https://www.etsy.com');";
var grid3x3 = "new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',3,3,0,'https://www.etsy.com');";
var grid2x3 = "new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',2,3,0,'https://www.etsy.com');";
var grid1x3 = "new Etsy.Mini(<UNIQUE_SHOP_ID>,'thumbnail',1,3,0,'https://www.etsy.com');";

(function () {
    function resize() {
        var min_2500 = window.matchMedia('only screen and (min-width: 2500px)').addListener(function () {
            var eval_grid5x3 = eval(grid5x3);
            products.innerText = eval_grid5x3;
        });
        var min_1900_max_2499 = window.matchMedia('only screen and (min-width: 1900px) and ' +
        '(max-width: 2499px)').addListener(function () {
            var eval_grid4x3 = eval(grid4x3);
            products.innerText = eval_grid4x3;
        });
        var min_1200_max_1899 = window.matchMedia('only screen and (min-width: 1200px) and ' +
        '(max-width: 1899px)').addListener(function () {
            var eval_grid3x3 = eval(grid3x3);
            products.innerText = eval_grid3x3;
        });
        var min_900_max_1199 = window.matchMedia('only screen and (min-width: 900px) and ' +
        '(max-width: 1199px)').addListener(function () {
            var eval_grid2x3 = eval(grid2x3);
            products.innerText = eval_grid2x3;
        });
        var max_899 = window.matchMedia('only screen and (max-width: 899px)').addListener(function () {
            var eval_grid1x3 = eval(grid1x3);
            products.innerText = eval_grid1x3;
        });
    }

    resize();
}());

While this does render the Etsy mini shop, it does so with some odd behaviors:

  1. The entire <body> is replaced with the injected script, when I expected the targeted <div> to be replaced with the script.

  2. Every time I resize the screen, it adds another Etsy mini shop (it does not replace the one that is currently there), resulting in the page becoming filled with numerous shops.

  3. The issue of it not rendering on pageload is still there.

Apologies if this is a rather simple question. I've spent a lot of time Googling solutions but nothing I've tried has worked. The code I have above is the closest I've come to having a responsive Etsy Mini shop. Thanks for any answers/comments/suggestions!

You should always put your JS script just before the close of the body tag so that way everything is loaded on the page then the JS file is executed or else it would run the file first then load the page causing it to not perform any function since the HTML is not yet loaded. The code is always read from left to right and top to bottom. Hope this helps.

I tried getting this to work with the "update and refresh the <script> tag" approach, and just wasn't able to get things to render correctly. However, I did a little digging and it turns out Etsy.Mini just injects an <iframe> into the page. If you grab that <iframe> and update the URL within, you can change the sizing of the Etsy Mini.

Here's an example of an <iframe> loaded by Etsy Mini.

<iframe frameborder="0"
    src="https://www.etsy.com/mini.php?shop_id=9999999&amp;image_type=gallery&amp;rows=5&amp;columns=5&amp;featured=0"
    width="975" height="1025">
</iframe>

The key to this is the URL in the src section of that <iframe> . There are two properties of note in the URL, rows and columns . Updating these properties while the page is rendered will change the sizing of the Etsy Mini, and thereby achieve something akin to bastardized responsiveness.

First, wrap your Etsy Mini script tags in a <div> with some id. This allows you to easily find the <iframe> . It'll be the only one inside of the <div> so long as you don't put anything else within except the <script> tags.

<div id="etsy-iframe-container">
    <script type='text/javascript' src='https://www.etsy.com/assets/js/etsy_mini_shop.js'></script>
    <script type='text/javascript'> new Etsy.Mini(9999999, 'gallery', 5, 5, 0, 'https://www.etsy.com');</script>
</div>

For reference purposes, since Etsy has erased all official trace of it from their website (but as of 2022 it still works!) the structure of an Etsy.Mini is.

Etsy.Mini(
    shopId (Integer), 
    type (String: 'gallery' or 'thumbnail'), 
    columns (Integer), 
    rows (Integer), 
    showUpTo4FeaturedItemsFirst (Boolean: 0 or 1), 
    etsyHomepageUrl (String: must be 'https://www.etsy.com')
)

You can get your Etsy shop id by pasting in your shop URL here . After wrapping your Etsy Mini <script> tags in a <div> , you can use the JavaScript below (create a custom JS file and load it into your HTML document) to resize the <iframe> dynamically by modifying its URL.

This is based on knowledge of the current screen's dimensions. A single Etsy Mini cell is always 184px in width and height. I discovered this by inspecting one in a Browser. With this knowledge, you can calculate how many Etsy Mini's will fit horizontally on the screen and update the <iframe> accordingly. The same approach could be used for updating the number of rows, but I don't think that's really necessary given that most browsers support infinite scroll these days. Setting the minColumns and maxColumns allows you to provide some bounds for what the Etsy Mini should look like at extremes.

let resizeEtsyMini = () => {
    let minColumns = 1;
    let maxColumns = 5;
    let clientWidth = document.documentElement.clientWidth;
    let etsyMiniColumns = Math.floor(clientWidth / 184);

    if (etsyMiniColumns < minColumns) {
        etsyMiniColumns = minColumns;
    }
    else if (etsyMiniColumns > maxColumns) {
        etsyMiniColumns = maxColumns
    }
    
    // Row value can be whatever, browsers have infinite scroll these days.
    setEtsyMiniSize(5, etsyMiniColumns, clientWidth);
}

let setEtsyMiniSize = (rows, columns, iframeWidth) => {
    let etsyIframe = document.getElementById("etsy-iframe-container").getElementsByTagName("iframe");
    let etsyURL = new URL(etsyIframe[0].src);
    etsyURL.searchParams.set("rows", rows);
    etsyURL.searchParams.set("columns", columns);

    etsyIframe[0].src = etsyURL.toString();
    etsyIframe[0].width = iframeWidth;
}

// On initial page load, and on every window resize, call resizeEtsyMini.
window.onload = window.onresize = resizeEtsyMini;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM