制作一个用于获取 Reddit 帖子的滑动器

问题描述 投票:0回答:1

const clientId = "CLIENT-ID";
const clientSecret = "CLIENT-SECRET";

async function fetchPosts() {
  const response = await fetch(
    "https://www.reddit.com/r/memes/hot.json?limit=10"
  );
  const data = await response.json();
  
  // Exclude stickied posts
  const nonStickiedPosts = data.data.children.filter(post => !post.data.stickied);

  return nonStickiedPosts;
}

function filterValidPosts(posts) {
  return posts.filter(
    (post) =>
      post.data.title &&
      post.data.url &&
      post.data.url.startsWith("http") &&
      post.data.url.includes(".gif") &&
      post.data.url.includes("v.redd.it") &&
      post.data.self && // Exclude self-posts
      !post.data.removed // Exclude deleted posts
  );
}


function convertToDirectLink(redditMediaLink) {
    const url = new URL(redditMediaLink);

    // Check if it's a Reddit preview link
    if (url.hostname === "preview.redd.it") {
        const [mediaId, format] = url.pathname.split("/").pop().split(".");

        if (mediaId && format) {
            // Build the direct link
            return `https://i.redd.it/${mediaId}.${format}`;
        }
    }

    // If it's not a Reddit preview link, return the original link
    return redditMediaLink;
}

// ...

// Function to render posts as cards on the webpage
async function renderPosts(posts) {
  const container = document.getElementById("postsContainer");
  container.innerHTML = "";

  for (let i = 0; i < posts.length; i += 3) {
    const row = document.createElement("div");
    row.classList.add("row");

    for (let j = i; j < i + 3 && j < posts.length; j++) {
      const post = posts[j];

      const card = document.createElement("div");
      card.classList.add("card");
      const cardContent = document.createElement("div");
      cardContent.classList.add("card-content");

      if (post.data.is_gallery) {
        // Handle Reddit galleries
        if (post.data.media_metadata) {
          // Iterate over media_metadata to get direct links
          for (const mediaId in post.data.media_metadata) {
            const galleryImage = post.data.media_metadata[mediaId];
            const directLink = convertToDirectLink(galleryImage.s.u); // Use the s.u field for direct link
            const image = document.createElement("img");
            image.src = directLink;
            image.alt = post.data.title;
            cardContent.appendChild(image);
          }
        }
      } else if (post.data.url) {
        // Handle posts with a single image or external links
        const image = document.createElement("img");
        image.src = await convertToDirectLink(post.data.url);
        image.alt = post.data.title;
        cardContent.appendChild(image);
      }

      cardContent.innerHTML += `<h3>${post.data.title}</h3>`;
      card.appendChild(cardContent);
      row.appendChild(card);
    }

    container.appendChild(row);
  }
}




async function fetchAndRenderNewPosts() {
  try {
    const posts = await fetchPosts();
    const validPosts = filterValidPosts(posts);

    if (validPosts.length > 0) {
      renderPosts(validPosts);
    } else {
      console.warn("No valid posts fetched. Trying again with new posts.");
      const newPosts = await fetchPosts();
      renderPosts(newPosts);
    }
  } catch (error) {
    console.error("Error fetching or rendering posts:", error);
  }
}

window.onload = function () {
  fetchAndRenderNewPosts();

  setInterval(fetchAndRenderNewPosts, 300000); // Fetch new posts every 5 minutes (adjust as needed)
};
body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
}

.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    align-items: flex-start;
    max-height: 100vh; /* Set a maximum height for the container */
    overflow-y: auto; /* Add vertical scroll if needed */
}

.row {
    display: flex;
    justify-content: space-around;
    margin-bottom: 20px; /* Adjust as needed for spacing between rows */
}

.card {
    margin: 10px;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    transition: box-shadow 0.3s ease-in-out;
    overflow: hidden;
    width: calc(33% - 20px); /* Adjust as needed for spacing between cards */
    max-width: 300px; /* Limit the maximum width of each card */

}

.card:hover {
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

.card-content {
    position: relative;
}

.card img {
    width: 100%;
    height: 100%;
    object-fit: cover; /* Ensure the image covers the entire container */
}
<div class="container" id="postsContainer"></div> 

我创建了一个 Reddit 帖子获取网站,我可以在卡片中获取画廊(包含多个图像的帖子),其中放置了所有图像,并且将单个图像作为卡片及其标题发布。现在对于画廊类型的帖子,我想制作一个滑动器,这样我就可以滑动而不是在一个卡盒中连续看到多个图像,但我不知道该怎么做。

function convertToDirectLink(redditMediaLink) {
    const url = new URL(redditMediaLink);

    // Check if it's a Reddit preview link
    if (url.hostname === "preview.redd.it") {
        const [mediaId, format] = url.pathname.split("/").pop().split(".");

        if (mediaId && format) {
            // Build the direct link
            return `https://i.redd.it/${mediaId}.${format}`;
        }
    }

    // If it's not a Reddit preview link, return the original link
    return redditMediaLink;
}

// ...

// Function to render posts as cards on the webpage
async function renderPosts(posts) {
  const container = document.getElementById("postsContainer");
  container.innerHTML = "";

  for (let i = 0; i < posts.length; i += 3) {
    const row = document.createElement("div");
    row.classList.add("row");

    for (let j = i; j < i + 3 && j < posts.length; j++) {
      const post = posts[j];

      const card = document.createElement("div");
      card.classList.add("card");
      const cardContent = document.createElement("div");
      cardContent.classList.add("card-content");

      if (post.data.is_gallery) {
        // Handle Reddit galleries
        if (post.data.media_metadata) {
          // Iterate over media_metadata to get direct links
          for (const mediaId in post.data.media_metadata) {
            const galleryImage = post.data.media_metadata[mediaId];
            const directLink = convertToDirectLink(galleryImage.s.u); // Use the s.u field for direct link
            const image = document.createElement("img");
            image.src = directLink;
            image.alt = post.data.title;
            cardContent.appendChild(image);
          }
        }
      } else if (post.data.url) {
        // Handle posts with a single image or external links
        const image = document.createElement("img");
        image.src = await convertToDirectLink(post.data.url);
        image.alt = post.data.title;
        cardContent.appendChild(image);
      }

      cardContent.innerHTML += `<h3>${post.data.title}</h3>`;
      card.appendChild(cardContent);
      row.appendChild(card);
    }

    container.appendChild(row);
  }
}

// ...



async function fetchAndRenderNewPosts() {
  try {
    const posts = await fetchPosts();
    const validPosts = filterValidPosts(posts);

    if (validPosts.length > 0) {
      renderPosts(validPosts);
    } else {
      console.warn("No valid posts fetched. Trying again with new posts.");
      const newPosts = await fetchPosts();
      renderPosts(newPosts);
    }
  } catch (error) {
    console.error("Error fetching or rendering posts:", error);
  }
}

window.onload = function () {
  fetchAndRenderNewPosts();

  setInterval(fetchAndRenderNewPosts, 300000); // Fetch new posts every 5 minutes (adjust as needed)
};

代码摘要:这就是我到目前为止所做的一切。链接转换器将

preview.redd.it
链接转换为
i.redd.it
,以便更轻松地进行高分辨率显示。渲染部分只是将图像渲染在卡片中,每行 3 张卡片。

javascript html fetch swiper.js reddit
1个回答
0
投票

这可能是一种方法。

async function fetchPosts() {
  let data = {"kind":"Listing","data":{"children":[{"kind":"t3","data":{"subreddit":"memes","is_gallery":false,"title":"r/Memes is looking for new moderators! Interested? Fill out our application!","id":"18zq3y5","url":"https://docs.google.com/forms/d/e/1FAIpQLSfBlrL6LVOktwIdGubvbJ7REeh9vANiBTIpUecW63PHINQECg/viewform","stickied":false}},{"kind":"t3","data":{"subreddit":"memes","is_gallery":false,"title":"It was the 9/one- one of British TV","id":"19c1wez","url":"https://i.redd.it/hoqa37i19sdc1.jpeg","stickied":false}},{"kind":"t3","data":{"subreddit":"McMansionHell","is_gallery":true,"title":"Look at the upper left corner of the bathroom","media_metadata":{"5j8l66lt27b61":{"s":{"y":576,"x":768,"u":"https://preview.redd.it/5j8l66lt27b61.jpg?width=768&amp;format=pjpg&amp;auto=webp&amp;s=ba0c95d8ce7cf1d325dfac2564c2fdd55b036508"},"id":"5j8l66lt27b61"},"797pwyft27b61":{"s":{"y":413,"x":550,"u":"https://preview.redd.it/797pwyft27b61.jpg?width=550&amp;format=pjpg&amp;auto=webp&amp;s=a6dc4d0e1fac886c901e662b08662c100a5ee4e7"},"id":"797pwyft27b61"},"pj9sc1st27b61":{"s":{"y":576,"x":768,"u":"https://preview.redd.it/pj9sc1st27b61.jpg?width=768&amp;format=pjpg&amp;auto=webp&amp;s=637aed513c30179864c5a33302f44bd035771e0b"},"id":"pj9sc1st27b61"}},"gallery_data":{"items":[{"media_id":"5j8l66lt27b61","id":22269281},{"media_id":"797pwyft27b61","id":22269279},{"media_id":"pj9sc1st27b61","id":22269284}]},"id":"kwudba","url":"https://www.reddit.com/gallery/kwudba","stickied":false}},{"kind":"t3","data":{"subreddit":"McMansionHell","is_gallery":true,"title":"This is a dummy gallery","media_metadata":{"f9gczent27b61":{"s":{"y":576,"x":768,"u":"https://preview.redd.it/f9gczent27b61.jpg?width=768&amp;format=pjpg&amp;auto=webp&amp;s=1a6cc9447c9b8bac8b5a91de7c8c32247d558eaa"},"id":"f9gczent27b61"},"v2fyorvt27b61":{"s":{"y":576,"x":768,"u":"https://preview.redd.it/v2fyorvt27b61.jpg?width=768&amp;format=pjpg&amp;auto=webp&amp;s=76fb9f6db49dd5a379eebd9a0ae7d3fa86c88745"},"id":"v2fyorvt27b61"}},"gallery_data":{"items":[{"media_id":"5j8l66lt27b61","id":22269281},{"media_id":"v2fyorvt27b61","id":22269285}]},"id":"dummygal","url":"https://www.reddit.com/gallery/dummygal","stickied":false}}],"before":null}};
    
    // Exclude stickied posts
    const nonStickiedPosts = data.data.children.filter(post => !post.data.stickied);
  
    return nonStickiedPosts;
}
  
function filterValidPosts(posts) {
    return posts.filter(
      (post) =>
        post.data.title &&
        post.data.url &&
        post.data.url.startsWith("http") &&
        post.data.url.includes(".gif") &&
        post.data.url.includes("v.redd.it") &&
        post.data.self && // Exclude self-posts
        !post.data.removed // Exclude deleted posts
    );
  }
  
  
function convertToDirectLink(redditMediaLink) {
  const url = new URL(redditMediaLink);

  // Check if it's a Reddit preview link
  if (url.hostname === "preview.redd.it") {
    const [mediaId, format] = url.pathname.split("/").pop().split(".");

    if (mediaId && format) {
      // Build the direct link
      return `https://i.redd.it/${mediaId}.${format}`;
    }
  }

  // If it's not a Reddit preview link, return the original link
  return redditMediaLink;
}

// ...

// Function to render posts as cards on the webpage
async function renderPosts(posts) {
  const container = document.getElementById("postsContainer");
  container.innerHTML = "";

  for (let i = 0; i < posts.length; i += 3) {
    const row = document.createElement("div");
    row.classList.add("row");

    for (let j = i; j < i + 3 && j < posts.length; j++) {
      const post = posts[j];

      const card = document.createElement("div");
      card.classList.add("card");
      const cardContent = document.createElement("div");
      cardContent.classList.add("card-content");

            let customClass = "";
      let swiperStart = `
        <!-- Slider main container -->
        <div class="swiper">
            <!-- Additional required wrapper -->
          <div class="swiper-wrapper">
          <!-- Slides -->
      `;
      let swiperContent = "";
      let swiperEnd = `
            </div>
            <!-- If we need pagination -->
                <div class="swiper-pagination"></div>
          <!-- If we need navigation buttons -->
          <div class="swiper-button-prev"></div>
          <div class="swiper-button-next"></div>
          <!-- If we need scrollbar -->
          <div class="swiper-scrollbar"></div>
        </div>
      `;
      if (post.data.is_gallery) {
        // Handle Reddit galleries
        if (post.data.media_metadata) {
            customClass = " gallery-post";
          // Iterate over media_metadata to get direct links
          for (const mediaId in post.data.media_metadata) {
            const galleryImage = post.data.media_metadata[mediaId];
            const directLink = convertToDirectLink(galleryImage.s.u); // Use the s.u field for direct link
            swiperContent += `
                <div class="swiper-slide">
                <img alt="`+post.data.title+`" src="`+directLink+`">
              </div>
            `;
          }
          
          const divElem = document.createElement("DIV");
          divElem.innerHTML = swiperStart + swiperContent + swiperEnd;
          cardContent.appendChild(divElem);
          cardContent.className += customClass;
        }
      } else if (post.data.url) {
        // Handle posts with a single image or external links
        const image = document.createElement("img");
        image.src = await convertToDirectLink(post.data.url);
        image.alt = post.data.title;
        cardContent.appendChild(image);
      }

      cardContent.innerHTML += `<h3>${post.data.title}</h3>`;
      card.appendChild(cardContent);
      row.appendChild(card);
    }

    container.appendChild(row);
  }
  
  initSwiper();
}
  
async function fetchAndRenderNewPosts() {
  try {
    const posts = await fetchPosts();
    const validPosts = filterValidPosts(posts);

    if (validPosts.length > 0) {
      renderPosts(validPosts);
    } else {
      console.warn("No valid posts fetched. Trying again with new posts.");
      const newPosts = await fetchPosts();
      renderPosts(newPosts);
    }
  } catch (error) {
    console.error("Error fetching or rendering posts:", JSON.stringify(error));
  }
}
  
window.onload = function () {
  fetchAndRenderNewPosts();
};

function initSwiper() {
  if(document.querySelectorAll(".gallery-post").length > 0) {
    console.log("I'm in....");
    const swiper = new Swiper('.swiper', {
      // Optional parameters
      direction: 'horizontal',
      loop: true,

      // If we need pagination
      pagination: {
        el: '.swiper-pagination',
      },

      // Navigation arrows
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });
  } else {
    console.log("I'm not in :(");
  }
}
body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
}

.container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    align-items: flex-start;
    max-height: 100vh; /* Set a maximum height for the container */
    overflow-y: auto; /* Add vertical scroll if needed */
}

.row {
    display: flex;
    justify-content: space-around;
    margin-bottom: 20px; /* Adjust as needed for spacing between rows */
    min-width: 98vw;
}

.card {
    margin: 10px;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    transition: box-shadow 0.3s ease-in-out;
    overflow: hidden;
    width: calc(33% - 20px); /* Adjust as needed for spacing between cards */
    max-width: 300px; /* Limit the maximum width of each card */

}

.card:hover {
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

.card-content {
    position: relative;
}

.card img {
    width: 100%;
    height: 100%;
    object-fit: cover; /* Ensure the image covers the entire container */
}
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<div class="container" id="postsContainer"></div>


为了简单起见,对原始代码进行了更改

您会注意到我已经删除了您最初的获取逻辑。这样做是为了测试目的 - 使用大大简化的 JSON 来模拟原始 URL 的响应。

此外,由于可用代码中未使用它们,因此我冒昧地从代码中删除了

clientId
clientSecret
。当然,如果有需要,您会使用它们。

setInterval
也已被删除,因为我提供的代码仅用于测试目的 - 当然,您会将其包含在原始代码中。

CSS 也有一些细微的变化,以适应滑动器的样式(

min-width
是为您的
.row
类设置的 - 删除它,您就会明白为什么添加它)。


对原始代码进行的更改,包括 swiper.js

函数

renderPosts
已被改编为包含创建 swiper 容器的逻辑,该容器将保存从 reddit 检索到的图像。为此,我依赖于官方文档。请注意,这只是一种方法 - 如果您发现我提供的解决方案不适合您的需要,请随意尝试。

向包含画廊的卡片添加自定义类,以便我们知道是否需要初始化滑动器。

最后,在

renderPosts
函数的最后,我添加了一个新函数 -
initSwiper
。该功能很简单,改编自官方文档中的内容(无滚动条,水平滑动,如果有画廊帖子,则初始化滑动器等)。

© www.soinside.com 2019 - 2024. All rights reserved.