You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.4 KiB
TypeScript
147 lines
4.4 KiB
TypeScript
import './Header.less'
|
|
|
|
import { Layout } from 'ant-design-vue'
|
|
|
|
import GlobalHeader, { globalHeaderProps } from './components/GlobalHeader'
|
|
|
|
import TopNavHeader from './components/TopNavHeader'
|
|
import { clearMenuItem } from './utils/utils'
|
|
import { getRender } from './utils'
|
|
|
|
import { VueNodeOrRenderPropType, WithFalseVueNodeOrRenderPropType } from '#/types'
|
|
import type { VueNodeOrRender } from '#/types'
|
|
import type { HeaderContentRender, HeaderRender, HeaderTitleRender } from './renderTypes'
|
|
|
|
import type { WithFalse } from './types'
|
|
import type { PropType, CSSProperties, Slots, ExtractPropTypes } from 'vue'
|
|
import type { PrivateSiderMenuProps } from './components/SiderMenu/SiderMenu'
|
|
|
|
export const headerViewProps = () => ({
|
|
// 集成
|
|
...globalHeaderProps(),
|
|
|
|
isMobile: {
|
|
type: Boolean,
|
|
default: undefined
|
|
},
|
|
logo: {
|
|
type: VueNodeOrRenderPropType as PropType<VueNodeOrRender>,
|
|
default: () => undefined
|
|
},
|
|
headerRender: {
|
|
type: WithFalseVueNodeOrRenderPropType as PropType<WithFalse<HeaderRender>>,
|
|
default: () => undefined
|
|
},
|
|
headerTitleRender: {
|
|
type: [Function, Boolean] as PropType<WithFalse<HeaderTitleRender>>,
|
|
default: () => undefined
|
|
},
|
|
headerContentRender: {
|
|
type: [Function, Boolean] as PropType<WithFalse<HeaderContentRender>>,
|
|
default: () => undefined
|
|
},
|
|
siderWidth: {
|
|
type: Number,
|
|
default: 208
|
|
},
|
|
hasSiderMenu: Boolean,
|
|
visible: Boolean
|
|
})
|
|
|
|
export type HeaderViewProps = Partial<ExtractPropTypes<ReturnType<typeof headerViewProps>>>
|
|
|
|
// TODO slots 支持
|
|
const renderContent = (props: HeaderViewProps & PrivateSiderMenuProps, slots: Slots) => {
|
|
const clearMenuData = clearMenuItem(props.menuData || [])
|
|
|
|
const headerContentRender = getRender<HeaderContentRender>(props, slots, 'headerContentRender')
|
|
|
|
let defaultDom
|
|
if (props.layout === 'top' && !props.isMobile) {
|
|
defaultDom = (
|
|
<TopNavHeader
|
|
theme={props.navTheme as 'light' | 'dark'}
|
|
mode="horizontal"
|
|
onCollapse={props.onCollapse}
|
|
{...props}
|
|
menuData={clearMenuData}
|
|
>
|
|
{slots}
|
|
</TopNavHeader>
|
|
)
|
|
} else {
|
|
defaultDom = (
|
|
<GlobalHeader onCollapse={props.onCollapse} {...props} menuData={clearMenuData}>
|
|
{{
|
|
...slots,
|
|
default: () => headerContentRender && headerContentRender(props, null)
|
|
}}
|
|
</GlobalHeader>
|
|
)
|
|
}
|
|
|
|
const headerRender = getRender<HeaderRender>(props, slots, 'headerRender')
|
|
if (headerRender && typeof headerRender === 'function') {
|
|
return headerRender(props, defaultDom)
|
|
}
|
|
return defaultDom
|
|
}
|
|
|
|
export default defineComponent({
|
|
name: 'BasicHeader',
|
|
props: headerViewProps(),
|
|
setup(props, { slots, attrs }) {
|
|
const needFixedHeader = computed(() => props.fixedHeader || props.layout === 'mix')
|
|
const isTop = computed(() => props.layout === 'top')
|
|
|
|
const className = computed(() => [
|
|
attrs.class,
|
|
{
|
|
[`${props.prefixCls}-fixed-header`]: needFixedHeader.value,
|
|
[`${props.prefixCls}-fixed-header-action`]: !props.collapsed,
|
|
[`${props.prefixCls}-top-menu`]: isTop.value,
|
|
[`${props.prefixCls}-header-${props.navTheme}`]: props.navTheme && props.layout !== 'mix'
|
|
}
|
|
])
|
|
|
|
/** 计算侧边栏的宽度,不然导致左边的样式会出问题 */
|
|
const width = computed(() => {
|
|
const needSettingWidth =
|
|
needFixedHeader.value && props.hasSiderMenu && !isTop.value && !props.isMobile
|
|
return props.layout !== 'mix' && needSettingWidth
|
|
? `calc(100% - ${props.collapsed ? 48 : props.siderWidth}px)`
|
|
: '100%'
|
|
})
|
|
|
|
const right = computed(() => (needFixedHeader.value ? 0 : undefined))
|
|
|
|
return () => (
|
|
<>
|
|
{needFixedHeader.value && (
|
|
<Layout.Header
|
|
style={{
|
|
height: `${props.headerHeight}px`,
|
|
lineHeight: `${props.headerHeight}px`,
|
|
background: 'transparent'
|
|
}}
|
|
/>
|
|
)}
|
|
<Layout.Header
|
|
style={{
|
|
padding: 0,
|
|
height: `${props.headerHeight}px`,
|
|
lineHeight: `${props.headerHeight}px`,
|
|
width: width.value,
|
|
zIndex: props.layout === 'mix' ? 100 : 19,
|
|
right: right.value,
|
|
...(attrs.style as CSSProperties)
|
|
}}
|
|
class={className.value}
|
|
>
|
|
{renderContent(props as any, slots)}
|
|
</Layout.Header>
|
|
</>
|
|
)
|
|
}
|
|
})
|