chore: rename api folder to composition

This commit is contained in:
chenjiahan
2020-08-26 15:32:30 +08:00
parent 216d326158
commit 2ec101f07b
22 changed files with 30 additions and 20 deletions
+21
View 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
View 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);
}
+13
View File
@@ -0,0 +1,13 @@
import { ref, Ref, watch } from 'vue';
export function useLazyRender(show: Ref<boolean>) {
const inited = ref(show.value);
watch(show, (value) => {
if (value) {
inited.value = value;
}
});
return inited;
}
+55
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);
}
};
}
+7
View File
@@ -0,0 +1,7 @@
import type { Ref } from 'vue';
export const useRect = (el: Ref<Element>) => el.value.getBoundingClientRect();
export const useWidth = (el: Ref<Element>) => useRect(el).width;
export const useHeight = (el: Ref<Element>) => useRect(el).height;
+27
View File
@@ -0,0 +1,27 @@
import { inject, computed, onUnmounted } from 'vue';
export type Parent<T = unknown> = null | {
children: T[];
};
export function useParent<T = unknown>(key: string, child: T = {} as T) {
const parent = inject<Parent<T>>(key, null);
if (parent) {
const { children } = parent;
const index = computed(() => children.indexOf(child));
children.push(child);
onUnmounted(() => {
children.splice(index.value, 1);
});
return {
index,
parent,
};
}
return {};
}
+56
View File
@@ -0,0 +1,56 @@
/**
* Vue Router support
*/
import { getCurrentInstance } from 'vue';
import type { Router, RouteLocation } from 'vue-router';
export type RouteConfig = {
url?: string;
to?: RouteLocation;
replace?: boolean;
};
function isRedundantNavigation(err: Error) {
return (
err.name === 'NavigationDuplicated' ||
// compatible with vue-router@3.3
(err.message && err.message.indexOf('redundant navigation') !== -1)
);
}
export function route(router: Router, props: RouteProps) {
const { to, url, replace } = props;
if (to && router) {
const promise = router[replace ? 'replace' : 'push'](to);
/* istanbul ignore else */
if (promise && promise.catch) {
promise.catch((err) => {
if (err && !isRedundantNavigation(err)) {
throw err;
}
});
}
} else if (url) {
replace ? location.replace(url) : (location.href = url);
}
}
export function useRoute() {
const vm = getCurrentInstance()!.proxy!;
return () => {
route(vm.$router, vm as RouteProps);
};
}
export type RouteProps = {
url?: string;
replace?: boolean;
to?: RouteLocation;
};
export const routeProps = {
url: String,
replace: Boolean,
to: [String, Object],
};
+10
View File
@@ -0,0 +1,10 @@
import { ref } from 'vue';
export function useToggle(defaultValue = false) {
const state = ref(defaultValue);
const setState = (value: boolean) => {
state.value = value;
};
return [state, setState];
}
+63
View 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 - startX.value;
deltaY.value = touch.clientY - startY.value;
offsetX.value = Math.abs(deltaX.value);
offsetY.value = Math.abs(deltaY.value);
if (!direction.value) {
direction.value = getDirection(offsetX.value, offsetY.value);
}
}
return {
move,
start,
startX,
startY,
deltaX,
deltaY,
offsetX,
offsetY,
direction,
};
}