Use type Component as vue component in custom-navbar-item.ts

This commit is contained in:
timongh 2023-02-09 13:01:58 +08:00
parent d24fbdd89a
commit 7ed9ced13d
17 changed files with 72 additions and 40 deletions

View File

@ -56,10 +56,11 @@
</template>
<script lang="ts">
import type { ComponentPublicInstance, Ref } from 'vue'
import type { Ref } from 'vue'
import { defineComponent, ref } from 'vue'
import { addComponentListener, removeComponentListener } from '@/core/settings'
import type { PopupContentInstance } from './custom-navbar-item'
import { CustomNavbarItem } from './custom-navbar-item'
import CustomNavbarLink from './CustomNavbarLink.vue'
@ -71,6 +72,22 @@ const isOpenInNewTab = (item: CustomNavbarItem) => {
}
return options.openInNewTab
}
function trigger(this: InstanceType<typeof ThisComponent>, initialPopup: boolean) {
const { popup } = this
if (!popup) {
return
}
const allowRefresh =
CustomNavbarItem.navbarOptions.refreshOnPopup &&
popup.popupRefresh &&
typeof popup.popupRefresh === 'function'
if (!initialPopup && allowRefresh) {
popup.popupRefresh()
}
if (popup.popupShow && typeof popup.popupShow === 'function') {
popup.popupShow()
}
}
const ThisComponent = defineComponent({
components: {
CustomNavbarLink,
@ -82,7 +99,7 @@ const ThisComponent = defineComponent({
},
},
setup: () => ({
popup: ref(null) as Ref<ComponentPublicInstance | null>,
popup: ref(null) as Ref<PopupContentInstance | null>,
popupContainer: ref(null) as Ref<HTMLDivElement | null>,
}),
data() {
@ -126,22 +143,10 @@ const ThisComponent = defineComponent({
'iframe-container': item.iframeName,
}
},
triggerPopupShow: lodash.debounce(function trigger(this: InstanceType<typeof ThisComponent>, initialPopup: boolean) {
const { popup } = this
if (!popup) {
return
}
const allowRefresh =
CustomNavbarItem.navbarOptions.refreshOnPopup &&
popup.popupRefresh &&
typeof popup.popupRefresh === 'function'
if (!initialPopup && allowRefresh) {
popup.popupRefresh()
}
if (popup.popupShow && typeof popup.popupShow === 'function') {
popup.popupShow()
}
}, 300) as unknown as (initialPopup: boolean) => void,
triggerPopupShow: lodash.debounce(trigger, 300) as unknown as (
this: any,
initialPopup: boolean,
) => void,
async requestPopup() {
const { item } = this as {
item: CustomNavbarItem

View File

@ -1,11 +1,23 @@
import type { Instance as Popper } from '@popperjs/core'
import { createPopper } from '@popperjs/core'
import type { Executable, ImportedVueComponent } from '@/core/common-types'
import type { Component, ComponentPublicInstance } from 'vue'
import type { Executable } from '@/core/common-types'
import { addComponentListener, getComponentSettings } from '@/core/settings'
import type { CustomNavbarOptions } from '.'
export interface PopupContentInstance
extends ComponentPublicInstance<{
container?: HTMLElement
item?: CustomNavbarItem
}> {
popupRefresh?(): void
popupShow(): void
}
export type PopupContent = Component & (new () => PopupContentInstance)
export const CustomNavbarItems = 'customNavbar.items'
export const CustomNavbarRenderedItems = 'customNavbar.renderedItems'
/**
@ -17,7 +29,7 @@ export interface CustomNavbarItemInit {
/** 显示名称 */
displayName: string
/** 内容 */
content: Executable<ImportedVueComponent> | string
content: Component<{ item?: CustomNavbarItem }> | string
/** 设定CSS flex样式 (grow, shrink, basis) */
flexStyle?: string
@ -39,7 +51,7 @@ export interface CustomNavbarItemInit {
loginRequired?: boolean
/** 弹窗内容 */
popupContent?: Executable<ImportedVueComponent>
popupContent?: PopupContent | undefined
/** 设为大于0的值时, 表示预计的弹窗宽度, 将会用于边缘检测, 防止超出viewport */
boundingWidth?: number
/** 不使用默认的弹窗padding */
@ -53,7 +65,7 @@ export interface CustomNavbarItemInit {
export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
name: string
displayName: string
content: Executable<ImportedVueComponent> | string
content: Component<{ item?: CustomNavbarItem }> | string
flexStyle = '0 0 auto'
disabled = false
@ -65,7 +77,7 @@ export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
touch = false
loginRequired = false
popupContent: Executable<ImportedVueComponent> = null
popupContent: PopupContent | undefined
popper: Popper = null
boundingWidth = 0
noPopupPadding = false

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import { getUID } from '@/core/utils'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
@ -15,5 +16,5 @@ export const favorites: CustomNavbarItemInit = {
boundingWidth: 380,
noPopupPadding: true,
popupContent: () => import('./NavbarFavorites.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarFavorites.vue')),
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const feeds: CustomNavbarItemInit = {
@ -20,7 +21,7 @@ export const feeds: CustomNavbarItemInit = {
},
loginRequired: true,
popupContent: () => import('./NavbarFeeds.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarFeeds.vue')),
boundingWidth: 300,
noPopupPadding: true,
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
const href = 'https://www.bilibili.com/account/history'
@ -13,5 +14,5 @@ export const history: CustomNavbarItemInit = {
boundingWidth: 400,
noPopupPadding: true,
popupContent: () => import('./NavbarHistory.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarHistory.vue')),
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const home: CustomNavbarItemInit = {
@ -9,5 +10,5 @@ export const home: CustomNavbarItemInit = {
touch: true,
boundingWidth: 366,
popupContent: () => import('./NavbarHome.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarHome.vue')),
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
interface NavbarIframeConfig {
@ -16,7 +17,7 @@ const getIframeItem = (config: NavbarIframeConfig): CustomNavbarItemInit & Navba
touch: true,
popupContent: () => import('./IframePopup.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./IframePopup.vue')),
boundingWidth: config.width,
noPopupPadding: true,
transparentPopup: true,

View File

@ -1,9 +1,10 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const logo: CustomNavbarItemInit = {
name: 'logo',
displayName: 'Logo',
content: () => import('./NavbarLogo.vue').then(m => m.default),
content: defineAsyncComponent(() => import('./NavbarLogo.vue')),
href: 'https://www.bilibili.com/',
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
const messagesUrl = 'https://message.bilibili.com/'
@ -11,6 +12,6 @@ export const messages: CustomNavbarItemInit = {
loginRequired: true,
touch: true,
popupContent: () => import('./NavbarMessages.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarMessages.vue')),
lazy: false,
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
const rankingUrl = 'https://www.bilibili.com/v/popular/rank/'
@ -10,5 +11,5 @@ export const ranking: CustomNavbarItemInit = {
active: document.URL.startsWith(rankingUrl),
touch: true,
popupContent: () => import('./NavbarRanking.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarRanking.vue')),
}

View File

@ -1,9 +1,10 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const search: CustomNavbarItemInit = {
name: 'search',
displayName: '搜索',
content: () => import('./NavbarSearch.vue').then(m => m.default),
content: defineAsyncComponent(() => import('./NavbarSearch.vue')),
// 禁用元素本身的 hover 效果之类的, 作为 content 的 NavbarSearch 是依然能够响应的
disabled: true,

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import { getUID } from '@/core/utils'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
@ -23,5 +24,5 @@ export const subscriptions: CustomNavbarItemInit = {
boundingWidth: 380,
noPopupPadding: true,
popupContent: () => import('./NavbarSubscriptions.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarSubscriptions.vue')),
}

View File

@ -1,12 +1,13 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const upload: CustomNavbarItemInit = {
name: 'upload',
displayName: '投稿',
content: () => import('./NavbarUpload.vue').then(m => m.default),
content: defineAsyncComponent(() => import('./NavbarUpload.vue')),
touch: true,
href: 'https://member.bilibili.com/platform/upload/video/frame',
popupContent: () => import('./UploadPopup.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./UploadPopup.vue')),
}

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import { getUID } from '@/core/utils'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
@ -5,12 +6,12 @@ import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const userInfo: CustomNavbarItemInit = {
name: 'userInfo',
displayName: '个人信息',
content: () => import('./UserFace.vue').then(m => m.default),
content: defineAsyncComponent(() => import('./UserFace.vue')),
href: getUID() ? 'https://space.bilibili.com' : null,
touch: true,
popupContent: () => import('./UserInfoPopup.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./UserInfoPopup.vue')),
lazy: false,
noPopupPadding: true,
boundingWidth: 240,

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { CustomNavbarItemInit } from '../custom-navbar-item'
export const watchlater: CustomNavbarItemInit = {
@ -12,5 +13,5 @@ export const watchlater: CustomNavbarItemInit = {
boundingWidth: 380,
noPopupPadding: true,
popupContent: () => import('./NavbarWatchlater.vue').then(m => m.default),
popupContent: defineAsyncComponent(() => import('./NavbarWatchlater.vue')),
}

View File

@ -1,5 +1,6 @@
import type { CustomNavbarOptions } from 'registry/lib/components/style/custom-navbar'
import { defineAsyncComponent } from 'vue'
import { getComponentSettings } from '@/core/settings'
import type { PluginMetadata } from '@/plugins/plugin'
@ -23,7 +24,7 @@ export const plugin: PluginMetadata = {
items.push({
name: 'channel',
displayName: '频道',
content: () => import('./NavbarChannel.vue'),
content: defineAsyncComponent(() => import('./NavbarChannel.vue')),
clickAction: () => {
const channelId = dq('.navbar-channel').getAttribute('data-channel-id')
window.open(

View File

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import type { PluginMetadata } from '@/plugins/plugin'
import type { CustomNavbarItemInit } from '../../../components/style/custom-navbar/custom-navbar-item'
@ -12,7 +13,7 @@ export const plugin: PluginMetadata = {
items.push({
name: 'darkMode',
displayName: '夜间开关',
content: () => import('./NavbarDarkMode.vue'),
content: defineAsyncComponent(() => import('./NavbarDarkMode.vue')),
clickAction: () => {
const settings = getComponentSettings('darkMode')