CSSの練習で、yahooニュースRSSを使って、gigazineみたいな表示をしてみた!
https://messiahworks.com/news/
他サーバにあるrssデータを、jsから直接取得できないWeb仕様なので、自鯖のphp経由で取得する。
ついでに複数RSSを1つに統合しておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
<?php header("Access-Control-Allow-Origin: *"); // すべてのオリジンからのアクセスを許可 header("Content-Type: application/xml"); // コンテンツタイプを適切に設定 // RSSのURLリスト $feedUrls = [ "https://news.yahoo.co.jp/rss/categories/domestic.xml", "https://news.yahoo.co.jp/rss/categories/world.xml", "https://news.yahoo.co.jp/rss/categories/business.xml", "https://news.yahoo.co.jp/rss/categories/entertainment.xml", "https://news.yahoo.co.jp/rss/categories/sports.xml", "https://news.yahoo.co.jp/rss/categories/it.xml", "https://news.yahoo.co.jp/rss/categories/science.xml", "https://news.yahoo.co.jp/rss/categories/life.xml", "https://news.yahoo.co.jp/rss/categories/local.xml" ]; // 個々のRSSから、統合した新RSSを生成する $dom = new DOMDocument('1.0', 'UTF-8'); $root = $dom->createElement('rss'); $root->setAttribute('version', '2.0'); $dom->appendChild($root); $channel = $dom->createElement('channel'); $root->appendChild($channel); $allItems = []; // 個々のRSSの数だけループ foreach ($feedUrls as $feedUrl) { $rss = simplexml_load_file($feedUrl); $source = basename($feedUrl, ".xml"); // XMLファイル名を取得 $count = 0; // カテゴリーごとのアイテムカウンター foreach ($rss->channel->item as $item) { // if ($count++ >= 5) break; // 各カテゴリーから最新の5件のみを取得 // ニュースitemに、カテゴリー項目を追加 $categoryElement = $dom->createElement('category', $source); $itemElement = $dom->importNode(dom_import_simplexml($item), true); $itemElement->appendChild($categoryElement); // 公開日をitemに追加 $pubDate = strtotime($item->pubDate); $allItems[] = ['date' => $pubDate, 'element' => $itemElement]; } } // ニュースを公開日の新しい順に並び替え usort($allItems, function ($item1, $item2) { return $item2['date'] - $item1['date']; }); // channel直下に、ニュースitemを追加して完成。 foreach ($allItems as $item) { $channel->appendChild($item['element']); } echo $dom->saveXML(); ?> |
自鯖phpからrssをjsで取得して、DOM生成。
CSSで見た目をgigazineっぽくする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>ニュースフィード</title> <style> body { /* 全体のCSS設定 */ font-family: Arial, sans-serif; /* フォント優先度順に指定 */ margin: 0; padding: 0; background: #f4f4f4; /* 背景色を設定 */ } /* ニュースの容れ物 */ .news-container { display: grid; /* グリットデザイン。カラム幅300pxで、ウィンドウの横幅があるだけ横積みしていく */ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 0px; /* グリッド間の隙間を0に設定 */ padding: 0px; /* コンテナの内側の余白を0に設定 */ } /* 個々のニュース */ .news-item { background: white; border: 1px solid #ddd; padding: 5px; position: relative; /* 前の要素の次に来る。absoluteだと全部最初に重なってしまう! */ } .news-title { position: absolute; /* 下から5pxの位置に配置 */ bottom: 5px; left: 5px; /* 左から5pxの位置 */ right: 5px; /* 右から5pxの位置 */ background-color: rgba(0, 0, 0, 0.7); /* 背景色を半透明の黒に設定 */ color: white; /* テキストの色を白に設定 */ } .news-image { width: 100%; /* 幅を100%に設定。親のnews-itemの幅一杯になる */ height: 200px; /* 高さを200pxに設定 */ object-fit: cover; /* 画像のサイズが枠に合わせて調整されるように設定 */ } </style> </head> <body> <h1>https://news.yahoo.co.jp/rssから取得</h1> <div class="news-container" id="newsFeed"></div> <script> // DOMが読み込まれたら実行。 document.addEventListener('DOMContentLoaded', function () { const endpoint = 'rss.php'; // PHPスクリプトのエンドポイント fetch(endpoint) // 指定されたURLからデータを取得 .then(response => response.text()) // テキスト型として取得 // さらにXML型としてDOM型としてdata取得 .then(str => new window.DOMParser().parseFromString(str, "text/xml")) .then(data => { const items = data.querySelectorAll("item"); // 全ニュースを取得 const newsFeed = document.getElementById("newsFeed"); // HTMLの出力先 // 個々のニュースの数だけループ items.forEach(item => { const title = item.querySelector('title').textContent; // タイトルを取得 const link = item.querySelector('link').textContent; // リンクを取得 const imageUrl = item.querySelector('image').textContent; // 画像URLを取得 const newsItem = document.createElement('div'); // ニュース項目用のdivを作成 newsItem.className = 'news-item'; const linkElem = document.createElement('a'); // リンク要素を作成 linkElem.href = link; // リンク先を設定 linkElem.target = '_blank'; // 新しいタブで開くように設定 const img = document.createElement('img'); // 画像要素を作成 img.src = imageUrl; // 画像のURLを設定 img.alt = title; // 画像の代替テキストとしてタイトルを設定 img.className = 'news-image'; const titleDiv = document.createElement('div'); // タイトル用のdivを作成 titleDiv.className = 'news-title'; titleDiv.textContent = title; // タイトルのテキストを設定 linkElem.appendChild(img); // 画像をリンク要素に追加 linkElem.appendChild(titleDiv); // タイトルをリンク要素に追加 newsItem.appendChild(linkElem); // リンク要素をニュース項目に追加 newsFeed.appendChild(newsItem); // ニュース項目をニュースコンテナに追加 }); }) .catch(err => { console.error("Error fetching and parsing data", err); // エラーログを出力 alert('データの読み込みに失敗しました。'); // エラーメッセージを表示 }); }); </script> </body> </html> |