mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
Merge branch 'next' of https://github.com/youzan/vant into dev
This commit is contained in:
commit
c40d2cc636
@ -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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
21
src/hooks/use-click-outside.ts
Normal file
21
src/hooks/use-click-outside.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Ref } from 'vue';
|
||||||
|
import { useGlobalEvent } from './use-global-event';
|
||||||
|
|
||||||
|
export type UseClickOutsideOpitons = {
|
||||||
|
event: string;
|
||||||
|
callback: EventListener;
|
||||||
|
element: Ref<Element>;
|
||||||
|
flag?: Ref<boolean>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useClickOutside(options: UseClickOutsideOpitons) {
|
||||||
|
const { event = 'click', callback, element, flag } = options;
|
||||||
|
|
||||||
|
function onClick(event: Event) {
|
||||||
|
if (!element.value.contains(event.target as Node)) {
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useGlobalEvent(document, event, onClick, false, flag);
|
||||||
|
}
|
46
src/hooks/use-global-event.ts
Normal file
46
src/hooks/use-global-event.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { on, off } from '../utils/dom/event';
|
||||||
|
import {
|
||||||
|
Ref,
|
||||||
|
watch,
|
||||||
|
onMounted,
|
||||||
|
onActivated,
|
||||||
|
onUnmounted,
|
||||||
|
onDeactivated
|
||||||
|
} from 'vue';
|
||||||
|
|
||||||
|
export function useGlobalEvent(
|
||||||
|
target: EventTarget,
|
||||||
|
event: string,
|
||||||
|
handler: EventListener,
|
||||||
|
passive = false,
|
||||||
|
flag?: Ref<boolean>
|
||||||
|
) {
|
||||||
|
let binded: boolean;
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
if (binded || (flag && !flag.value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
on(target, event, handler, passive);
|
||||||
|
binded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove() {
|
||||||
|
if (binded) {
|
||||||
|
off(target, event, handler);
|
||||||
|
binded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
watch(() => {
|
||||||
|
flag.value ? add() : remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(add);
|
||||||
|
onActivated(add);
|
||||||
|
onUnmounted(remove);
|
||||||
|
onDeactivated(remove);
|
||||||
|
}
|
55
src/hooks/use-lock-scroll.ts
Normal file
55
src/hooks/use-lock-scroll.ts
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
63
src/hooks/use-touch.ts
Normal file
63
src/hooks/use-touch.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const MIN_DISTANCE = 10;
|
||||||
|
|
||||||
|
function getDirection(x: number, y: number) {
|
||||||
|
if (x > y && x > MIN_DISTANCE) {
|
||||||
|
return 'horizontal';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y > x && y > MIN_DISTANCE) {
|
||||||
|
return 'vertical';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTouch() {
|
||||||
|
const startX = ref(0);
|
||||||
|
const startY = ref(0);
|
||||||
|
const deltaX = ref(0);
|
||||||
|
const deltaY = ref(0);
|
||||||
|
const offsetX = ref(0);
|
||||||
|
const offsetY = ref(0);
|
||||||
|
const direction = ref('');
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
direction.value = '';
|
||||||
|
deltaX.value = 0;
|
||||||
|
deltaY.value = 0;
|
||||||
|
offsetX.value = 0;
|
||||||
|
offsetY.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function start(event: TouchEvent) {
|
||||||
|
reset();
|
||||||
|
startX.value = event.touches[0].clientX;
|
||||||
|
startY.value = event.touches[0].clientY;
|
||||||
|
}
|
||||||
|
|
||||||
|
function move(event: TouchEvent) {
|
||||||
|
const touch = event.touches[0];
|
||||||
|
deltaX.value = touch.clientX - this.startX;
|
||||||
|
deltaY.value = touch.clientY - this.startY;
|
||||||
|
offsetX.value = Math.abs(this.deltaX);
|
||||||
|
offsetY.value = Math.abs(this.deltaY);
|
||||||
|
|
||||||
|
if (!direction.value) {
|
||||||
|
direction.value = getDirection(offsetX.value, offsetY.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
move,
|
||||||
|
start,
|
||||||
|
startX,
|
||||||
|
startY,
|
||||||
|
deltaX,
|
||||||
|
deltaY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
direction
|
||||||
|
};
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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: {
|
||||||
|
@ -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);
|
||||||
|
@ -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 &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user