fix(layout): scrollTo not working with native scrollbar

This commit is contained in:
07akioni 2021-05-25 16:43:02 +08:00
parent c5dd884df6
commit e32b020a95
7 changed files with 120 additions and 100 deletions

View File

@ -2,6 +2,10 @@
## Pending ## Pending
### Breaking Changes
- `n-layout-sider` removed `show-content` prop. Please use `show-collapsed-content` instead.
### Feats ### Feats
- `n-data-table` support tree data. - `n-data-table` support tree data.
@ -25,6 +29,7 @@
### Fixes ### Fixes
- `n-layout` & `n-layout-sider`'s `scrollTo` not working with native scrollbar.
- `n-layout-sider`'s `collapse-mode` not working. - `n-layout-sider`'s `collapse-mode` not working.
- Internal selection component's theme peers has wrong key for popover. - Internal selection component's theme peers has wrong key for popover.

View File

@ -2,6 +2,10 @@
## Pending ## Pending
### Breaking Changes
- `n-layout-sider` 移除了 `show-content`,使用 `show-collapsed-content` 代替
### Feats ### Feats
- `n-data-table` 支持树形数据 - `n-data-table` 支持树形数据
@ -25,6 +29,7 @@
### Fixes ### Fixes
- `n-layout` & `n-layout-sider``scrollTo` 在使用原生滚动条时不生效
- `n-layout-sider``collapse-mode` 属性不生效 - `n-layout-sider``collapse-mode` 属性不生效
- 内部 selection 组件的主题 peers 中 popover 的 key 不正确 - 内部 selection 组件的主题 peers 中 popover 的 key 不正确

View File

@ -1,5 +1,5 @@
export { default as NLayout } from './src/Layout' export { default as NLayout } from './src/Layout'
export { default as NLayoutContent } from './src/Layout' export { default as NLayoutContent } from './src/LayoutContent'
export { default as NLayoutHeader } from './src/LayoutHeader' export { default as NLayoutHeader } from './src/LayoutHeader'
export { default as NLayoutFooter } from './src/LayoutFooter' export { default as NLayoutFooter } from './src/LayoutFooter'
export { default as NLayoutSider } from './src/LayoutSider' export { default as NLayoutSider } from './src/LayoutSider'

View File

@ -40,97 +40,102 @@ export const layoutInjectionKey: InjectionKey<
ExtractPropTypes<LayoutProps> ExtractPropTypes<LayoutProps>
> = Symbol('layout') > = Symbol('layout')
export default defineComponent({ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
name: 'Layout', export function createLayoutComponent (isContent: boolean) {
alias: ['LayoutContent'], return defineComponent({
props: { name: isContent ? 'LayoutContent' : 'Layout',
...(useTheme.props as ThemeProps<LayoutTheme>), props: {
...layoutProps ...(useTheme.props as ThemeProps<LayoutTheme>),
}, ...layoutProps
setup (props) { },
const selfRef = ref<HTMLElement | null>(null) setup (props) {
const scrollbarRef = ref<ScrollbarInst | null>(null) const scrollableDivRef = ref<HTMLElement | null>(null)
const { mergedClsPrefixRef } = useConfig(props) const scrollbarRef = ref<ScrollbarInst | null>(null)
const themeRef = useTheme( const { mergedClsPrefixRef } = useConfig(props)
'Layout', const themeRef = useTheme(
'Layout', 'Layout',
style, 'Layout',
layoutLight, style,
props, layoutLight,
mergedClsPrefixRef props,
) mergedClsPrefixRef
const scrollTo: LayoutInst['scrollTo'] = ( )
options: ScrollToOptions | number, const scrollTo: LayoutInst['scrollTo'] = (
y?: number options: ScrollToOptions | number,
): void => { y?: number
if (scrollbarRef.value) { ): void => {
scrollbarRef.value.scrollTo(options as any, y as any) if (scrollbarRef.value) {
} else if (selfRef.value) { scrollbarRef.value.scrollTo(options as any, y as any)
selfRef.value.scrollTo(options as any, y as any) } else if (scrollableDivRef.value) {
scrollableDivRef.value.scrollTo(options as any, y as any)
}
} }
} const scrollableDivStyleRef = computed(() => {
const scrollableDivStyleRef = computed(() => { return [
return [ props.contentStyle,
props.contentStyle, {
{ height: '100%',
height: '100%', overflow: 'auto'
overflow: 'auto' }
} ]
]
})
if (__DEV__) provide(layoutInjectionKey, props)
return {
mergedClsPrefix: mergedClsPrefixRef,
selfRef,
scrollbarRef,
scrollableDivStyle: scrollableDivStyleRef,
scrollTo,
mergedTheme: themeRef,
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--color': props.embedded ? self.colorEmbedded : self.color,
'--text-color': self.textColor
}
}) })
if (__DEV__) provide(layoutInjectionKey, props)
return {
mergedClsPrefix: mergedClsPrefixRef,
scrollableDivRef,
scrollbarRef,
scrollableDivStyle: scrollableDivStyleRef,
scrollTo,
mergedTheme: themeRef,
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--color': props.embedded ? self.colorEmbedded : self.color,
'--text-color': self.textColor
}
})
}
},
render () {
const { mergedClsPrefix } = this
return (
<div
class={[
isContent && `${mergedClsPrefix}-layout-content`,
`${mergedClsPrefix}-layout`,
`${mergedClsPrefix}-layout--${this.position}-positioned`,
this.hasSider && `${mergedClsPrefix}-layout--has-sider`
]}
style={this.cssVars as CSSProperties}
>
{!this.nativeScrollbar ? (
<NScrollbar
{...this.scrollbarProps}
ref="scrollbarRef"
theme={this.mergedTheme.peers.Scrollbar}
themeOverrides={this.mergedTheme.peerOverrides.Scrollbar}
contentClass={`${mergedClsPrefix}-layout__content`}
contentStyle={this.contentStyle}
>
{this.$slots}
</NScrollbar>
) : (
<div
ref="scrollableDivRef"
class={`${mergedClsPrefix}-layout__content`}
style={this.scrollableDivStyle}
>
{this.$slots}
</div>
)}
</div>
)
} }
}, })
render () { }
const { mergedClsPrefix } = this
return ( export default createLayoutComponent(false)
<div
ref="selfRef"
class={[
`${mergedClsPrefix}-layout`,
`${mergedClsPrefix}-layout--${this.position}-positioned`,
this.hasSider && `${mergedClsPrefix}-layout--has-sider`
]}
style={this.cssVars as CSSProperties}
>
{!this.nativeScrollbar ? (
<NScrollbar
{...this.scrollbarProps}
ref="scrollbarRef"
theme={this.mergedTheme.peers.Scrollbar}
themeOverrides={this.mergedTheme.peerOverrides.Scrollbar}
contentClass={`${mergedClsPrefix}-layout__content`}
contentStyle={this.contentStyle}
>
{this.$slots}
</NScrollbar>
) : (
<div
class={`${mergedClsPrefix}-layout__content`}
style={this.scrollableDivStyle}
>
{this.$slots}
</div>
)}
</div>
)
}
})

View File

@ -0,0 +1,3 @@
import { createLayoutComponent } from './Layout'
export default createLayoutComponent(true)

View File

@ -48,7 +48,7 @@ const layoutSiderProps = {
default: undefined default: undefined
}, },
defaultCollapsed: Boolean, defaultCollapsed: Boolean,
showContent: { showCollapsedContent: {
type: Boolean, type: Boolean,
default: true default: true
}, },
@ -106,7 +106,7 @@ export default defineComponent({
} }
} }
} }
const selfRef = ref<HTMLElement | null>(null) const scrollableDivRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<ScrollbarInst | null>(null) const scrollbarRef = ref<ScrollbarInst | null>(null)
const styleMaxWidthRef = computed(() => { const styleMaxWidthRef = computed(() => {
return formatLength( return formatLength(
@ -140,11 +140,11 @@ export default defineComponent({
function scrollTo (options: ScrollToOptions | number, y?: number): void { function scrollTo (options: ScrollToOptions | number, y?: number): void {
if (scrollbarRef.value) { if (scrollbarRef.value) {
scrollbarRef.value.scrollTo(options as any, y as any) scrollbarRef.value.scrollTo(options as any, y as any)
} else if (selfRef.value) { } else if (scrollableDivRef.value) {
if (y === undefined) { if (y === undefined) {
selfRef.value.scrollTo(options as any) scrollableDivRef.value.scrollTo(options as any)
} else { } else {
selfRef.value.scrollTo(options as any, y as any) scrollableDivRef.value.scrollTo(options as any, y as any)
} }
} }
} }
@ -183,7 +183,7 @@ export default defineComponent({
mergedClsPrefixRef mergedClsPrefixRef
) )
return { return {
selfRef, scrollableDivRef,
scrollbarRef, scrollbarRef,
mergedClsPrefix: mergedClsPrefixRef, mergedClsPrefix: mergedClsPrefixRef,
mergedTheme: themeRef, mergedTheme: themeRef,
@ -227,13 +227,13 @@ export default defineComponent({
const { mergedClsPrefix } = this const { mergedClsPrefix } = this
return ( return (
<aside <aside
ref="selfRef"
class={[ class={[
`${mergedClsPrefix}-layout-sider`, `${mergedClsPrefix}-layout-sider`,
`${mergedClsPrefix}-layout-sider--${this.position}-positioned`, `${mergedClsPrefix}-layout-sider--${this.position}-positioned`,
this.bordered && `${mergedClsPrefix}-layout-sider--bordered`, this.bordered && `${mergedClsPrefix}-layout-sider--bordered`,
this.mergedCollapsed && `${mergedClsPrefix}-layout-sider--collapsed`, this.mergedCollapsed && `${mergedClsPrefix}-layout-sider--collapsed`,
this.showContent && `${mergedClsPrefix}-layout-sider--show-content` (!this.mergedCollapsed || this.showCollapsedContent) &&
`${mergedClsPrefix}-layout-sider--show-content`
]} ]}
style={[ style={[
this.cssVars, this.cssVars,
@ -269,6 +269,7 @@ export default defineComponent({
<div <div
class={`${mergedClsPrefix}-layout-sider__content`} class={`${mergedClsPrefix}-layout-sider__content`}
style={this.scrollableDivStyle} style={this.scrollableDivStyle}
ref="scrollableDivRef"
> >
{this.$slots} {this.$slots}
</div> </div>

View File

@ -26,6 +26,7 @@ export default cB('layout', `
`) `)
]) ])
]), ]),
cE('content', 'box-sizing: border-box;'),
cM('absolute-positioned', ` cM('absolute-positioned', `
position: absolute; position: absolute;
left: 0; left: 0;