Add infinite scroll

This commit is contained in:
the1812 2020-06-13 14:54:15 +08:00
parent 3d6961a1ee
commit a1dd164f21
10 changed files with 494 additions and 347 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -33,10 +33,10 @@
"compact-layout.min.js": "B20609A7CBBDB1845FA0156FB5BE6B1E1A1B8B069EA85F65D16241DD2C12D738", "compact-layout.min.js": "B20609A7CBBDB1845FA0156FB5BE6B1E1A1B8B069EA85F65D16241DD2C12D738",
"custom-control-background.min.css": "1981FD2BF3B17ECF33F98D5DEDAF0D32ACBE9532A51FDB70822286991AB98EF3", "custom-control-background.min.css": "1981FD2BF3B17ECF33F98D5DEDAF0D32ACBE9532A51FDB70822286991AB98EF3",
"custom-control-background.min.js": "B9F366B251D1572ACE801FF6ECF15D4D1AAB3EA5A5B04B961B6F4310E2AB1A84", "custom-control-background.min.js": "B9F366B251D1572ACE801FF6ECF15D4D1AAB3EA5A5B04B961B6F4310E2AB1A84",
"custom-navbar.min.css": "9B21F32F0BD66613AED9E52F666BF5088BB1A7B1CFEBBDABAD0B7B74C64878D7", "custom-navbar.min.css": "813761561B78BBBD7AF662FC661FBF948ABEE69676A9454AC540444B53638971",
"custom-navbar.min.html": "183B1F7182633044CCB20A3710524492118308CF55915AA9AA9F36850500F457", "custom-navbar.min.html": "183B1F7182633044CCB20A3710524492118308CF55915AA9AA9F36850500F457",
"custom-navbar.min.js": "0D53FECB162F73C77B305CB2324ECA956D91F43BBDF3AA9B1B01D6727EDF2D99", "custom-navbar.min.js": "0D53FECB162F73C77B305CB2324ECA956D91F43BBDF3AA9B1B01D6727EDF2D99",
"custom-navbar-activities.min.js": "802226FE2C24D56379A6EAD13D3697A4D5A46109D0C63EDACAE8E667ED267EA1", "custom-navbar-activities.min.js": "D18DDC1B01B5F91E147539955A6400092564891114CF5C38771D5F71F67C454B",
"custom-navbar-blank.min.js": "DC2B75D5760EECD3A257785FDFBB7E5DEBF61CD9083C68DD5BCE468B093F54F3", "custom-navbar-blank.min.js": "DC2B75D5760EECD3A257785FDFBB7E5DEBF61CD9083C68DD5BCE468B093F54F3",
"custom-navbar-category.min.js": "2D1A6189540E5DE22A9741AFCFDA2FED50EA960B129547B1E756F2D5E53C0C67", "custom-navbar-category.min.js": "2D1A6189540E5DE22A9741AFCFDA2FED50EA960B129547B1E756F2D5E53C0C67",
"custom-navbar-component.min.js": "1E19E02F7BFCC3397C14907EC8390F03522E128B528CB82412F202BAF57C28E9", "custom-navbar-component.min.js": "1E19E02F7BFCC3397C14907EC8390F03522E128B528CB82412F202BAF57C28E9",
@ -58,12 +58,11 @@
"danmaku-send-bar.min.css": "52149D46CF3A15CF6EB186CB49F298DE18B0723E52D8693228F66099847EDCCB", "danmaku-send-bar.min.css": "52149D46CF3A15CF6EB186CB49F298DE18B0723E52D8693228F66099847EDCCB",
"danmaku-send-bar.min.js": "7108E72F00C169F26E20409F4AA79F05553310375BABC392EB7E2166224B800A", "danmaku-send-bar.min.js": "7108E72F00C169F26E20409F4AA79F05553310375BABC392EB7E2166224B800A",
"dark.min.css": "BCC164174A579D1D2B4CC4F993611B65B283F71D4F0679299FF8C3D4A8FDDE7F", "dark.min.css": "BCC164174A579D1D2B4CC4F993611B65B283F71D4F0679299FF8C3D4A8FDDE7F",
"dark.user.css": "8068EB2B2AC92ADAD8E0E904C4F9CF07D3394EA2CD196CEDC674B28D19CF1556", "dark.user.css": "1946312C75FD486219173E12B95847FCA382E66AF9BA89268B45B0B8FC1EE2BB",
"dark-color-scheme.min.js": "6D353AC738180317ACF9D2E046BFFBA0ACC0FA7A8D22B8E16C51127CDE4FE96B", "dark-color-scheme.min.js": "6D353AC738180317ACF9D2E046BFFBA0ACC0FA7A8D22B8E16C51127CDE4FE96B",
"dark-important.min.css": "5369385A2C16188FB11E71C4C5B91275646F22F0F09E518E37813CC4FA23A072", "dark-important.min.css": "5369385A2C16188FB11E71C4C5B91275646F22F0F09E518E37813CC4FA23A072",
"dark-navbar.min.css": "7FAD547E326B768904B3739C978DF86FFDDD5E5064FB8F490710D197CCC3018B", "dark-navbar.min.css": "7FAD547E326B768904B3739C978DF86FFDDD5E5064FB8F490710D197CCC3018B",
"dark-schedule.min.js": "853C446547603F4F0425F19F09F73335C9EC451A790C1C07E5E5B88A09E9B453", "dark-schedule.min.js": "853C446547603F4F0425F19F09F73335C9EC451A790C1C07E5E5B88A09E9B453",
"dark-slice-9.min.css": "7B717361A3252C90B7BA6B02DEA097B328F72DC3781133D94FE56A2B01DB2B2A",
"dark-styles.min.js": "74E6D655F88E50A27D60F189554F6656CCD2A6EA2686FD9946CA9A89EABF7719", "dark-styles.min.js": "74E6D655F88E50A27D60F189554F6656CCD2A6EA2686FD9946CA9A89EABF7719",
"debounce.min.js": "54D33E1273C1F3FE19550BF1844339C3D54D6B01DF8A39C3162D95B93B079CFA", "debounce.min.js": "54D33E1273C1F3FE19550BF1844339C3D54D6B01DF8A39C3162D95B93B079CFA",
"default-danmaku-settings.min.css": "D9942B184FEDA7B08CFA0C34920E97D7A83B81762DCBF757642EBB60F95FF25D", "default-danmaku-settings.min.css": "D9942B184FEDA7B08CFA0C34920E97D7A83B81762DCBF757642EBB60F95FF25D",

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -34,32 +34,32 @@
.activity-tab { .activity-tab {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
} .tab-name {
.activity-tab.selected { line-height: normal;
opacity: 1; opacity: 0.5;
transform: scale(1.2); }
} &.selected {
.activity-tab .tab-name { opacity: 1;
line-height: normal; transform: scale(1.2);
opacity: 0.5; .tab-name {
} opacity: 1;
.activity-tab.selected .tab-name { font-weight: bold;
opacity: 1; }
font-weight: bold; }
} &[data-count]::before {
.activity-tab[data-count]::before { content: attr(data-count);
content: attr(data-count); position: absolute;
position: absolute; top: 0;
top: 0; left: 50%;
left: 50%; transform: translateX(-50%) translateY(-100%);
transform: translateX(-50%) translateY(-100%); font-size: 10px;
font-size: 10px; font-weight: normal;
font-weight: normal; line-height: 1;
line-height: 1; background-color: #8884;
background-color: #8884; padding: 2px 4px;
padding: 2px 4px; border-radius: 10px;
border-radius: 10px; white-space: nowrap;
white-space: nowrap; }
} }
.activity-tab::after, .activity-tab::after,
.subscriptions .tab::after { .subscriptions .tab::after {
@ -78,6 +78,10 @@
.subscriptions .tab.selected::after { .subscriptions .tab.selected::after {
transform: scaleX(1); transform: scaleX(1);
} }
.activity-popup-content::-webkit-scrollbar,
.subscriptions .content::-webkit-scrollbar {
width: 0px !important;
}
.activity-popup-content { .activity-popup-content {
overflow: auto; overflow: auto;
overscroll-behavior: contain; overscroll-behavior: contain;
@ -88,43 +92,39 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
scrollbar-width: none !important; scrollbar-width: none !important;
} .view-more {
.activity-popup-content::-webkit-scrollbar, display: flex;
.subscriptions .content::-webkit-scrollbar { align-items: center;
width: 0px !important; flex-shrink: 0;
} position: -webkit-sticky;
.activity-popup-content .view-more { position: sticky;
display: flex; bottom: 0;
align-items: center; left: 0;
flex-shrink: 0; justify-content: center;
position: -webkit-sticky; padding: 6px 12px;
position: sticky; background-color: #fffe;
bottom: 0; transform: translateY(-6px);
left: 0; box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px;
justify-content: center; cursor: pointer;
padding: 6px 12px; height: 28px;
background-color: #fffe; border-radius: 14px;
transform: translateY(-6px); box-sizing: border-box;
box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px; z-index: 2;
cursor: pointer; &:hover {
height: 28px; background-color: #fff;
border-radius: 14px; }
box-sizing: border-box; .mdi {
z-index: 2; line-height: 1;
} margin-left: 8px;
.activity-popup-content .view-more:hover { font-size: 12pt;
background-color: #fff; }
} body.dark & {
&.dark .activity-popup-content .view-more { background-color: #333e;
background-color: #333e; &:hover {
} background-color: #333;
&.dark .activity-popup-content .view-more:hover { }
background-color: #333; }
} }
.activity-popup-content .view-more .mdi {
line-height: 1;
margin-left: 8px;
font-size: 12pt;
} }
.activity-popup-content .loading, .activity-popup-content .loading,
.bangumi-subscriptions .loading, .bangumi-subscriptions .loading,
@ -140,27 +140,125 @@
line-height: 1; line-height: 1;
margin-right: 6px; margin-right: 6px;
} }
.video-activity { .video-activity {
padding: 0 12px; padding: 0 12px;
display: flex; // display: flex;
justify-content: space-between; // justify-content: space-between;
align-self: stretch; align-self: stretch;
} display: grid;
.video-activity.center { grid-template:
height: 100%; "left right" auto
flex-direction: column; "trigger trigger" auto / 1fr 1fr;
justify-content: center; &.center {
align-items: center; display: flex;
} height: 100%;
.video-activity-card { flex-direction: column;
--card-width: 172px; justify-content: center;
width: var(--card-width); align-items: center;
display: flex; }
flex-direction: column; &-column {
box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px; &.left {
margin-bottom: 12px; grid-area: left;
break-inside: avoid; justify-self: start;
flex-shrink: 0; }
&.right {
grid-area: right;
justify-self: end;
}
}
&-card {
--card-width: 172px;
width: var(--card-width);
display: flex;
flex-direction: column;
box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px;
margin-bottom: 12px;
break-inside: avoid;
flex-shrink: 0;
.cover {
width: var(--card-width);
background-color: #8884;
height: calc(var(--card-width) / 16 * 10);
object-fit: cover;
display: block;
min-height: 100px;
}
.title {
font-size: 10pt;
font-weight: bold;
margin: 8px 8px 2px 8px;
color: inherit;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.5;
max-height: 3em;
word-break: break-all;
}
.up {
display: flex;
justify-content: space-between;
align-items: center;
margin: 6px 8px;
border-radius: 13px;
padding: 2px;
&:hover {
background-color: #8882;
}
.face {
width: 24px;
border-radius: 50%;
background-color: #8884;
}
.name {
padding: 0 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.title:hover,
.up:hover .name {
color: var(--theme-color);
}
.cover-container {
position: relative;
}
.time,
.watchlater {
position: absolute;
bottom: 4px;
display: flex;
align-items: center;
background-color: #000a;
color: #fff;
padding: 0 8px;
height: 20px;
border-radius: 10px;
box-sizing: border-box;
opacity: 0;
}
.time,
.watchlater {
opacity: 1;
}
.time {
left: 4px;
}
.watchlater {
padding: 0 8px 0 3px;
right: 4px;
font-size: 11px;
.mdi {
line-height: 1;
margin-right: 4px;
font-size: 16px;
}
}
}
} }
&.dark .video-activity-card, &.dark .video-activity-card,
&.dark .activity-popup-content .view-more, &.dark .activity-popup-content .view-more,
@ -168,98 +266,17 @@
box-shadow: rgba(0, 0, 0, 0.3) 0 4px 8px 0px; box-shadow: rgba(0, 0, 0, 0.3) 0 4px 8px 0px;
background-color: #2d2d2d; background-color: #2d2d2d;
} }
.video-activity-card .cover {
width: var(--card-width);
background-color: #8884;
height: calc(var(--card-width) / 16 * 10);
object-fit: cover;
display: block;
min-height: 100px;
}
.video-activity-card .title {
font-size: 10pt;
font-weight: bold;
margin: 8px 8px 2px 8px;
color: inherit;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.5;
max-height: 3em;
word-break: break-all;
}
.video-activity-card .title:hover,
.video-activity-card .up:hover .name {
color: var(--theme-color);
}
.video-activity-card .up {
display: flex;
justify-content: space-between;
align-items: center;
margin: 6px 8px;
border-radius: 13px;
padding: 2px;
}
.video-activity-card .up:hover {
background-color: #8882;
}
.video-activity-card .up .face {
width: 24px;
border-radius: 50%;
background-color: #8884;
}
.video-activity-card .up .name {
padding: 0 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.video-activity-card .cover-container {
position: relative;
}
.video-activity-card .time,
.video-activity-card .watchlater {
position: absolute;
bottom: 4px;
display: flex;
align-items: center;
background-color: #000a;
color: #fff;
padding: 0 8px;
height: 20px;
border-radius: 10px;
box-sizing: border-box;
opacity: 0;
}
.video-activity-card:hover .time,
.video-activity-card:hover .watchlater {
opacity: 1;
}
.video-activity-card .time {
left: 4px;
}
.video-activity-card .watchlater {
padding: 0 8px 0 3px;
right: 4px;
font-size: 11px;
}
.video-activity-card .watchlater .mdi {
line-height: 1;
margin-right: 4px;
font-size: 16px;
}
.bangumi-activity { .bangumi-activity {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-top: 4px; padding-top: 4px;
width: 100%; width: 100%;
} &.center {
.bangumi-activity.center { height: 100%;
height: 100%; justify-content: center;
justify-content: center; align-items: center;
align-items: center; }
} }
.bangumi-card { .bangumi-card {
--cover-width: 100px; --cover-width: 100px;
@ -271,133 +288,135 @@
grid-template-rows: 6fr 5fr; grid-template-rows: 6fr 5fr;
position: relative; position: relative;
flex-shrink: 0; flex-shrink: 0;
.up {
grid-area: title;
display: flex;
align-items: center;
padding: 0 12px;
align-self: start;
overflow: hidden;
.cover {
height: 18px;
border-radius: 50%;
}
.title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 6px;
line-height: normal;
}
}
.ep-title {
grid-area: epTitle;
font-size: 11pt;
font-weight: bold;
padding: 0 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
align-self: center;
color: inherit;
line-height: normal;
}
&:hover .ep-title {
color: var(--theme-color);
}
.ep-cover {
width: var(--cover-width);
min-height: 62.5px;
background-color: #8884;
grid-area: cover;
}
} }
&.dark .bangumi-card, &.dark .bangumi-card,
&.dark .live-card { &.dark .live-card {
box-shadow: rgba(0, 0, 0, 0.3) 0 2px 8px 0px; box-shadow: rgba(0, 0, 0, 0.3) 0 2px 8px 0px;
background-color: #2d2d2d; background-color: #2d2d2d;
} }
.bangumi-card .up {
grid-area: title;
display: flex;
align-items: center;
padding: 0 12px;
align-self: start;
overflow: hidden;
}
.bangumi-card .up .cover {
height: 18px;
border-radius: 50%;
}
.bangumi-card .up .title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 6px;
line-height: normal;
}
.bangumi-card .ep-title {
grid-area: epTitle;
font-size: 11pt;
font-weight: bold;
padding: 0 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
align-self: center;
color: inherit;
line-height: normal;
}
.bangumi-card:hover .ep-title {
color: var(--theme-color);
}
.bangumi-card .ep-cover {
width: var(--cover-width);
min-height: 62.5px;
background-color: #8884;
grid-area: cover;
}
.column-activity { .column-activity {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
padding: 0 12px; padding: 0 12px;
} &.center {
.column-activity.center { height: 100%;
height: 100%; align-items: center;
align-items: center; justify-content: center;
justify-content: center; }
} }
.column-card { .column-card {
width: 356px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 12px; margin-bottom: 12px;
box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px; box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px;
position: relative; position: relative;
flex-shrink: 0; flex-shrink: 0;
.up {
position: absolute;
left: 8px;
bottom: 6px;
padding: 2px;
display: flex;
align-items: center;
background-color: #000a;
border-radius: 14px;
height: 28px;
box-sizing: border-box;
.name {
margin: 0 6px;
color: #fff;
}
}
.face {
border-radius: 50%;
height: 24px;
}
.title {
padding: 10px 10px 0;
font-size: 11pt;
font-weight: bold;
color: inherit;
line-height: normal;
}
&:hover .title {
color: var(--theme-color);
}
.description {
margin: 8px 10px;
max-height: 3em;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
line-height: 1.5;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
}
.covers {
position: relative;
display: flex;
}
.cover {
flex: 1;
object-fit: cover;
}
} }
.column-card .up {
position: absolute;
left: 8px;
bottom: 6px;
padding: 2px;
display: flex;
align-items: center;
background-color: #000a;
border-radius: 14px;
height: 28px;
box-sizing: border-box;
}
.column-card .face {
border-radius: 50%;
height: 24px;
}
.column-card .up .name {
margin: 0 6px;
color: #fff;
}
.column-card .title {
padding: 10px 10px 0;
font-size: 11pt;
font-weight: bold;
color: inherit;
line-height: normal;
}
.column-card:hover .title {
color: var(--theme-color);
}
.column-card .description {
margin: 8px 10px;
max-height: 3em;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
line-height: 1.5;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: -webkit-box;
}
.column-card .covers {
position: relative;
display: flex;
}
.column-card .cover {
width: 0;
flex-grow: 1;
object-fit: cover;
}
.live-activity { .live-activity {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
width: 100%; width: 100%;
padding-top: 4px; padding-top: 4px;
} &.center {
.live-activity.center { height: 100%;
height: 100%; align-items: center;
align-items: center; justify-content: center;
justify-content: center; }
} }
.live-card { .live-card {
margin: 0 12px 12px 12px; margin: 0 12px 12px 12px;
@ -412,36 +431,49 @@
padding: 2px; padding: 2px;
width: auto; width: auto;
flex-shrink: 0; flex-shrink: 0;
.face {
grid-area: face;
border-radius: 50%;
height: 48px;
}
.live-title {
grid-area: title;
font-size: 11pt;
font-weight: bold;
align-self: center;
padding: 0 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: inherit;
line-height: normal;
}
&:hover .live-title {
color: var(--theme-color);
}
.name {
grid-area: name;
align-self: start;
padding: 0 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: normal;
}
} }
.live-card .face {
grid-area: face; .video-activity,
border-radius: 50%; .bangumi-activity,
height: 48px; .column-activity,
} .live-activity {
.live-card .live-title { .trigger {
grid-area: title; text-align: center;
font-size: 11pt; grid-area: trigger;
font-weight: bold; align-self: stretch;
align-self: center; margin-bottom: 12px;
padding: 0 12px; }
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: inherit;
line-height: normal;
}
.live-card:hover .live-title {
color: var(--theme-color);
}
.live-card .name {
grid-area: name;
align-self: start;
padding: 0 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: normal;
} }
.activity-content-enter-active, .activity-content-enter-active,
.activity-content-leave-active, .activity-content-leave-active,
.subscriptions-content-enter-active, .subscriptions-content-enter-active,

View File

@ -3,19 +3,22 @@ import { VideoCardInfo } from '../../simplify-home/video-card-info'
let componentUpdate = async () => { } let componentUpdate = async () => { }
let tabUpdate = async () => { } let tabUpdate = async () => { }
let latestID: string let latestID: string
// feeds history API https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history?uid=${getUID()}&offset_dynamic_id=${lastCardID}&type=${feedsType}
// live list https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=${pageSize}
interface ActivityTabComponentConfig { interface ActivityTabComponentConfig {
dataObject: {} dataObject: {}
apiUrl: string apiUrl: string
name: string name: string
handleJson: (json: any) => void handleJson: (json: any) => Promise<void>
template: string template: string
nextPage?: () => Promise<boolean>
} }
interface ActivityTab { interface ActivityTab {
name: string name: string
moreUrl: string moreUrl: string
} }
const getActivityTabComponent = ({ dataObject, apiUrl, name, handleJson, template }: ActivityTabComponentConfig) => { const getActivityTabComponent = ({ dataObject, apiUrl, name, handleJson, nextPage, template }: ActivityTabComponentConfig) => {
return { const component = {
template, template,
components: { components: {
'dpi-img': () => import('../dpi-img.vue'), 'dpi-img': () => import('../dpi-img.vue'),
@ -42,16 +45,44 @@ const getActivityTabComponent = ({ dataObject, apiUrl, name, handleJson, templat
data() { data() {
return Object.assign({ return Object.assign({
loading: true, loading: true,
hasMoreContent: true,
scrollObserver: null,
}, dataObject) }, dataObject)
}, },
mounted() { async mounted() {
this.fetchData()
componentUpdate = async () => await this.fetchData(true) componentUpdate = async () => await this.fetchData(true)
await this.fetchData()
if (this.$refs.trigger && typeof this.nextPage === 'function') {
console.log('infinite scroll')
const trigger = this.$refs.trigger as HTMLElement
const observer = new IntersectionObserver(async (entries) => {
console.log(entries)
if (entries.some(e => e.intersectionRatio > 0)) {
const hasMoreContent = await this.nextPage()
if (!hasMoreContent) {
console.log('disconnect')
observer.disconnect()
this.hasMoreContent = false
}
}
})
this.scrollObserver = observer
observer.observe(trigger)
}
}, },
destroyed() { beforeDestroy() {
componentUpdate = async () => { } componentUpdate = async () => { }
if (this.scrollObserver) {
console.log('destroy')
this.scrollObserver.disconnect()
this.scrollObserver = null
}
}, },
} }
if (nextPage) {
(component.methods as any).nextPage = nextPage
}
return component
} }
export class Activities extends NavbarComponent { export class Activities extends NavbarComponent {
constructor() { constructor() {
@ -80,6 +111,9 @@ export class Activities extends NavbarComponent {
} }
this.getNotifyCount() this.getNotifyCount()
setInterval(async () => { setInterval(async () => {
if (!navigator.onLine) {
return
}
await this.getNotifyCount() await this.getNotifyCount()
await tabUpdate() await tabUpdate()
await componentUpdate() await componentUpdate()
@ -214,18 +248,19 @@ export class Activities extends NavbarComponent {
<div class="video-activity" :class="{center: loading || (leftCards.length + rightCards.length) === 0}"> <div class="video-activity" :class="{center: loading || (leftCards.length + rightCards.length) === 0}">
<activity-loading :loading="loading"></activity-loading> <activity-loading :loading="loading"></activity-loading>
<activity-empty v-if="!loading && leftCards.length + rightCards.length === 0"></activity-empty> <activity-empty v-if="!loading && leftCards.length + rightCards.length === 0"></activity-empty>
<div v-if="!loading" class="video-activity-column"> <div v-if="!loading" class="video-activity-column left">
<video-card v-for="card of leftCards" :key="card.id" :card="card" :watchlaterInit="card.watchlater"></video-card> <video-card v-for="card of leftCards" :key="card.id" :card="card" :watchlaterInit="card.watchlater"></video-card>
</div> </div>
<div v-if="!loading" class="video-activity-column"> <div v-if="!loading" class="video-activity-column right">
<video-card v-for="card of rightCards" :key="card.id" :card="card" :watchlaterInit="card.watchlater"></video-card> <video-card v-for="card of rightCards" :key="card.id" :card="card" :watchlaterInit="card.watchlater"></video-card>
</div> </div>
<div v-if="!loading && hasMoreContent" class="trigger" ref="trigger">...</div>
</div> </div>
`, `,
handleJson: async function (json) { async handleJson(json) {
// const { getWatchlaterList } = await import('../../video/watchlater-api') // const { getWatchlaterList } = await import('../../video/watchlater-api')
// const watchlaterList = await getWatchlaterList() // const watchlaterList = await getWatchlaterList()
const cards = _.uniqBy(_.get(json, 'data.cards', []).map((card: any) => { const jsonCards = _.get(json, 'data.cards', []).map((card: any) => {
const cardJson = JSON.parse(card.card) const cardJson = JSON.parse(card.card)
return { return {
coverUrl: cardJson.pic, coverUrl: cardJson.pic,
@ -242,14 +277,38 @@ export class Activities extends NavbarComponent {
watchlater: true, watchlater: true,
get new() { return Activities.isNewID(this.id) }, get new() { return Activities.isNewID(this.id) },
} }
}), (it: VideoCardInfo) => it.aid) }) as VideoCardInfo[]
const cards = _.uniqBy(jsonCards.concat(this.leftCards, this.rightCards), it => it.id)
.sort((a, b) => {
return b.id > a.id ? 1 : -1
})
if (cards.length === 0) {
this.hasMoreContent = false
}
this.leftCards = cards.filter((_, index) => index % 2 === 0) this.leftCards = cards.filter((_, index) => index % 2 === 0)
this.rightCards = cards.filter((_, index) => index % 2 === 1) this.rightCards = cards.filter((_, index) => index % 2 === 1)
if (this.leftCards.length !== this.rightCards.length) { // if (this.leftCards.length !== this.rightCards.length) {
this.leftCards.pop() // this.leftCards.pop()
} // }
Activities.updateLatestID(cards) Activities.updateLatestID(cards)
} },
async nextPage() {
const cards = [...this.leftCards, ...this.rightCards].sort((a, b) => {
return b.id > a.id ? 1 : -1
}) as VideoCardInfo[]
if (cards.length === 0) {
return false
}
let lastCardID = cards.pop()!.id
const api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history?uid=${getUID()}&offset_dynamic_id=${lastCardID}&type=8`
const json = await Ajax.getJsonWithCredentials(api)
console.log('lastCardID', lastCardID, json)
if (json.code !== 0) {
return false
}
await this.handleJson(json)
return Boolean(_.get(json, 'data.has_more', true))
},
}), { }), {
components: { components: {
'video-card': { 'video-card': {
@ -313,10 +372,11 @@ export class Activities extends NavbarComponent {
<div class="title">{{card.title}}</div> <div class="title">{{card.title}}</div>
</div> </div>
</a> </a>
<div v-if="!loading && hasMoreContent" class="trigger" ref="trigger">...</div>
</div> </div>
`, `,
handleJson: async function (json) { handleJson: async function (json) {
this.cards = _.get(json, 'data.cards', []).map((card: any) => { const cards = _.get(json, 'data.cards', []).map((card: any) => {
const cardJson = JSON.parse(card.card) const cardJson = JSON.parse(card.card)
return { return {
title: cardJson.apiSeasonInfo.title, title: cardJson.apiSeasonInfo.title,
@ -327,8 +387,30 @@ export class Activities extends NavbarComponent {
id: card.desc.dynamic_id_str, id: card.desc.dynamic_id_str,
get new() { return Activities.isNewID(this.id) }, get new() { return Activities.isNewID(this.id) },
} }
}) }) as { id: string }[]
Activities.updateLatestID(this.cards) this.cards = _.uniqBy(cards.concat(this.cards), it => it.id)
.sort((a, b) => {
return b.id > a.id ? 1 : -1
})
if (cards.length === 0) {
this.hasMoreContent = false
}
Activities.updateLatestID(cards)
},
async nextPage() {
const cards = [...this.cards] as VideoCardInfo[]
if (cards.length === 0) {
return false
}
let lastCardID = cards.pop()!.id
const api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history?uid=${getUID()}&offset_dynamic_id=${lastCardID}&type=512`
const json = await Ajax.getJsonWithCredentials(api)
console.log('lastCardID', lastCardID, json)
if (json.code !== 0) {
return false
}
await this.handleJson(json)
return Boolean(_.get(json, 'data.has_more', true))
}, },
}), }),
'column-activity': getActivityTabComponent({ 'column-activity': getActivityTabComponent({
@ -341,19 +423,22 @@ export class Activities extends NavbarComponent {
<activity-empty v-if="!loading && cards.length === 0"></activity-empty> <activity-empty v-if="!loading && cards.length === 0"></activity-empty>
<a v-if="!loading" class="column-card" :class="{new: card.new}" v-for="card of cards" :key="card.id" target="_blank" :href="card.url"> <a v-if="!loading" class="column-card" :class="{new: card.new}" v-for="card of cards" :key="card.id" target="_blank" :href="card.url">
<div class="covers"> <div class="covers">
<dpi-img class="cover" v-for="cover of card.covers" :key="cover" :size="{height: 120}" :src="cover"></dpi-img> <!--<dpi-img class="cover" v-for="cover of card.covers" :key="cover" :size="{ height: 120, width: 0 }" :src="cover"></dpi-img>-->
<img class="cover" v-for="cover of card.covers" :key="cover" height="120" width="0" :src="cover"/>
<a class="up" target="_blank" :href="card.upUrl"> <a class="up" target="_blank" :href="card.upUrl">
<dpi-img class="face" :size="24" :src="card.faceUrl"></dpi-img> <img class="face" height="24" width="24" :src="card.faceUrl"/>
<!--<dpi-img class="face" :size="24" :src="card.faceUrl"></dpi-img>-->
<div class="name">{{card.upName}}</div> <div class="name">{{card.upName}}</div>
</a> </a>
</div> </div>
<h1 class="title" :title="card.title">{{card.title}}</h1> <h1 class="title" :title="card.title">{{card.title}}</h1>
<div class="description" :title="card.description">{{card.description}}</div> <div class="description" :title="card.description">{{card.description}}</div>
</a> </a>
<div v-if="!loading && hasMoreContent" class="trigger" ref="trigger">...</div>
</div> </div>
`, `,
handleJson: async function (json) { handleJson: async function (json) {
this.cards = _.get(json, 'data.cards', []).map((card: any) => { const cards = _.get(json, 'data.cards', []).map((card: any) => {
const cardJson = JSON.parse(card.card) const cardJson = JSON.parse(card.card)
return { return {
covers: cardJson.image_urls, covers: cardJson.image_urls,
@ -367,9 +452,31 @@ export class Activities extends NavbarComponent {
id: card.desc.dynamic_id_str, id: card.desc.dynamic_id_str,
get new() { return Activities.isNewID(this.id) }, get new() { return Activities.isNewID(this.id) },
} }
}) }) as { id: string }[]
this.cards = _.uniqBy(cards.concat(this.cards), it => it.id)
.sort((a, b) => {
return b.id > a.id ? 1 : -1
})
if (cards.length === 0) {
this.hasMoreContent = false
}
Activities.updateLatestID(this.cards) Activities.updateLatestID(this.cards)
}, },
async nextPage() {
const cards = [...this.cards] as VideoCardInfo[]
if (cards.length === 0) {
return false
}
let lastCardID = cards.pop()!.id
const api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history?uid=${getUID()}&offset_dynamic_id=${lastCardID}&type=64`
const json = await Ajax.getJsonWithCredentials(api)
console.log('lastCardID', lastCardID, json)
if (json.code !== 0) {
return false
}
await this.handleJson(json)
return Boolean(_.get(json, 'data.has_more', true))
},
}), }),
'live-activity': getActivityTabComponent({ 'live-activity': getActivityTabComponent({
dataObject: { cards: [] }, dataObject: { cards: [] },
@ -387,7 +494,7 @@ export class Activities extends NavbarComponent {
</div> </div>
`, `,
handleJson: async function (json) { handleJson: async function (json) {
this.cards = _.get(json, 'data.list', []).map((card: any) => { const parseLiveCard = (card: any) => {
return { return {
faceUrl: card.face, faceUrl: card.face,
title: card.title, title: card.title,
@ -395,7 +502,20 @@ export class Activities extends NavbarComponent {
id: card.roomid, id: card.roomid,
url: card.link, url: card.link,
} }
}
this.cards = _.get(json, 'data.list', []).map(parseLiveCard)
const fullList = await Ajax.getPages({
api: page => {
return Ajax.getJsonWithCredentials(`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=24`)
},
getList: json => {
return _.get(json, 'data.list', [])
},
getTotal: json => {
return _.get(json, 'data.results', 0)
},
}) })
this.cards = fullList.map(parseLiveCard)
}, },
}), }),
}, },