Merge branch 'develop' of gitee.com:layui-vue/layui-vue into develop
This commit is contained in:
@@ -5,7 +5,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, shallowRef, withDefaults, computed, onMounted } from "vue";
|
||||
import {
|
||||
ref,
|
||||
shallowRef,
|
||||
withDefaults,
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
} from "vue";
|
||||
import { useThrottle } from "@vueuse/core";
|
||||
import LayIcon from "../icon/index";
|
||||
import "./index.less";
|
||||
|
||||
@@ -186,6 +194,13 @@ onMounted(() => {
|
||||
scrollTarget.value = getScrollTarget();
|
||||
scrollTarget.value.addEventListener("scroll", throttle(handleScroll, 300));
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
scrollTarget.value?.removeEventListener(
|
||||
"scroll",
|
||||
throttle(handleScroll, 300)
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
|
||||
.layui-btn-primary {
|
||||
border-color: @global-neutral-color-3;
|
||||
border-color: @button-border-color;
|
||||
background: 0 0;
|
||||
color: #666;
|
||||
}
|
||||
@@ -113,4 +113,4 @@
|
||||
color: #d2d2d2 !important;
|
||||
cursor: not-allowed !important;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,3 @@
|
||||
<template>
|
||||
<slot name="prefix"></slot>
|
||||
<span ref="counterRef" style="font-family: sans-serif" />
|
||||
<slot name="suffix"></slot>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayCountUp",
|
||||
@@ -11,77 +5,103 @@ export default {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { CountUp } from "countup.js";
|
||||
import type { CountUpOptions } from "countup.js";
|
||||
import { computed, onMounted, Ref, ref, watch } from "vue";
|
||||
import { TransitionPresets, useTransition } from "@vueuse/core";
|
||||
|
||||
export interface LayCountupProps {
|
||||
startVal?: number; // 起始值
|
||||
endVal?: number; //显示的值
|
||||
decimal?: string; // 小数点
|
||||
decimalPlaces?: number; // 小数位数
|
||||
useGrouping?: boolean; // 是否使用千位分隔符
|
||||
separator?: string; // 千位分隔符
|
||||
autoplay?: boolean; //是否自动播放
|
||||
useEasing?: boolean; // 使用动画
|
||||
easingFn?: any; //动画类型
|
||||
duration?: number; // 动画持续时间
|
||||
prefix?: string; // 前缀
|
||||
suffix?: string; // 后缀
|
||||
option?: CountUpOptions; // 选项
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<LayCountupProps>(), {
|
||||
startVal: 0,
|
||||
endVal: 0,
|
||||
option: () => {
|
||||
return {};
|
||||
},
|
||||
decimal: ".",
|
||||
decimalPlaces: 0,
|
||||
useGrouping: true,
|
||||
separator: ",",
|
||||
autoplay: true,
|
||||
useEasing: true,
|
||||
easingFn: TransitionPresets.easeInOutCubic,
|
||||
duration: 2000,
|
||||
prefix: "",
|
||||
suffix: "",
|
||||
});
|
||||
|
||||
const counterRef = ref<HTMLDivElement | null>(null);
|
||||
const instance = ref<CountUp | null>(null);
|
||||
const {
|
||||
decimalPlaces,
|
||||
useGrouping,
|
||||
separator,
|
||||
useEasing,
|
||||
duration,
|
||||
prefix,
|
||||
suffix,
|
||||
} = props;
|
||||
const defaultOptions: CountUpOptions = {
|
||||
startVal: 0, // 开始数字
|
||||
decimalPlaces: decimalPlaces ? decimalPlaces : 0, // 小数位数
|
||||
useEasing: useEasing ? useEasing : true, // 使用缓动动画
|
||||
duration: duration ? duration : 2, // 动画持续时间
|
||||
useGrouping: useGrouping ? useGrouping : true, // 是否使用千位分隔符
|
||||
separator: separator ? separator : ",", // 千位分隔符
|
||||
decimal: ".", // 小数点分隔符
|
||||
prefix: prefix ? prefix : "", // 前缀
|
||||
suffix: suffix ? suffix : "", // 后缀
|
||||
let localStartVal: Ref<number> = ref(props.startVal);
|
||||
const isNumber = (val: string) => !isNaN(parseFloat(val));
|
||||
|
||||
/**
|
||||
* from: https://github.com/PanJiaChen/vue-countTo/blob/master/src/vue-countTo.vue
|
||||
* @description 格式化数字
|
||||
* @param num 要格式化的数字
|
||||
* @returns 格式化后的数字
|
||||
*/
|
||||
const formatNumber = (num: number | string): string => {
|
||||
if (typeof num != "number") return "0";
|
||||
num = num.toFixed(props.decimalPlaces);
|
||||
num += "";
|
||||
const x = num.split(".");
|
||||
let x1 = x[0];
|
||||
const x2 = x.length > 1 ? props.decimal + x[1] : "";
|
||||
const rgx = /(\d+)(\d{3})/;
|
||||
if (props.separator && !isNumber(props.separator)) {
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, "$1" + props.separator + "$2");
|
||||
}
|
||||
}
|
||||
return props.prefix + x1 + x2 + props.suffix;
|
||||
};
|
||||
|
||||
const printVal = useTransition(localStartVal, {
|
||||
delay: 0,
|
||||
duration: props.duration,
|
||||
disabled: !props.useEasing,
|
||||
transition:
|
||||
typeof props.easingFn === "string"
|
||||
? TransitionPresets[props.easingFn]
|
||||
: props.easingFn,
|
||||
});
|
||||
|
||||
const displayValue = computed(() => formatNumber(printVal.value));
|
||||
|
||||
const start = function () {
|
||||
localStartVal.value = props.endVal;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.endVal,
|
||||
() => {
|
||||
update(props.endVal);
|
||||
if (props.autoplay) {
|
||||
localStartVal.value = props.endVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
createCounter();
|
||||
if (props.autoplay) {
|
||||
start();
|
||||
}
|
||||
});
|
||||
|
||||
const createCounter = () => {
|
||||
if (!counterRef.value) return;
|
||||
const opts: CountUpOptions = Object.assign(defaultOptions, props.option);
|
||||
instance.value = new CountUp(counterRef?.value, props.endVal, opts);
|
||||
start();
|
||||
};
|
||||
|
||||
const start = () => {
|
||||
if (!instance.value) return;
|
||||
instance?.value.start();
|
||||
};
|
||||
|
||||
const update = (newEndVal: number) => {
|
||||
if (!instance.value) return;
|
||||
instance?.value.update(newEndVal);
|
||||
};
|
||||
defineExpose({
|
||||
start,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<slot name="prefix"></slot>
|
||||
<!-- <span style="font-family: sans-serif" /> -->
|
||||
<span>{{ displayValue }}</span>
|
||||
<slot name="suffix"></slot>
|
||||
</template>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
len: "%s必须是长度为%s个字符",
|
||||
min: "%s最小长度为%s个字符",
|
||||
max: "%s最长%s个字符",
|
||||
range: "%s字符长度需要在%s和%s直接",
|
||||
range: "%s字符长度需要在%s和%s之间",
|
||||
},
|
||||
number: {
|
||||
len: "%s长度必须为%s",
|
||||
|
||||
@@ -20,10 +20,6 @@ export interface LayFullscreenProps {
|
||||
immersive?: boolean;
|
||||
position?: string;
|
||||
zIndex?: string;
|
||||
// top?: string;
|
||||
// left?: string;
|
||||
// width?: string;
|
||||
// height?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<LayFullscreenProps>(), {
|
||||
@@ -182,11 +178,6 @@ const styleLayFullscreen = function (
|
||||
) {
|
||||
el.style.position = isRemove ? "" : props.position || "";
|
||||
el.style.zIndex = isRemove ? "" : props.zIndex || "";
|
||||
// 实验内容
|
||||
// el.style.top = isRemove ? "" : (props.top || "");
|
||||
// el.style.left = isRemove ? "" : (props.left || "");
|
||||
// el.style.width = isRemove ? "" : (props.width || "");
|
||||
// el.style.height = isRemove ? "" : (props.height || "");
|
||||
};
|
||||
|
||||
const activeEl = computed(() => (targetEl.value = props.target));
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import type { App } from "vue";
|
||||
import { LayLayer } from "@layui/layer-vue";
|
||||
|
||||
LayLayer.install = (app: App) => {
|
||||
app.component(LayLayer.name, LayLayer);
|
||||
};
|
||||
|
||||
export default LayLayer;
|
||||
@@ -159,7 +159,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
//
|
||||
.layui-nav.layui-nav-collapse {
|
||||
width: 60px;
|
||||
span {
|
||||
@@ -170,11 +169,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.layui-nav-tree {
|
||||
width: 200px;
|
||||
padding: 0;
|
||||
width: 200px;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
@@ -190,7 +188,7 @@
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding: 5px 30px 5px 30px;
|
||||
padding: 5px 23px 5px 23px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item * {
|
||||
@@ -205,6 +203,10 @@
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item span {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-bar {
|
||||
width: 5px;
|
||||
height: 0;
|
||||
@@ -322,7 +324,7 @@
|
||||
}
|
||||
|
||||
.layui-nav-tree.inverted .layui-this > a {
|
||||
padding: 5px 24px 5px 24px;
|
||||
padding: 5px 17px 5px 17px;
|
||||
}
|
||||
|
||||
.layui-nav-tree.level {
|
||||
|
||||
@@ -5,7 +5,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, provide } from "vue";
|
||||
import { computed, provide, ref, watch } from "vue";
|
||||
import "./index.less";
|
||||
|
||||
export interface LayMenuProps {
|
||||
@@ -30,14 +30,17 @@ const props = withDefaults(defineProps<LayMenuProps>(), {
|
||||
collapse: false,
|
||||
});
|
||||
|
||||
let oldOpenKeys = ref<string[]>([]);
|
||||
|
||||
const isTree = computed(() => props.tree);
|
||||
const isCollapse = computed(() => props.collapse);
|
||||
|
||||
const openKeys = computed({
|
||||
get() {
|
||||
return props.openKeys;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:selectedKey", val);
|
||||
emit("update:openKeys", val);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -50,9 +53,25 @@ const selectedKey = computed({
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.collapse,
|
||||
() => {
|
||||
if (props.collapse) {
|
||||
// 删除所有打开
|
||||
oldOpenKeys.value = props.openKeys;
|
||||
emit("update:openKeys", []);
|
||||
} else {
|
||||
// 赋值所有打开
|
||||
emit("update:openKeys", oldOpenKeys.value);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
provide("isTree", isTree);
|
||||
provide("selectedKey", selectedKey);
|
||||
provide("openKeys", openKeys);
|
||||
provide("isCollapse", isCollapse);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -27,8 +27,15 @@ const selectHandle = function () {
|
||||
@click="selectHandle()"
|
||||
>
|
||||
<a href="javascript:void(0)">
|
||||
<slot v-if="slots.default"></slot>
|
||||
<span v-else>{{ title }}</span>
|
||||
<i v-if="slots.icon">
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<span v-if="slots.title">
|
||||
<slot name="title"></slot>
|
||||
</span>
|
||||
<span v-else>
|
||||
<slot></slot>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
@@ -28,6 +28,7 @@ const props = defineProps<LaySubMenuProps>();
|
||||
const isTree: Ref<boolean> = inject("isTree") as Ref<boolean>;
|
||||
const selectedKey: Ref<string> = inject("selectedKey") as Ref<string>;
|
||||
const openKeys: Ref<string[]> = inject("openKeys") as Ref<string[]>;
|
||||
const isCollapse: Ref<boolean> = inject("isCollapse") as Ref<boolean>;
|
||||
|
||||
const isOpen = computed(() => {
|
||||
return openKeys.value.includes(props.id);
|
||||
@@ -43,10 +44,12 @@ watch(isOpen, () => {
|
||||
});
|
||||
|
||||
const openHandle = function () {
|
||||
if (openKeys.value.includes(props.id)) {
|
||||
openKeys.value.splice(openKeys.value.indexOf(props.id), 1);
|
||||
} else {
|
||||
openKeys.value.push(props.id);
|
||||
if (!isCollapse.value) {
|
||||
if (openKeys.value.includes(props.id)) {
|
||||
openKeys.value.splice(openKeys.value.indexOf(props.id), 1);
|
||||
} else {
|
||||
openKeys.value.push(props.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,8 +87,12 @@ onBeforeUnmount(() => window.removeEventListener("resize", setPosition));
|
||||
:class="[isOpen && isTree ? 'layui-nav-itemed' : '']"
|
||||
>
|
||||
<a href="javascript:void(0)" @click="openHandle()">
|
||||
<slot v-if="slots.title" name="title"></slot>
|
||||
<span v-else>{{ title }}</span>
|
||||
<i>
|
||||
<slot v-if="slots.icon" name="icon"></slot>
|
||||
</i>
|
||||
<span>
|
||||
<slot v-if="slots.title" name="title"></slot>
|
||||
</span>
|
||||
<i
|
||||
:class="[isOpen && !isTree ? 'layui-nav-mored' : '']"
|
||||
class="layui-icon layui-icon-down layui-nav-more"
|
||||
|
||||
@@ -3,10 +3,10 @@ import type { App, Component } from "vue";
|
||||
import "./theme/index.less";
|
||||
import "@layui/layer-vue/lib/index.css";
|
||||
import "@layui/icons-vue/lib/index.css";
|
||||
import { layer, useLayer } from "@layui/layer-vue";
|
||||
import { layer } from "@layui/layer-vue";
|
||||
import layerInstall from "@layui/layer-vue";
|
||||
import i18n from "./language";
|
||||
|
||||
import LayLayer from "./component/layer/index";
|
||||
import LayBacktop from "./component/backTop/index";
|
||||
import LayAvatar from "./component/avatar/index";
|
||||
import LayAvatarList from "./component/avatarList/index";
|
||||
@@ -140,7 +140,6 @@ const components: Record<string, Component> = {
|
||||
LayCarousel,
|
||||
LayCarouselItem,
|
||||
LayColorPicker,
|
||||
LayLayer,
|
||||
LayTooltip,
|
||||
LayInputNumber,
|
||||
LaySkeleton,
|
||||
@@ -161,6 +160,7 @@ const install = (app: App, options?: InstallOptions): void => {
|
||||
app.component(item.name || key, item);
|
||||
}
|
||||
app.use(i18n);
|
||||
app.use(layerInstall);
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -223,7 +223,6 @@ export {
|
||||
LayCarousel,
|
||||
LayCarouselItem,
|
||||
LayColorPicker,
|
||||
LayLayer,
|
||||
LayTooltip,
|
||||
LayInputNumber,
|
||||
LaySkeleton,
|
||||
@@ -238,6 +237,6 @@ export {
|
||||
LayConfigProvider,
|
||||
};
|
||||
|
||||
export { layer, useLayer };
|
||||
export { layer };
|
||||
|
||||
export default { install };
|
||||
|
||||
@@ -3492,4 +3492,4 @@ body .layui-util-face .layui-layer-content {
|
||||
.layui-anim-fadeout {
|
||||
-webkit-animation-name: layui-fadeout;
|
||||
animation-name: layui-fadeout;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user