feat: add use-lock-scroll hook

This commit is contained in:
陈嘉涵 2020-01-13 16:37:27 +08:00
parent 0dfce17f6c
commit d9d63959f5
8 changed files with 68 additions and 13 deletions

View File

@ -2,7 +2,7 @@ import { createNamespace } from '../utils';
import { BORDER_TOP_BOTTOM } from '../utils/constant'; import { BORDER_TOP_BOTTOM } from '../utils/constant';
import { ParentMixin } from '../mixins/relation'; import { ParentMixin } from '../mixins/relation';
import { ClickOutsideMixin } from '../mixins/click-outside'; import { ClickOutsideMixin } from '../mixins/click-outside';
import { getScrollEventTarget } from '../utils/dom/scroll'; import { getScroller } from '../utils/dom/scroll';
const [createComponent, bem] = createNamespace('dropdown-menu'); const [createComponent, bem] = createNamespace('dropdown-menu');
@ -47,7 +47,7 @@ export default createComponent({
computed: { computed: {
scroller() { scroller() {
return getScrollEventTarget(this.$el); return getScroller(this.$el);
} }
}, },

View File

@ -0,0 +1,55 @@
import { useTouch } from './use-touch';
import { getScroller } from '../utils/dom/scroll';
import { on, off, preventDefault } from '../utils/dom/event';
let count = 0;
const CLASSNAME = 'van-overflow-hidden';
export function useLockScroll(element: HTMLElement) {
const { start, move, deltaY, direction } = useTouch();
function onTouchMove(event: TouchEvent) {
move(event);
if (direction.value !== 'vertical') {
return;
}
let prevent = false;
const up = deltaY.value < 0;
const scroller = getScroller(event.target as HTMLElement, element);
const { scrollTop, scrollHeight, offsetHeight } = scroller as HTMLElement;
if (scrollTop === 0) {
prevent = up && offsetHeight < scrollHeight;
} else if (scrollTop + offsetHeight >= scrollHeight) {
prevent = !up;
}
if (prevent) {
preventDefault(event, true);
}
}
function lock() {
if (!count) {
document.body.classList.add(CLASSNAME);
}
count++;
on(document, 'touchstart', start);
on(document, 'touchmove', onTouchMove);
}
lock();
return function unlock() {
count--;
off(document, 'touchstart', start);
off(document, 'touchmove', onTouchMove);
if (!count) {
document.body.classList.remove(CLASSNAME);
}
};
}

View File

@ -10,7 +10,7 @@ import {
getElementTop, getElementTop,
getRootScrollTop, getRootScrollTop,
setRootScrollTop, setRootScrollTop,
getScrollEventTarget getScroller
} from '../utils/dom/scroll'; } from '../utils/dom/scroll';
const [createComponent, bem] = createNamespace('index-bar'); const [createComponent, bem] = createNamespace('index-bar');
@ -21,7 +21,7 @@ export default createComponent({
ParentMixin('vanIndexBar'), ParentMixin('vanIndexBar'),
BindEventMixin(function(bind) { BindEventMixin(function(bind) {
if (!this.scroller) { if (!this.scroller) {
this.scroller = getScrollEventTarget(this.$el); this.scroller = getScroller(this.$el);
} }
bind(this.scroller, 'scroll', this.onScroll); bind(this.scroller, 'scroll', this.onScroll);

View File

@ -1,7 +1,7 @@
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
import { isHidden } from '../utils/dom/style'; import { isHidden } from '../utils/dom/style';
import { BindEventMixin } from '../mixins/bind-event'; import { BindEventMixin } from '../mixins/bind-event';
import { getScrollEventTarget } from '../utils/dom/scroll'; import { getScroller } from '../utils/dom/scroll';
import Loading from '../loading'; import Loading from '../loading';
const [createComponent, bem, t] = createNamespace('list'); const [createComponent, bem, t] = createNamespace('list');
@ -10,7 +10,7 @@ export default createComponent({
mixins: [ mixins: [
BindEventMixin(function(bind) { BindEventMixin(function(bind) {
if (!this.scroller) { if (!this.scroller) {
this.scroller = getScrollEventTarget(this.$el); this.scroller = getScroller(this.$el);
} }
bind(this.scroller, 'scroll', this.check); bind(this.scroller, 'scroll', this.check);

View File

@ -4,7 +4,7 @@ import { PortalMixin } from '../portal';
import { CloseOnPopstateMixin } from '../close-on-popstate'; import { CloseOnPopstateMixin } from '../close-on-popstate';
import { on, off, preventDefault } from '../../utils/dom/event'; import { on, off, preventDefault } from '../../utils/dom/event';
import { openOverlay, closeOverlay, updateOverlay } from './overlay'; import { openOverlay, closeOverlay, updateOverlay } from './overlay';
import { getScrollEventTarget } from '../../utils/dom/scroll'; import { getScroller } from '../../utils/dom/scroll';
export const popupMixinProps = { export const popupMixinProps = {
// whether to show popup // whether to show popup
@ -152,7 +152,7 @@ export function PopupMixin(options = {}) {
onTouchMove(event) { onTouchMove(event) {
this.touchMove(event); this.touchMove(event);
const direction = this.deltaY > 0 ? '10' : '01'; const direction = this.deltaY > 0 ? '10' : '01';
const el = getScrollEventTarget(event.target, this.$el); const el = getScroller(event.target, this.$el);
const { scrollHeight, offsetHeight, scrollTop } = el; const { scrollHeight, offsetHeight, scrollTop } = el;
let status = '11'; let status = '11';

View File

@ -1,7 +1,7 @@
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
import { preventDefault } from '../utils/dom/event'; import { preventDefault } from '../utils/dom/event';
import { TouchMixin } from '../mixins/touch'; import { TouchMixin } from '../mixins/touch';
import { getScrollTop, getScrollEventTarget } from '../utils/dom/scroll'; import { getScrollTop, getScroller } from '../utils/dom/scroll';
import Loading from '../loading'; import Loading from '../loading';
const [createComponent, bem, t] = createNamespace('pull-refresh'); const [createComponent, bem, t] = createNamespace('pull-refresh');
@ -76,7 +76,7 @@ export default createComponent({
mounted() { mounted() {
this.bindTouchEvent(this.$refs.track); this.bindTouchEvent(this.$refs.track);
this.scrollEl = getScrollEventTarget(this.$el); this.scrollEl = getScroller(this.$el);
}, },
methods: { methods: {

View File

@ -1,6 +1,6 @@
import { createNamespace, isDef } from '../utils'; import { createNamespace, isDef } from '../utils';
import { BindEventMixin } from '../mixins/bind-event'; import { BindEventMixin } from '../mixins/bind-event';
import { getScrollTop, getElementTop, getScrollEventTarget } from '../utils/dom/scroll'; import { getScrollTop, getElementTop, getScroller } from '../utils/dom/scroll';
const [createComponent, bem] = createNamespace('sticky'); const [createComponent, bem] = createNamespace('sticky');
@ -8,7 +8,7 @@ export default createComponent({
mixins: [ mixins: [
BindEventMixin(function(bind) { BindEventMixin(function(bind) {
if (!this.scroller) { if (!this.scroller) {
this.scroller = getScrollEventTarget(this.$el); this.scroller = getScroller(this.$el);
} }
bind(this.scroller, 'scroll', this.onScroll, true); bind(this.scroller, 'scroll', this.onScroll, true);

View File

@ -4,7 +4,7 @@ type ScrollElement = HTMLElement | Window;
// http://w3help.org/zh-cn/causes/SD9013 // http://w3help.org/zh-cn/causes/SD9013
// http://stackoverflow.com/questions/17016740/onscroll-function-is-not-working-for-chrome // http://stackoverflow.com/questions/17016740/onscroll-function-is-not-working-for-chrome
const overflowScrollReg = /scroll|auto/i; const overflowScrollReg = /scroll|auto/i;
export function getScrollEventTarget(element: HTMLElement, rootParent: ScrollElement = window) { export function getScroller(element: HTMLElement, rootParent: ScrollElement = window) {
let node = element; let node = element;
while ( while (
node && node &&