feat: add native-scrollbars option to workaround scrolling perf issues

This commit is contained in:
Roman Hotsiy 2017-09-21 18:03:31 +03:00
parent d8b6e022b7
commit f2ed92c69e
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
4 changed files with 32 additions and 14 deletions

View File

@ -156,6 +156,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
* `no-auto-auth` - do not inject Authentication section automatically * `no-auto-auth` - do not inject Authentication section automatically
* `path-in-middle-panel` - show path link and HTTP verb in the middle panel instead of the right one * `path-in-middle-panel` - show path link and HTTP verb in the middle panel instead of the right one
* `hide-loading` - do not show loading animation. Useful for small docs * `hide-loading` - do not show loading animation. Useful for small docs
* `native-scrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs)
## Advanced usage ## Advanced usage
Instead of adding `spec-url` attribute to the `<redoc>` element you can initialize ReDoc via globally exposed `Redoc` object: Instead of adding `spec-url` attribute to the `<redoc>` element you can initialize ReDoc via globally exposed `Redoc` object:

View File

@ -9,6 +9,7 @@ $mobile-menu-compact-breakpoint: 550px;
#resources-nav { #resources-nav {
position: relative; position: relative;
width: 100%; width: 100%;
overflow: scroll;
} }
ul.menu-root { ul.menu-root {

View File

@ -22,6 +22,7 @@ const OPTION_NAMES = new Set([
'untrustedSpec', 'untrustedSpec',
'hideLoading', 'hideLoading',
'ignoredHeaderParameters', 'ignoredHeaderParameters',
'nativeScrollbars',
]); ]);
export interface Options { export interface Options {
@ -40,6 +41,7 @@ export interface Options {
hideLoading?: boolean; hideLoading?: boolean;
spec?: any; spec?: any;
ignoredHeaderParameters?: string[]; ignoredHeaderParameters?: string[];
nativeScrollbars?: boolean;
} }
@Injectable() @Injectable()
@ -109,6 +111,8 @@ export class OptionsService {
if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true; if (isString(this._options.pathInMiddlePanel)) this._options.pathInMiddlePanel = true;
if (isString(this._options.untrustedSpec)) this._options.untrustedSpec = true; if (isString(this._options.untrustedSpec)) this._options.untrustedSpec = true;
if (isString(this._options.hideLoading)) this._options.hideLoading = true; if (isString(this._options.hideLoading)) this._options.hideLoading = true;
if (isString(this._options.nativeScrollbars))
this._options.nativeScrollbars = true;
if (isString(this._options.expandResponses)) { if (isString(this._options.expandResponses)) {
let str = this._options.expandResponses as string; let str = this._options.expandResponses as string;
if (str === 'all') return; if (str === 'all') return;

View File

@ -1,37 +1,49 @@
'use strict';
import 'perfect-scrollbar/dist/css/perfect-scrollbar.css'; import 'perfect-scrollbar/dist/css/perfect-scrollbar.css';
import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core'; import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { BrowserDomAdapter as DOM } from '../../../utils/browser-adapter';
import * as PS from 'perfect-scrollbar'; import * as PS from 'perfect-scrollbar';
import { OptionsService } from '../../../services/options.service';
@Directive({ @Directive({
selector: '[perfect-scrollbar]' selector: '[perfect-scrollbar]',
}) })
export class PerfectScrollbar implements OnInit, OnDestroy { export class PerfectScrollbar implements OnInit, OnDestroy {
$element: any; $element: any;
subscription: any; subscription: any;
enabled: boolean = true;
constructor(elementRef:ElementRef) { constructor(elementRef: ElementRef, optionsService: OptionsService) {
this.$element = elementRef.nativeElement; this.$element = elementRef.nativeElement;
this.enabled = !optionsService.options.nativeScrollbars;
} }
update() { update() {
if (!this.enabled) return;
PS.update(this.$element); PS.update(this.$element);
} }
ngOnInit() { ngOnInit() {
requestAnimationFrame(() => PS.initialize(this.$element, { if (!this.enabled) return;
requestAnimationFrame(() =>
PS.initialize(this.$element, {
wheelSpeed: 2, wheelSpeed: 2,
wheelPropagation: false, handlers: [
'click-rail',
'drag-scrollbar',
'keyboard',
'wheel',
'touch',
],
wheelPropagation: true,
minScrollbarLength: 20, minScrollbarLength: 20,
suppressScrollX: true suppressScrollX: true,
})); } as any),
);
} }
ngOnDestroy() { ngOnDestroy() {
if (!this.enabled) return;
PS.destroy(this.$element); PS.destroy(this.$element);
} }
} }