init
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "NextIcon",
|
||||
};
|
||||
</script>
|
||||
<script setup lang="ts">
|
||||
import LayIcon from "../component/icon/index";
|
||||
|
||||
const props = defineProps<{
|
||||
color?: string;
|
||||
size?: string;
|
||||
}>();
|
||||
</script>
|
||||
<template>
|
||||
<lay-icon :color="props.color" :size="props.size" type="layui-icon-next" />
|
||||
</template>
|
||||
@@ -0,0 +1,72 @@
|
||||
import { w as withInstall } from "../badge/index2.js";
|
||||
import { defineComponent, useSlots, computed, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, renderSlot, createCommentVNode } from "vue";
|
||||
var index = /* @__PURE__ */ (() => ".layui-line-horizontal{position:relative;clear:both;width:100%;min-width:100%;max-width:100%;margin:var(--layui-line-margin) 0;border-bottom:var(--layui-line-border-width) var(--layui-line-border-style) var(--global-neutral-color-5);border-top-style:none;border-left-style:none;border-right-style:none}.layui-line-horizontal.layui-line-with-text{margin:14px 0}.layui-line-vertical{display:inline-block;min-width:1px;max-width:1px;height:1em;margin:0 var(--layui-line-margin);vertical-align:middle;border-left:var(--layui-line-border-width) var(--layui-line-border-style) var(--global-neutral-color-5);border-top-style:none;border-bottom-style:none;border-right-style:none}.layui-line-text{position:absolute;top:50%;box-sizing:border-box;padding:0 10px;color:currentColor;line-height:2;background-color:#fff;transform:translateY(-50%)}.layui-line-text-center{left:var(--layui-line-text-offset);transform:translate(-50%,-50%)}.layui-line-text-left{left:var(--layui-line-text-offset)}.layui-line-text-right{right:var(--layui-line-text-offset)}\n")();
|
||||
const __default__ = {
|
||||
name: "LayLine"
|
||||
};
|
||||
const _sfc_main = defineComponent({
|
||||
...__default__,
|
||||
props: {
|
||||
direction: { default: "horizontal" },
|
||||
contentPosition: { default: "center" },
|
||||
borderWidth: { default: "1px" },
|
||||
borderStyle: { default: "solid" },
|
||||
offset: { default: "25px" },
|
||||
theme: null,
|
||||
margin: { default: "8px" }
|
||||
},
|
||||
setup(__props) {
|
||||
var _a;
|
||||
const props = __props;
|
||||
const slots = useSlots();
|
||||
const lineTheme = [
|
||||
"red",
|
||||
"orange",
|
||||
"green",
|
||||
"cyan",
|
||||
"blue",
|
||||
"black",
|
||||
"gray"
|
||||
];
|
||||
const isBuiltInColor = lineTheme.includes((_a = props.theme) != null ? _a : "");
|
||||
const lineClass = computed(() => [
|
||||
`layui-line-${props.direction}`,
|
||||
{
|
||||
[`layui-border-${props.theme}`]: isBuiltInColor,
|
||||
[`layui-line-with-text`]: Boolean(slots.default)
|
||||
}
|
||||
]);
|
||||
const lineStyle = computed(() => ({
|
||||
"border-color": !isBuiltInColor ? props.theme : void 0,
|
||||
"--layui-line-border-width": props.borderWidth,
|
||||
"--layui-line-border-style": props.borderStyle,
|
||||
"--layui-line-margin": props.margin
|
||||
}));
|
||||
const lineTextStyle = computed(() => ({
|
||||
"--layui-line-text-offset": props.contentPosition != "center" ? props.offset : "50%",
|
||||
transform: calcTranslate()
|
||||
}));
|
||||
function calcTranslate() {
|
||||
if (props.offset.includes("%")) {
|
||||
return props.contentPosition === "right" ? "translate(50%, -50%)" : "translate(-50%, -50%)";
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
return (_ctx, _cache) => {
|
||||
return openBlock(), createElementBlock("div", {
|
||||
class: normalizeClass(unref(lineClass)),
|
||||
style: normalizeStyle(unref(lineStyle))
|
||||
}, [
|
||||
_ctx.$slots.default && __props.direction === "horizontal" ? (openBlock(), createElementBlock("span", {
|
||||
key: 0,
|
||||
class: normalizeClass([`layui-line-text layui-line-text-${__props.contentPosition}`]),
|
||||
style: normalizeStyle(unref(lineTextStyle))
|
||||
}, [
|
||||
renderSlot(_ctx.$slots, "default")
|
||||
], 6)) : createCommentVNode("", true)
|
||||
], 6);
|
||||
};
|
||||
}
|
||||
});
|
||||
const component = withInstall(_sfc_main);
|
||||
export { component as default };
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 321 B |
@@ -0,0 +1,223 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayBacktop",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
ref,
|
||||
shallowRef,
|
||||
withDefaults,
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
} from "vue";
|
||||
import { LayIcon } from "@layui/icons-vue";
|
||||
import "./index.less";
|
||||
|
||||
export interface BackTopProps {
|
||||
target?: string;
|
||||
showHeight?: number;
|
||||
disabled?: boolean;
|
||||
position?: "fixed" | "absolute";
|
||||
right?: number;
|
||||
bottom?: number;
|
||||
size?: "medium" | "small";
|
||||
bgcolor?: string;
|
||||
opacity?: number;
|
||||
color?: string;
|
||||
borderRadius?: number | string;
|
||||
circle?: boolean;
|
||||
icon?: string;
|
||||
iconSize?: number;
|
||||
iconColor?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<BackTopProps>(), {
|
||||
target: "window",
|
||||
showHeight: 200,
|
||||
icon: "layui-icon-top",
|
||||
iconSize: 30,
|
||||
disabled: false,
|
||||
circle: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["click"]);
|
||||
|
||||
const backtopRef = ref<HTMLElement | null>(null);
|
||||
const scrollTarget = shallowRef<Window | HTMLElement | undefined>(undefined);
|
||||
let visible = ref(props.showHeight === 0);
|
||||
|
||||
const classBacktop = computed(() => {
|
||||
return {
|
||||
"layui-backtop-medium": props.size === "medium",
|
||||
"layui-backtop-small": props.size === "small",
|
||||
};
|
||||
});
|
||||
|
||||
const borderRadius = computed(() => {
|
||||
if (props.circle) {
|
||||
return "50%";
|
||||
}
|
||||
return typeof props.borderRadius === "number"
|
||||
? `${props.borderRadius}px`
|
||||
: props.borderRadius;
|
||||
});
|
||||
|
||||
const styleBacktop = computed(() => {
|
||||
return {
|
||||
position: props.position,
|
||||
right: `${props.right}px`,
|
||||
bottom: `${props.bottom}px`,
|
||||
backgroundColor: props.bgcolor,
|
||||
opacity: props.opacity,
|
||||
color: props.color,
|
||||
borderRadius: borderRadius.value,
|
||||
};
|
||||
});
|
||||
|
||||
// TODO 待改进
|
||||
const easeInOut = (value: number): number => {
|
||||
return value < 0.5 ? 2 * value * value : 1 - 2 * (value - 1) * (value - 1);
|
||||
};
|
||||
|
||||
const scrollToTop = () => {
|
||||
if (!scrollTarget.value) return;
|
||||
if (scrollTarget.value instanceof Window) {
|
||||
window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); // smooth | instant(default)
|
||||
} else {
|
||||
const previous: number = Date.now();
|
||||
const scrollHeight: number = scrollTarget.value.scrollTop;
|
||||
const animationFunc = () => {
|
||||
if (!scrollTarget.value || scrollTarget.value instanceof Window) return;
|
||||
const elapsed = (Date.now() - previous) / 450;
|
||||
if (elapsed < 1) {
|
||||
scrollTarget.value.scrollTop = scrollHeight * (1 - easeInOut(elapsed));
|
||||
window.requestAnimationFrame(animationFunc);
|
||||
} else {
|
||||
scrollTarget.value.scrollTop = 0;
|
||||
}
|
||||
};
|
||||
window.requestAnimationFrame(animationFunc);
|
||||
}
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
if (!scrollTarget.value) return;
|
||||
const scrollTop =
|
||||
scrollTarget.value instanceof Window
|
||||
? window.pageYOffset
|
||||
: scrollTarget.value.scrollTop;
|
||||
visible.value = scrollTop >= props.showHeight;
|
||||
};
|
||||
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
if (!props.disabled) {
|
||||
scrollToTop();
|
||||
}
|
||||
emit("click", event);
|
||||
};
|
||||
|
||||
const handlerMousedown = () => {
|
||||
backtopRef.value!.style.opacity = "1";
|
||||
};
|
||||
|
||||
const handlerMouseup = () => {
|
||||
backtopRef.value!.style.opacity = "0.95";
|
||||
};
|
||||
|
||||
// 获取滚动目标元素
|
||||
const getScrollTarget = () => {
|
||||
if (props.target === "window") {
|
||||
// @ts-ignore
|
||||
return getScrollParent(backtopRef.value!, false);
|
||||
} else {
|
||||
const targetElement = document.querySelector<HTMLElement>(props.target);
|
||||
if (!targetElement) {
|
||||
throw new Error(`target is not existed: ${props.target}`);
|
||||
}
|
||||
// 特定容器内部显示
|
||||
if (props.position === "absolute") {
|
||||
if (!targetElement.parentElement) {
|
||||
throw new Error(
|
||||
`target parent element is not existed: ${props.target}`
|
||||
);
|
||||
}
|
||||
targetElement.parentElement.style.position = "relative";
|
||||
// backtopRef.value!.style.position = props.position;
|
||||
}
|
||||
return targetElement;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取距离元素最近的可滚动祖先元素
|
||||
const getScrollParent = (
|
||||
element: HTMLElement,
|
||||
includeHidden: boolean
|
||||
): HTMLElement => {
|
||||
let style: CSSStyleDeclaration = getComputedStyle(element);
|
||||
let excludeStaticParent: boolean = style.position === "absolute";
|
||||
let overflowRegex: RegExp = includeHidden
|
||||
? /(auto|scroll|hidden)/
|
||||
: /(auto|scroll)/;
|
||||
//if (style.position === "fixed") return document.documentElement || document.body || window;
|
||||
for (let parent: HTMLElement = element; (parent = parent.parentElement!); ) {
|
||||
style = getComputedStyle(parent);
|
||||
if (excludeStaticParent && style.position === "static") {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
overflowRegex.test(style.overflow + style.overflowY + style.overflowX)
|
||||
) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
return window;
|
||||
};
|
||||
|
||||
// 节流
|
||||
const throttle = (func: Function, wait: number) => {
|
||||
var timer: any = null;
|
||||
return (...args: any) => {
|
||||
if (!timer) {
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
func.apply(this, args);
|
||||
}, wait);
|
||||
}
|
||||
};
|
||||
};
|
||||
const callback = throttle(handleScroll, 300);
|
||||
onMounted(() => {
|
||||
if (!props.target) return;
|
||||
scrollTarget.value = getScrollTarget();
|
||||
scrollTarget.value.addEventListener("scroll", callback);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
scrollTarget.value?.removeEventListener("scroll", callback);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-show="visible"
|
||||
ref="backtopRef"
|
||||
class="layui-backtop"
|
||||
:class="classBacktop"
|
||||
:style="{ ...styleBacktop }"
|
||||
@click.stop="handleClick"
|
||||
@mousedown="handlerMousedown"
|
||||
@mouseup="handlerMouseup"
|
||||
>
|
||||
<slot>
|
||||
<lay-icon
|
||||
:type="props.icon"
|
||||
:size="`${props.iconSize}px`"
|
||||
:color="props.iconColor"
|
||||
/>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,163 @@
|
||||
import { w as withInstall } from "../badge/index2.js";
|
||||
import { defineComponent, ref, computed, onMounted, onBeforeUnmount, renderSlot } from "vue";
|
||||
var index = /* @__PURE__ */ (() => ".layui-fullscreen{top:0;left:0;width:100%;height:100%;position:fixed;overflow:auto;z-index:10}\n")();
|
||||
const __default__ = {
|
||||
name: "LayFullscreen"
|
||||
};
|
||||
const _sfc_main = defineComponent({
|
||||
...__default__,
|
||||
props: {
|
||||
target: null,
|
||||
immersive: { type: Boolean, default: true },
|
||||
position: null,
|
||||
zIndex: null
|
||||
},
|
||||
emits: ["fullscreenchange"],
|
||||
setup(__props, { emit }) {
|
||||
const props = __props;
|
||||
const methodMap = [
|
||||
[
|
||||
"requestFullscreen",
|
||||
"exitFullscreen",
|
||||
"fullscreenElement",
|
||||
"fullscreenEnabled",
|
||||
"fullscreenchange",
|
||||
"fullscreenerror"
|
||||
],
|
||||
[
|
||||
"webkitRequestFullscreen",
|
||||
"webkitExitFullscreen",
|
||||
"webkitFullscreenElement",
|
||||
"webkitFullscreenEnabled",
|
||||
"webkitfullscreenchange",
|
||||
"webkitfullscreenerror"
|
||||
],
|
||||
[
|
||||
"webkitRequestFullScreen",
|
||||
"webkitCancelFullScreen",
|
||||
"webkitCurrentFullScreenElement",
|
||||
"webkitCancelFullScreen",
|
||||
"webkitfullscreenchange",
|
||||
"webkitfullscreenerror"
|
||||
],
|
||||
[
|
||||
"mozRequestFullScreen",
|
||||
"mozCancelFullScreen",
|
||||
"mozFullScreenElement",
|
||||
"mozFullScreenEnabled",
|
||||
"mozfullscreenchange",
|
||||
"mozfullscreenerror"
|
||||
],
|
||||
[
|
||||
"msRequestFullscreen",
|
||||
"msExitFullscreen",
|
||||
"msFullscreenElement",
|
||||
"msFullscreenEnabled",
|
||||
"MSFullscreenChange",
|
||||
"MSFullscreenError"
|
||||
]
|
||||
];
|
||||
const defaultElement = document.documentElement;
|
||||
let targetEl = ref(props.target || defaultElement);
|
||||
const isFullscreen = ref(false);
|
||||
let isSupported = false;
|
||||
const unprefixedMethods = methodMap[0];
|
||||
const fullscreenAPI = {};
|
||||
for (const methodList of methodMap) {
|
||||
if (methodList[1] in document) {
|
||||
for (const [index2, method] of methodList.entries()) {
|
||||
fullscreenAPI[unprefixedMethods[index2]] = method;
|
||||
}
|
||||
isSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
async function enter(targetEl2) {
|
||||
if (!isSupported)
|
||||
return;
|
||||
if (!targetEl2)
|
||||
targetEl2 = activeEl.value || defaultElement;
|
||||
let fullscreenEnter = null;
|
||||
if (props.immersive) {
|
||||
fullscreenEnter = Promise.resolve(targetEl2[fullscreenAPI.requestFullscreen]());
|
||||
} else {
|
||||
styleLayFullscreen(targetEl2, false);
|
||||
fullscreenEnter = Promise.resolve(targetEl2 == null ? void 0 : targetEl2.classList.add("layui-fullscreen"));
|
||||
}
|
||||
return await (fullscreenEnter == null ? void 0 : fullscreenEnter.then(() => {
|
||||
isFullscreen.value = true;
|
||||
emit("fullscreenchange", isFullscreen.value);
|
||||
return !!document.fullscreenElement;
|
||||
}));
|
||||
}
|
||||
async function exit(targetEl2) {
|
||||
if (!isSupported)
|
||||
return;
|
||||
if (!targetEl2)
|
||||
targetEl2 = activeEl.value || document;
|
||||
let fullscreenExit = null;
|
||||
if (props.immersive) {
|
||||
fullscreenExit = Promise.resolve(document[fullscreenAPI.exitFullscreen]());
|
||||
} else {
|
||||
if (targetEl2 instanceof Document)
|
||||
return;
|
||||
styleLayFullscreen(targetEl2, true);
|
||||
fullscreenExit = Promise.resolve(targetEl2 == null ? void 0 : targetEl2.classList.remove("layui-fullscreen"));
|
||||
}
|
||||
return await (fullscreenExit == null ? void 0 : fullscreenExit.then(() => {
|
||||
isFullscreen.value = false;
|
||||
emit("fullscreenchange", isFullscreen.value);
|
||||
return !!document.fullscreenElement;
|
||||
}));
|
||||
}
|
||||
async function toggle() {
|
||||
if (isFullscreen.value) {
|
||||
await exit(activeEl.value);
|
||||
} else {
|
||||
await enter(activeEl.value);
|
||||
}
|
||||
}
|
||||
const styleLayFullscreen = function(el, isRemove = false) {
|
||||
el.style.position = isRemove ? "" : props.position || "";
|
||||
el.style.zIndex = isRemove ? "" : props.zIndex || "";
|
||||
};
|
||||
const activeEl = computed(() => targetEl.value = props.target);
|
||||
const onFullscreenchange = function(event) {
|
||||
if (isFullscreen.value && !document.fullscreenElement) {
|
||||
if (props.immersive) {
|
||||
isFullscreen.value = false;
|
||||
emit("fullscreenchange", isFullscreen.value);
|
||||
} else if (event.key === "Escape") {
|
||||
exit(activeEl.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
const onKeydownF11 = function(event) {
|
||||
let isRootNodeFullscreen = props.immersive && (!activeEl.value || activeEl.value === defaultElement);
|
||||
if (event.key === "F11" && isRootNodeFullscreen) {
|
||||
event.preventDefault();
|
||||
toggle();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
document.addEventListener(fullscreenAPI.fullscreenchange, onFullscreenchange);
|
||||
document.addEventListener("keydown", onFullscreenchange);
|
||||
document.addEventListener("keydown", onKeydownF11);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener(fullscreenAPI.fullscreenchange, onFullscreenchange);
|
||||
document.removeEventListener("keydown", onFullscreenchange);
|
||||
document.removeEventListener("keydown", onKeydownF11);
|
||||
});
|
||||
return (_ctx, _cache) => {
|
||||
return renderSlot(_ctx.$slots, "default", {
|
||||
isFullscreen: isFullscreen.value,
|
||||
enter,
|
||||
exit,
|
||||
toggle
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
const component = withInstall(_sfc_main);
|
||||
export { component as default };
|
||||
Binary file not shown.
Reference in New Issue
Block a user