Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdfebd32b5 | ||
|
|
77c9c0f8bc | ||
|
|
a274cf6f12 | ||
|
|
339248be6b | ||
|
|
97241241b9 | ||
|
|
c72e7a915f | ||
|
|
90b9388386 |
7
.env
@@ -1,6 +1,9 @@
|
||||
# 全局 API 地址
|
||||
# VITE_GLOBAL_API="http://localhost:6688"
|
||||
VITE_GLOBAL_API="https://api-hot.imsyy.top"
|
||||
VITE_GLOBAL_API="https://api-hot.efefee.cn"
|
||||
|
||||
# ICP 备案号
|
||||
VITE_ICP = "豫ICP备2022018134号-1"
|
||||
VITE_ICP = "豫ICP备2022018134号-1"
|
||||
|
||||
# 全局目录
|
||||
VITE_DIR = "/"
|
||||
30
package.json
@@ -3,7 +3,7 @@
|
||||
"description": "今日热榜",
|
||||
"author": "imsyy",
|
||||
"github": "https://github.com/imsyy",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -12,24 +12,24 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||
"axios": "^1.3.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"axios": "^1.6.8",
|
||||
"lunar-calendar": "^0.1.4",
|
||||
"pinia": "^2.0.28",
|
||||
"pinia-plugin-persistedstate": "^3.1.0",
|
||||
"sass": "^1.56.1",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"sass": "^1.74.1",
|
||||
"scrollreveal": "^4.0.9",
|
||||
"terser": "^5.16.5",
|
||||
"vue": "^3.2.45",
|
||||
"vue-router": "^4.1.6",
|
||||
"terser": "^5.30.3",
|
||||
"vue": "^3.4.21",
|
||||
"vue-router": "^4.3.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"naive-ui": "^2.34.3",
|
||||
"unplugin-auto-import": "^0.12.0",
|
||||
"unplugin-vue-components": "^0.22.11",
|
||||
"vite": "^4.0.0",
|
||||
"vite-plugin-pwa": "^0.14.1"
|
||||
"@vitejs/plugin-vue": "^4.6.2",
|
||||
"naive-ui": "^2.38.1",
|
||||
"unplugin-auto-import": "^0.12.2",
|
||||
"unplugin-vue-components": "^0.22.12",
|
||||
"vite": "^4.5.3",
|
||||
"vite-plugin-pwa": "^0.14.7"
|
||||
}
|
||||
}
|
||||
|
||||
3457
pnpm-lock.yaml
generated
BIN
public/logo/acfun.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/logo/douban-group.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
BIN
public/logo/github.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
public/logo/hellogithub.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/logo/honkai.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/logo/jianshu.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
public/logo/netease_music_toplist.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/logo/ngabbs.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
BIN
public/logo/qq_music_toplist.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/logo/starrail.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
public/logo/v2ex.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
public/logo/zhihu-daily.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
@@ -4,11 +4,16 @@ import axios from "@/api/request";
|
||||
* 获取热榜分类数据
|
||||
* @param {string} type 热榜分类名称
|
||||
* @param {boolean} isNew 是否拉取最新数据
|
||||
* @param {object} params 请求参数
|
||||
* @returns
|
||||
*/
|
||||
export const getHotLists = (type, isNew) => {
|
||||
export const getHotLists = (type, isNew = false, params) => {
|
||||
return axios({
|
||||
method: "GET",
|
||||
url: `/${type}${isNew ? "/new" : "/"}`,
|
||||
url: `/${type}`,
|
||||
params: {
|
||||
cache: !isNew,
|
||||
...params,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<n-card
|
||||
hoverable
|
||||
class="hot-list"
|
||||
:header-style="{ padding: '16px' }"
|
||||
:content-style="{ padding: '0 16px' }"
|
||||
:footer-style="{ padding: '16px' }"
|
||||
:id="`hot-list-${hotData.name}`"
|
||||
class="hot-list"
|
||||
hoverable
|
||||
@click="toList"
|
||||
>
|
||||
<template #header>
|
||||
@@ -17,15 +18,15 @@
|
||||
/>
|
||||
<n-text class="name-text">{{ hotData.label }}</n-text>
|
||||
</div>
|
||||
<n-text v-if="hotListData?.subtitle" class="subtitle" :depth="2">
|
||||
{{ hotListData.subtitle }}
|
||||
<n-text v-if="hotListData?.type" class="subtitle" :depth="2">
|
||||
{{ hotListData.type }}
|
||||
</n-text>
|
||||
<n-skeleton v-else width="60px" text round />
|
||||
</n-space>
|
||||
</template>
|
||||
<n-scrollbar class="news-list" ref="scrollbarRef">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<template v-if="loadingError">
|
||||
<div v-if="loadingError" class="error">
|
||||
<n-result
|
||||
size="small"
|
||||
status="500"
|
||||
@@ -33,43 +34,51 @@
|
||||
description="生活总会遇到不如意的事情"
|
||||
style="margin-top: 40px"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="!hotListData || listLoading">
|
||||
<div class="loading">
|
||||
<n-skeleton text round :repeat="10" height="20px" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="lists" :id="hotData.name + 'Lists'">
|
||||
<div
|
||||
class="item"
|
||||
v-for="(item, index) in hotListData.data.slice(0, 15)"
|
||||
:key="item"
|
||||
<n-button
|
||||
size="small"
|
||||
secondary
|
||||
strong
|
||||
round
|
||||
@click.stop="getHotListsData(hotData.name)"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="Refresh" />
|
||||
</template>
|
||||
重试
|
||||
</n-button>
|
||||
</div>
|
||||
<div v-else-if="!hotListData || listLoading" class="loading">
|
||||
<n-skeleton text round :repeat="10" height="20px" />
|
||||
</div>
|
||||
<div v-else class="lists" :id="hotData.name + 'Lists'">
|
||||
<div
|
||||
class="item"
|
||||
v-for="(item, index) in hotListData.data.slice(0, 15)"
|
||||
:key="item"
|
||||
>
|
||||
<n-text
|
||||
class="num"
|
||||
:class="
|
||||
index === 0
|
||||
? 'one'
|
||||
: index === 1
|
||||
? 'two'
|
||||
: index === 2
|
||||
? 'three'
|
||||
: null
|
||||
"
|
||||
:depth="2"
|
||||
>{{ index + 1 }}</n-text
|
||||
>
|
||||
<n-text
|
||||
class="num"
|
||||
:class="
|
||||
index === 0
|
||||
? 'one'
|
||||
: index === 1
|
||||
? 'two'
|
||||
: index === 2
|
||||
? 'three'
|
||||
: null
|
||||
"
|
||||
:depth="2"
|
||||
>{{ index + 1 }}</n-text
|
||||
>
|
||||
<n-text
|
||||
:style="{ fontSize: store.listFontSize + 'px' }"
|
||||
class="text"
|
||||
@click.stop="jumpLink(item)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</n-text>
|
||||
</div>
|
||||
<n-text
|
||||
:style="{ fontSize: store.listFontSize + 'px' }"
|
||||
class="text"
|
||||
@click.stop="jumpLink(item)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</n-text>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</Transition>
|
||||
</n-scrollbar>
|
||||
<template #footer>
|
||||
@@ -158,11 +167,12 @@ const listLoading = ref(false);
|
||||
const loadingError = ref(false);
|
||||
|
||||
// 获取热榜数据
|
||||
const getHotListsData = async (type, isNew = false) => {
|
||||
const getHotListsData = async (name, isNew = false) => {
|
||||
try {
|
||||
// hotListData.value = null;
|
||||
loadingError.value = false;
|
||||
const result = await getHotLists(type, isNew);
|
||||
const item = store.newsArr.find((item) => item.name == name);
|
||||
const result = await getHotLists(item.name, isNew, item.params);
|
||||
// console.log(result);
|
||||
if (result.code === 200) {
|
||||
listLoading.value = false;
|
||||
@@ -222,6 +232,23 @@ const toList = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 判断列表是否显示
|
||||
const checkListShow = () => {
|
||||
const typeName = props.hotData.name;
|
||||
const listId = "hot-list-" + typeName;
|
||||
const listDom = document.getElementById(listId);
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
console.log(`👀 ${typeName} 可见,开始加载`);
|
||||
getHotListsData(props.hotData.name);
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(listDom);
|
||||
};
|
||||
|
||||
// 实时改变更新时间
|
||||
watch(
|
||||
() => store.timeData,
|
||||
@@ -233,7 +260,7 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (props.hotData.name) getHotListsData(props.hotData.name);
|
||||
checkListShow();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -242,17 +269,6 @@ onMounted(() => {
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -294,6 +310,15 @@ onMounted(() => {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.n-button {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -82,13 +82,13 @@ export const mainStore = defineStore("mainData", {
|
||||
},
|
||||
{
|
||||
label: "腾讯新闻",
|
||||
name: "newsqq",
|
||||
name: "qq-news",
|
||||
order: 12,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "豆瓣",
|
||||
name: "douban_new",
|
||||
label: "豆瓣电影",
|
||||
name: "douban-movie",
|
||||
order: 13,
|
||||
show: true,
|
||||
},
|
||||
@@ -98,21 +98,21 @@ export const mainStore = defineStore("mainData", {
|
||||
order: 14,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "崩坏:星穹铁道",
|
||||
name: "starrail",
|
||||
order: 16,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "LOL",
|
||||
name: "lol",
|
||||
order: 15,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "快手",
|
||||
name: "kuaishou",
|
||||
order: 16,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "网易新闻",
|
||||
name: "netease",
|
||||
name: "netease-news",
|
||||
order: 17,
|
||||
show: true,
|
||||
},
|
||||
@@ -122,6 +122,36 @@ export const mainStore = defineStore("mainData", {
|
||||
order: 18,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "豆瓣讨论小组",
|
||||
name: "douban-group",
|
||||
order: 19,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "NGA",
|
||||
name: "ngabbs",
|
||||
order: 20,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "HelloGitHub",
|
||||
name: "hellogithub",
|
||||
order: 21,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "简书",
|
||||
name: "jianshu",
|
||||
order: 22,
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: "知乎日报",
|
||||
name: "zhihu-daily",
|
||||
order: 23,
|
||||
show: true,
|
||||
},
|
||||
],
|
||||
newsArr: [],
|
||||
// 链接跳转方式
|
||||
@@ -131,7 +161,7 @@ export const mainStore = defineStore("mainData", {
|
||||
// 时间数据
|
||||
timeData: null,
|
||||
// 字体大小
|
||||
listFontSize: 14,
|
||||
listFontSize: 16,
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// 全局样式
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -11,4 +10,15 @@ html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 动画
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -141,9 +141,10 @@ const pageNumber = ref(
|
||||
const listData = ref(null);
|
||||
|
||||
// 获取热榜数据
|
||||
const getHotListsData = (type, isNew = false) => {
|
||||
const getHotListsData = async (name, isNew = false) => {
|
||||
listData.value = null;
|
||||
getHotLists(type, isNew).then((res) => {
|
||||
const item = store.newsArr.find((item) => item.name == name)
|
||||
getHotLists(item.name, isNew, item.params).then((res) => {
|
||||
console.log(res);
|
||||
if (res.code === 200) {
|
||||
listData.value = res;
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<n-card class="set-item">
|
||||
<div class="top" style="flex-direction: column; align-items: flex-start">
|
||||
<div class="name">
|
||||
<n-text class="text">歌词文本大小</n-text>
|
||||
<n-text class="text">列表文本大小</n-text>
|
||||
<n-card
|
||||
class="tip"
|
||||
:style="{
|
||||
@@ -74,8 +74,8 @@
|
||||
:min="14"
|
||||
:step="0.01"
|
||||
:marks="{
|
||||
14: '默认',
|
||||
16: '大一点',
|
||||
14: '小一点',
|
||||
16: '默认',
|
||||
20: '最大',
|
||||
}"
|
||||
/>
|
||||
|
||||
148
vite.config.js
@@ -1,82 +1,88 @@
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
imports: [
|
||||
"vue",
|
||||
{
|
||||
"naive-ui": [
|
||||
"useDialog",
|
||||
"useMessage",
|
||||
"useNotification",
|
||||
"useLoadingBar",
|
||||
export default defineConfig(({ mode }) => {
|
||||
return {
|
||||
base: loadEnv(mode, process.cwd())["VITE_DIR"],
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
imports: [
|
||||
"vue",
|
||||
{
|
||||
"naive-ui": [
|
||||
"useDialog",
|
||||
"useMessage",
|
||||
"useNotification",
|
||||
"useLoadingBar",
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()],
|
||||
}),
|
||||
// PWA
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /(.*?)\.(woff2|woff|ttf)/,
|
||||
handler: "CacheFirst",
|
||||
options: {
|
||||
cacheName: "file-cache",
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern:
|
||||
/(.*?)\.(webp|png|jpe?g|svg|gif|bmp|psd|tiff|tga|eps)/,
|
||||
handler: "CacheFirst",
|
||||
options: {
|
||||
cacheName: "image-cache",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()],
|
||||
}),
|
||||
// PWA
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /(.*?)\.(woff2|woff|ttf)/,
|
||||
handler: "CacheFirst",
|
||||
options: {
|
||||
cacheName: "file-cache",
|
||||
manifest: {
|
||||
name: "今日热榜",
|
||||
short_name: "DailyHot",
|
||||
description: "汇聚全网热点,热门尽览无余",
|
||||
display: "standalone",
|
||||
start_url: "/",
|
||||
theme_color: "#fff",
|
||||
background_color: "#efefef",
|
||||
icons: [
|
||||
{
|
||||
src: "/ico/favicon.png",
|
||||
sizes: "200x200",
|
||||
type: "image/png",
|
||||
},
|
||||
},
|
||||
{
|
||||
urlPattern: /(.*?)\.(webp|png|jpe?g|svg|gif|bmp|psd|tiff|tga|eps)/,
|
||||
handler: "CacheFirst",
|
||||
options: {
|
||||
cacheName: "image-cache",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
manifest: {
|
||||
name: "今日热榜",
|
||||
short_name: "DailyHot",
|
||||
description: "汇聚全网热点,热门尽览无余",
|
||||
display: "standalone",
|
||||
start_url: "/",
|
||||
theme_color: "#fff",
|
||||
background_color: "#efefef",
|
||||
icons: [
|
||||
{
|
||||
src: "/ico/favicon.png",
|
||||
sizes: "200x200",
|
||||
type: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
minify: "terser",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
pure_funcs: ["console.log"],
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 6699,
|
||||
},
|
||||
build: {
|
||||
minify: "terser",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
pure_funcs: ["console.log"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||