284 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						||
<html lang="cn">
 | 
						||
 | 
						||
<head>
 | 
						||
    <meta charset="UTF-8">
 | 
						||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
						||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
						||
    <title>B站热搜</title>
 | 
						||
    <link rel="stylesheet" href="./assets/css/main.css">
 | 
						||
    <style>
 | 
						||
        #list td {
 | 
						||
            font-size: 14px;
 | 
						||
        }
 | 
						||
    </style>
 | 
						||
</head>
 | 
						||
 | 
						||
<body>
 | 
						||
    <div style="text-align: center;">
 | 
						||
        <h1>B站热搜榜</h1>
 | 
						||
        <hr>
 | 
						||
        <div>
 | 
						||
            显示字段:
 | 
						||
            <label for="show_keyword">
 | 
						||
                <input type="checkbox" class="filter_checkbox" name="show_keyword" id="show_keyword" checked="true"
 | 
						||
                    detailed-checked="true">关键词
 | 
						||
            </label>
 | 
						||
            <label for="show_word_type">
 | 
						||
                <input type="checkbox" class="filter_checkbox" name="show_word_type" id="show_word_type"
 | 
						||
                    detailed-checked="true">word_type
 | 
						||
            </label>
 | 
						||
            <label for="show_hot_id">
 | 
						||
                <input type="checkbox" class="filter_checkbox" name="show_hot_id" id="show_hot_id"
 | 
						||
                    detailed-checked="true">hot_id
 | 
						||
            </label>
 | 
						||
            <br>
 | 
						||
            <button id="btn_show_all">全选</button>
 | 
						||
            <button id="btn_show_none">全不选</button>
 | 
						||
            |
 | 
						||
            <button id="btn_show_default">普通</button>
 | 
						||
            <button id="btn_show_detailed">详细</button>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
    <p id="latestUpdateTime" style="font-size: 12px; display: inline-block; vertical-align: middle;"></p>
 | 
						||
    <nobr>
 | 
						||
        <button id="btn_refresh">重新拉取</button>
 | 
						||
    </nobr>
 | 
						||
    <nobr>
 | 
						||
        <label for="auto_refresh">
 | 
						||
            <input type="checkbox" name="auto_refresh" id="auto_refresh">自动拉取<span id="auto_refresh_countdown"></span>
 | 
						||
        </label>
 | 
						||
    </nobr>
 | 
						||
    <nobr>
 | 
						||
        <span id="update-finish-info" style="color: green; font-weight: bold; display: none;">拉取成功,数据已更新</span>
 | 
						||
    </nobr>
 | 
						||
    <table id="list"></table>
 | 
						||
    <script>
 | 
						||
        let iconMapper = {
 | 
						||
            "http://i0.hdslb.com/bfs/feed-admin/e9e7a2d8497d4063421b685e72680bf1cfb99a0d.png": ["热", "#FF895C"],
 | 
						||
            "http://i0.hdslb.com/bfs/feed-admin/4d579fb61f9655316582db193118bba3a721eec0.png": ["新", "#F87399"],
 | 
						||
        }
 | 
						||
        function getIconText(iconUrl) {
 | 
						||
            if (!iconUrl) {
 | 
						||
                return '';
 | 
						||
            }
 | 
						||
            else if (Object.keys(iconMapper).indexOf(iconUrl) != -1) {
 | 
						||
                return iconMapper[iconUrl];
 | 
						||
            } else {
 | 
						||
                console.log("未知 iconUrl:", iconUrl);
 | 
						||
                return [" ? ", 'grey'];
 | 
						||
            }
 | 
						||
        }
 | 
						||
    </script>
 | 
						||
    <script>
 | 
						||
        /**
 | 
						||
         * 全局变量
 | 
						||
         */
 | 
						||
        // 拉取下来的数据
 | 
						||
        let hotBandData;
 | 
						||
 | 
						||
        // 按钮
 | 
						||
        const btnShowAll = document.getElementById('btn_show_all');
 | 
						||
        const btnShowNone = document.getElementById('btn_show_none');
 | 
						||
        const btnShowDefault = document.getElementById('btn_show_default');
 | 
						||
        const btnShowDetailed = document.getElementById('btn_show_detailed');
 | 
						||
 | 
						||
        const btnRefresh = document.getElementById('btn_refresh');
 | 
						||
 | 
						||
        // 复选框
 | 
						||
        const filterCheckbox = document.getElementsByClassName("filter_checkbox");
 | 
						||
 | 
						||
        const showKeyword = document.getElementById("show_keyword");
 | 
						||
        const showWordType = document.getElementById("show_word_type");
 | 
						||
        const showHotId = document.getElementById("show_hot_id");
 | 
						||
 | 
						||
        const autoRefresh = document.getElementById("auto_refresh");
 | 
						||
 | 
						||
 | 
						||
        // 绑定按钮点击事件
 | 
						||
        btnShowAll.addEventListener('click', function () {
 | 
						||
            for (let i = 0; i < filterCheckbox.length; i++) {
 | 
						||
                const element = filterCheckbox[i];
 | 
						||
                element.checked = true;
 | 
						||
            }
 | 
						||
            render();
 | 
						||
        });
 | 
						||
        btnShowNone.addEventListener('click', function () {
 | 
						||
            for (let i = 0; i < filterCheckbox.length; i++) {
 | 
						||
                const element = filterCheckbox[i];
 | 
						||
                element.checked = false;
 | 
						||
            }
 | 
						||
            render();
 | 
						||
        });
 | 
						||
        btnShowDefault.addEventListener('click', function () {
 | 
						||
            for (let i = 0; i < filterCheckbox.length; i++) {
 | 
						||
                const element = filterCheckbox[i];
 | 
						||
                element.checked = element.getAttribute('checked') === 'true';
 | 
						||
            }
 | 
						||
            render();
 | 
						||
        });
 | 
						||
        btnShowDetailed.addEventListener('click', function () {
 | 
						||
            for (let i = 0; i < filterCheckbox.length; i++) {
 | 
						||
                const element = filterCheckbox[i];
 | 
						||
                element.checked = element.getAttribute('detailed-checked') === 'true';
 | 
						||
            }
 | 
						||
            render();
 | 
						||
        });
 | 
						||
 | 
						||
        btnRefresh.onclick = function () {
 | 
						||
            getData();
 | 
						||
            document.getElementById("update-finish-info").style.display = "";
 | 
						||
            // btnRefresh.style.display = "none";
 | 
						||
            btnRefresh.style.visibility = "hidden";
 | 
						||
            setTimeout(function () {
 | 
						||
                document.getElementById("update-finish-info").style.display = "none";
 | 
						||
                // btnRefresh.style.display = "";
 | 
						||
                btnRefresh.style.visibility = "";
 | 
						||
            }, 1000);
 | 
						||
        };
 | 
						||
 | 
						||
        // 绑定复选框改变事件
 | 
						||
        for (let i = 0; i < filterCheckbox.length; i++) {
 | 
						||
            // console.log(filterCheckbox[i]);
 | 
						||
            filterCheckbox[i].onchange = function () {
 | 
						||
                render();
 | 
						||
            };
 | 
						||
        }
 | 
						||
 | 
						||
        let autoRefreshIntreval = null;
 | 
						||
        const autoRefreshCountDownElement = document.getElementById('auto_refresh_countdown');
 | 
						||
        const countDown = 20; // 自动拉取间隔时间,单位:秒
 | 
						||
        let autoRefreshCountDown = countDown;
 | 
						||
        autoRefresh.onchange = function () {
 | 
						||
            if (autoRefresh.checked) {
 | 
						||
                btnRefresh.style.display = "none";
 | 
						||
                btnRefresh.click();
 | 
						||
                autoRefreshIntreval = setInterval(function () {
 | 
						||
                    if ((--autoRefreshCountDown) > 0) {
 | 
						||
                        autoRefreshCountDownElement.innerHTML = `(${autoRefreshCountDown}s)`;
 | 
						||
                    } else {
 | 
						||
                        autoRefreshCountDown = countDown;
 | 
						||
                        btnRefresh.click();
 | 
						||
                        autoRefreshCountDownElement.innerHTML = ``;
 | 
						||
                    }
 | 
						||
                }, 1000);
 | 
						||
            } else {
 | 
						||
                clearInterval(autoRefreshIntreval);
 | 
						||
                btnRefresh.style.display = "";
 | 
						||
                autoRefreshCountDownElement.innerHTML = ``;
 | 
						||
            }
 | 
						||
        };
 | 
						||
 | 
						||
        // 根据屏幕判断要显示哪些字段
 | 
						||
        // 此时还未拉取数据,所以进入 render 函数会直接返回,不会多次渲染
 | 
						||
        let initWidth = document.body.offsetWidth;
 | 
						||
        // console.log(initWidth);
 | 
						||
        if (initWidth < 400) {
 | 
						||
            btnShowNone.click();
 | 
						||
            btnShowNone.innerHTML += "(默认)";
 | 
						||
        } else if (initWidth < 780) {
 | 
						||
            btnShowDefault.click();
 | 
						||
            btnShowDefault.innerHTML += "(默认)";
 | 
						||
        } else {
 | 
						||
            btnShowDetailed.click();
 | 
						||
            btnShowDetailed.innerHTML += "(默认)";
 | 
						||
        }
 | 
						||
 | 
						||
        // 网页加载后加载榜单
 | 
						||
        getData();
 | 
						||
 | 
						||
        // 定时刷新
 | 
						||
        // setInterval(getData, 10 * 1000);
 | 
						||
 | 
						||
        function getData() {
 | 
						||
            var xhr = new XMLHttpRequest();
 | 
						||
            xhr.open("GET", "../data/bilibili-hotband/latest.json?t=" + Date.now(), true);
 | 
						||
            xhr.send();
 | 
						||
            xhr.onreadystatechange = function () {
 | 
						||
                if (xhr.readyState !== 4) return;
 | 
						||
 | 
						||
                if (xhr.status == 200) {
 | 
						||
                    try {
 | 
						||
                        hotBandData = JSON.parse(xhr.responseText);
 | 
						||
                        if (!hotBandData.data || typeof hotBandData.data !== 'object')
 | 
						||
                            throw new Error("data is undefined or not an object");
 | 
						||
                    } catch (e) {
 | 
						||
                        console.error("[error]", "\n", e, "\n", "\n", "[xhr.responseText]", "\n", xhr.responseText);
 | 
						||
                        alert("latest.json 文件解析失败,请检查文件");
 | 
						||
                        return;
 | 
						||
                    }
 | 
						||
                    console.log(hotBandData);
 | 
						||
 | 
						||
                    // 更新时间
 | 
						||
                    document.getElementById("latestUpdateTime").innerHTML =
 | 
						||
                        "数据拉取时间:" + new Date().toLocaleString() + "<br/>" +
 | 
						||
                        "热榜更新时间:" + new Date(hotBandData.update_time).toLocaleString();
 | 
						||
 | 
						||
                    // 渲染榜单
 | 
						||
                    render();
 | 
						||
                } else if (xhr.status == 404) {
 | 
						||
                    alert("data 目录下未找到 latest.json 文件,可能的原因:\n您还没有运行脚本拉取数据,请先运行脚本,然后刷新页面");
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        function render() {
 | 
						||
            if (!hotBandData) return;
 | 
						||
 | 
						||
            /**
 | 
						||
             * 渲染热搜列表
 | 
						||
             */
 | 
						||
            let hotBandList = hotBandData.data;
 | 
						||
            var str = [];
 | 
						||
            // 渲染表格
 | 
						||
            str.push(`<thead>
 | 
						||
                <tr class="thead" style="top: 0; background-color: white; position: sticky;">
 | 
						||
                    <td>编号</td>
 | 
						||
                    <td>热搜</td>
 | 
						||
                    ${showKeyword.checked ? "<td>关键词</td>" : ""}
 | 
						||
                    ${showWordType.checked ? "<td>word_type</td>" : ""}
 | 
						||
                    ${showHotId.checked ? "<td>hot_id</td>" : ""}
 | 
						||
                </tr>
 | 
						||
            </thead>`);
 | 
						||
            str.push(`<tbody>`);
 | 
						||
 | 
						||
            for (var i = 0; i < hotBandList.length; i++) {
 | 
						||
                const hotBand = hotBandList[i];
 | 
						||
                str.push(`<tr>
 | 
						||
                    <!-- 编号 -->
 | 
						||
                    <td>${hotBand.position}</td>
 | 
						||
 | 
						||
                    <!-- 热搜 -->
 | 
						||
                    <td style="text-align: left;">
 | 
						||
                        <nobr>
 | 
						||
                            <div style="min-width: 20px; display: inline-block;">
 | 
						||
                                <span class="hotband-label" style="background-color: ${getIconText(hotBand.icon)[1]}; ${hotBand.icon ? "" : "display: none;"}">${getIconText(hotBand.icon)[0]}</span>
 | 
						||
                            </div>
 | 
						||
                            <span>${hotBand.show_name}</span>
 | 
						||
                            ${hotBand.show_live_icon ? `<span class="hotband-label" style="background-color: #f69; padding: 1px 5px;">直播中</span>` : ""}
 | 
						||
                        </nobr>
 | 
						||
                    </td>
 | 
						||
 | 
						||
                    ${showKeyword.checked ? `
 | 
						||
                    <!-- 关键词 -->
 | 
						||
                    <td>${hotBand.keyword}</td>
 | 
						||
                    ` : ""}
 | 
						||
 | 
						||
                    ${showWordType.checked ? `
 | 
						||
                    <!-- word_type -->
 | 
						||
                    <td>${hotBand.word_type}</td>
 | 
						||
                    ` : ""}
 | 
						||
 | 
						||
                    ${showHotId.checked ? `
 | 
						||
                    <!-- hot_id -->
 | 
						||
                    <td>${hotBand.hot_id}</td>
 | 
						||
                    ` : ""}
 | 
						||
                </tr >`);
 | 
						||
            }
 | 
						||
            str.push(`</tbody>`);
 | 
						||
            document.getElementById('list').innerHTML = str.join('');
 | 
						||
        }
 | 
						||
    </script>
 | 
						||
</body>
 | 
						||
 | 
						||
</html> |