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

View File

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

View File

@ -1,5 +1,5 @@
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 NLayoutFooter } from './src/LayoutFooter'
export { default as NLayoutSider } from './src/LayoutSider'

View File

@ -40,97 +40,102 @@ export const layoutInjectionKey: InjectionKey<
ExtractPropTypes<LayoutProps>
> = Symbol('layout')
export default defineComponent({
name: 'Layout',
alias: ['LayoutContent'],
props: {
...(useTheme.props as ThemeProps<LayoutTheme>),
...layoutProps
},
setup (props) {
const selfRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<ScrollbarInst | null>(null)
const { mergedClsPrefixRef } = useConfig(props)
const themeRef = useTheme(
'Layout',
'Layout',
style,
layoutLight,
props,
mergedClsPrefixRef
)
const scrollTo: LayoutInst['scrollTo'] = (
options: ScrollToOptions | number,
y?: number
): void => {
if (scrollbarRef.value) {
scrollbarRef.value.scrollTo(options as any, y as any)
} else if (selfRef.value) {
selfRef.value.scrollTo(options as any, y as any)
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function createLayoutComponent (isContent: boolean) {
return defineComponent({
name: isContent ? 'LayoutContent' : 'Layout',
props: {
...(useTheme.props as ThemeProps<LayoutTheme>),
...layoutProps
},
setup (props) {
const scrollableDivRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<ScrollbarInst | null>(null)
const { mergedClsPrefixRef } = useConfig(props)
const themeRef = useTheme(
'Layout',
'Layout',
style,
layoutLight,
props,
mergedClsPrefixRef
)
const scrollTo: LayoutInst['scrollTo'] = (
options: ScrollToOptions | number,
y?: number
): void => {
if (scrollbarRef.value) {
scrollbarRef.value.scrollTo(options as any, y as any)
} else if (scrollableDivRef.value) {
scrollableDivRef.value.scrollTo(options as any, y as any)
}
}
}
const scrollableDivStyleRef = computed(() => {
return [
props.contentStyle,
{
height: '100%',
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
}
const scrollableDivStyleRef = computed(() => {
return [
props.contentStyle,
{
height: '100%',
overflow: 'auto'
}
]
})
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 (
<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>
)
}
})
})
}
export default createLayoutComponent(false)

View File

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

View File

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

View File

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