Merge branch 'v1.7.0' of https://gitee.com/layui/layui-vue into v1.7.0

This commit is contained in:
0o张不歪o0 2022-11-14 10:23:23 +08:00
commit ba22a7aa30
26 changed files with 342 additions and 194 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@layui/layui-vue", "name": "@layui/layui-vue",
"version": "1.7.5", "version": "1.7.7",
"author": "就眠儀式", "author": "就眠儀式",
"license": "MIT", "license": "MIT",
"description": "a component library for Vue 3 base on layui-vue", "description": "a component library for Vue 3 base on layui-vue",

View File

@ -174,7 +174,7 @@ const getScrollParent = (
} }
} }
// @ts-ignore // @ts-ignore
return document.documentElement || document.body || window; return window;
}; };
// //
@ -189,18 +189,15 @@ const throttle = (func: Function, wait: number) => {
} }
}; };
}; };
const callback = throttle(handleScroll, 300);
onMounted(() => { onMounted(() => {
if (!props.target) return; if (!props.target) return;
scrollTarget.value = getScrollTarget(); scrollTarget.value = getScrollTarget();
scrollTarget.value.addEventListener("scroll", throttle(handleScroll, 300)); scrollTarget.value.addEventListener("scroll", callback);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
scrollTarget.value?.removeEventListener( scrollTarget.value?.removeEventListener("scroll", callback);
"scroll",
throttle(handleScroll, 300)
);
}); });
</script> </script>

View File

@ -13,12 +13,12 @@ import { CheckboxSize } from "./interface";
export interface CheckboxProps { export interface CheckboxProps {
name?: string; name?: string;
skin?: string; skin?: string;
value: string | number | object;
label?: string; label?: string;
isIndeterminate?: boolean; value: string | number | object;
modelValue?: boolean | Array<string | number | object>; modelValue?: boolean | Array<string | number | object>;
disabled?: boolean; isIndeterminate?: boolean;
size?: CheckboxSize; size?: CheckboxSize;
disabled?: boolean;
} }
const props = withDefaults(defineProps<CheckboxProps>(), { const props = withDefaults(defineProps<CheckboxProps>(), {
@ -113,6 +113,8 @@ const isDisabled = computed(() => {
} }
return false; return false;
}); });
defineExpose({ toggle: handleClick });
</script> </script>
<template> <template>

View File

@ -103,7 +103,7 @@ watch(
// //
const footOnOk = () => { const footOnOk = () => {
emits("update:modelValue", Month.value?Month.value:-1); emits("update:modelValue", Month.value ? Month.value : -1);
if (datePicker.range) { if (datePicker.range) {
// //
emits("ok"); emits("ok");

View File

@ -119,7 +119,7 @@ const scrollTo = () => {
// //
const footOnOk = () => { const footOnOk = () => {
emits("update:modelValue", Year.value?Year.value:-1); emits("update:modelValue", Year.value ? Year.value : -1);
if (datePicker.range) { if (datePicker.range) {
// //
emits("ok"); emits("ok");

View File

@ -187,7 +187,7 @@ const endPlaceholder = computed(() => {
}); });
const dropdownRef = ref(null); const dropdownRef = ref(null);
const $emits = defineEmits(["update:modelValue",'change','blur','focus']); const $emits = defineEmits(["update:modelValue", "change", "blur", "focus"]);
const hms = ref({ const hms = ref({
hh: 0, hh: 0,
mm: 0, mm: 0,
@ -267,10 +267,10 @@ const getDateValue = () => {
} }
if (props.timestamp) { if (props.timestamp) {
$emits("update:modelValue", dayjs(dayjsVal).unix() * 1000); $emits("update:modelValue", dayjs(dayjsVal).unix() * 1000);
$emits("change",dayjs(dayjsVal).unix() * 1000); $emits("change", dayjs(dayjsVal).unix() * 1000);
} else { } else {
$emits("update:modelValue", dayjsVal); $emits("update:modelValue", dayjsVal);
$emits("change",dayjsVal); $emits("change", dayjsVal);
} }
setTimeout(() => { setTimeout(() => {
unWatch = false; unWatch = false;
@ -281,7 +281,7 @@ const getDateValueByRange = () => {
if (rangeValue.first === "" || rangeValue.last === "") { if (rangeValue.first === "" || rangeValue.last === "") {
dateValue.value = ["", ""]; dateValue.value = ["", ""];
$emits("update:modelValue", dateValue.value); $emits("update:modelValue", dateValue.value);
$emits("change",dateValue.value); $emits("change", dateValue.value);
return; return;
} }
let format = "YYYY-MM-DD"; let format = "YYYY-MM-DD";
@ -301,7 +301,7 @@ const getDateValueByRange = () => {
dayjs(rangeValue.last).format(format), dayjs(rangeValue.last).format(format),
]; ];
$emits("update:modelValue", dateValue.value); $emits("update:modelValue", dateValue.value);
$emits("change",dateValue.value); $emits("change", dateValue.value);
setTimeout(() => { setTimeout(() => {
unWatch = false; unWatch = false;
}, 0); }, 0);

View File

@ -20,6 +20,7 @@ import {
cloneVNode, cloneVNode,
useAttrs, useAttrs,
StyleValue, StyleValue,
PropType,
} from "vue"; } from "vue";
import { import {
computed, computed,
@ -45,7 +46,7 @@ import {
} from "./interface"; } from "./interface";
import TeleportWrapper from "../_components/teleportWrapper.vue"; import TeleportWrapper from "../_components/teleportWrapper.vue";
import { useFirstElement, isScrollElement, getScrollElements } from "./util"; import { useFirstElement, isScrollElement, getScrollElements } from "./util";
import RenderFunction from "../_components/renderFunction"; import RenderFunction, { RenderFunc } from "../_components/renderFunction";
import { transformPlacement } from "./util"; import { transformPlacement } from "./util";
export type DropdownTrigger = "click" | "hover" | "focus" | "contextMenu"; export type DropdownTrigger = "click" | "hover" | "focus" | "contextMenu";

View File

@ -109,7 +109,7 @@ const onBlur = (event: Event) => {
const onNumberBlur = (event: Event) => { const onNumberBlur = (event: Event) => {
let value = (event.target as HTMLInputElement).value; let value = (event.target as HTMLInputElement).value;
if(value === "") { if (value === "") {
value = props.min ? String(props.min) : "0"; value = props.min ? String(props.min) : "0";
} else { } else {
if (props.max && props.max < Number(value)) value = props.max.toString(); if (props.max && props.max < Number(value)) value = props.max.toString();

View File

@ -11,6 +11,7 @@ import { LayIcon } from "@layui/icons-vue";
import layButton from "../button/index.vue"; import layButton from "../button/index.vue";
import { ref, watch, withDefaults, computed, Ref } from "vue"; import { ref, watch, withDefaults, computed, Ref } from "vue";
import { InputNumberSize } from "./interface"; import { InputNumberSize } from "./interface";
import { add, sub } from "./math";
export interface InputNumberProps { export interface InputNumberProps {
modelValue?: number; modelValue?: number;
@ -84,11 +85,11 @@ const maxControl = computed(() => {
}); });
const addition = function () { const addition = function () {
num.value += Number(props.step); num.value = add(num.value, props.step);
}; };
const subtraction = function () { const subtraction = function () {
num.value -= Number(props.step); num.value = sub(num.value, props.step);
}; };
const longDown = function (fn: Function) { const longDown = function (fn: Function) {

View File

@ -0,0 +1,61 @@
//加法
function add(arg1: number, arg2: number) {
var r1, r2, m, c;
try {
r1 = arg1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
c = Math.abs(r1 - r2);
m = Math.pow(10, Math.max(r1, r2));
if (c > 0) {
var cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", "")) * cm;
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 + arg2) / m;
}
//减法
function sub(arg1: number, arg2: number) {
var r1, r2, m, c;
try {
r1 = arg1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
c = Math.abs(r1 - r2);
m = Math.pow(10, Math.max(r1, r2));
if (c > 0) {
var cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", "")) * cm;
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 - arg2) / m;
}
export { add, sub };

View File

@ -1,7 +1,9 @@
<template> <template>
<div class="lay-page-header"> <div class="lay-page-header">
<div class="lay-page-header__left" @click="emits('back')"> <div class="lay-page-header__left" @click="emits('back')">
<i class="layui-icon" :class="[backIcon]"></i> <slot name="backIcon"
><i class="layui-icon" :class="[backIcon]"></i
></slot>
<div class="lay-page-header__title">{{ backText }}</div> <div class="lay-page-header__title">{{ backText }}</div>
</div> </div>
<div class="lay-page-header__content"> <div class="lay-page-header__content">

View File

@ -14,6 +14,8 @@ const postionFns: any = {
) { ) {
innnerPosition.value = "bottom"; innnerPosition.value = "bottom";
top = bottom; top = bottom;
} else {
innnerPosition.value = "top";
} }
return { return {
top: `${top}px`, top: `${top}px`,
@ -30,6 +32,8 @@ const postionFns: any = {
if (window.innerHeight - bottom < popper.offsetHeight + 6) { if (window.innerHeight - bottom < popper.offsetHeight + 6) {
innnerPosition.value = "top"; innnerPosition.value = "top";
bottom = top - popper.offsetHeight - 6; bottom = top - popper.offsetHeight - 6;
} else {
innnerPosition.value = "bottom";
} }
return { return {
top: `${bottom}px`, top: `${bottom}px`,
@ -47,6 +51,8 @@ const postionFns: any = {
if (left < 0) { if (left < 0) {
innnerPosition.value = "right"; innnerPosition.value = "right";
left = right; left = right;
} else {
innnerPosition.value = "left";
} }
return { return {
top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`, top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`,
@ -63,6 +69,8 @@ const postionFns: any = {
if (window.innerWidth < right + popper.offsetWidth + 6) { if (window.innerWidth < right + popper.offsetWidth + 6) {
innnerPosition.value = "left"; innnerPosition.value = "left";
right = left - popper.offsetWidth - 6; right = left - popper.offsetWidth - 6;
} else {
innnerPosition.value = "right";
} }
return { return {
top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`, top: `${top - (popper.offsetHeight - el.offsetHeight) / 2}px`,

View File

@ -9,7 +9,7 @@
@mouseenter="handlerPopperMouseEnter" @mouseenter="handlerPopperMouseEnter"
@mouseleave="handlerPopperMouseLeave" @mouseleave="handlerPopperMouseLeave"
> >
<slot>{{ content }}</slot> <slot> {{ content }}</slot>
<div class="layui-popper-arrow"></div> <div class="layui-popper-arrow"></div>
</div> </div>
</transition> </transition>

View File

@ -68,6 +68,7 @@ const multipleValue = ref([]);
const emits = defineEmits<SelectEmits>(); const emits = defineEmits<SelectEmits>();
const openState: Ref<boolean> = ref(false); const openState: Ref<boolean> = ref(false);
const options = ref<any>([]); const options = ref<any>([]);
const composing = ref(false);
var timer: any; var timer: any;
const getOption = (nodes: VNode[], newOptions: any[]) => { const getOption = (nodes: VNode[], newOptions: any[]) => {
@ -79,7 +80,12 @@ const getOption = (nodes: VNode[], newOptions: any[]) => {
if (component.name == LaySelectOption.name) { if (component.name == LaySelectOption.name) {
if (item.children) { if (item.children) {
// @ts-ignore // @ts-ignore
item.props.label = item.children.default()[0].children; const label = item.children.default()[0].children;
if (typeof label == "string") {
// @ts-ignore
item.props.label = label;
}
} }
newOptions.push(item.props); newOptions.push(item.props);
} }
@ -104,6 +110,15 @@ const handleRemove = (value: any) => {
} }
}; };
const onCompositionstart = () => {
composing.value = true;
};
const onCompositionend = (event: Event) => {
composing.value = false;
handleSearch((event.target as HTMLInputElement).value);
};
onMounted(() => { onMounted(() => {
intOption(); intOption();
timer = setInterval(intOption, 500); timer = setInterval(intOption, 500);
@ -150,6 +165,7 @@ const multiple = computed(() => {
}); });
const handleSearch = (value: string) => { const handleSearch = (value: string) => {
if (composing.value) return;
emits("search", value); emits("search", value);
searchValue.value = value; searchValue.value = value;
}; };
@ -204,13 +220,15 @@ provide("multiple", multiple);
</lay-tag-input> </lay-tag-input>
<lay-input <lay-input
v-else v-else
v-model="singleValue" :modelValue="singleValue"
:placeholder="placeholder" :placeholder="placeholder"
:allow-clear="allowClear" :allow-clear="allowClear"
:readonly="!showSearch" :readonly="!showSearch"
:disabled="disabled" :disabled="disabled"
:class="{ 'layui-unselect': !showSearch }" :class="{ 'layui-unselect': !showSearch }"
:size="size" :size="size"
@compositionstart="onCompositionstart"
@compositionend="onCompositionend"
@Input="handleSearch" @Input="handleSearch"
@clear="handleClear" @clear="handleClear"
> >
@ -225,9 +243,11 @@ provide("multiple", multiple);
<dl class="layui-select-content"> <dl class="layui-select-content">
<div class="layui-select-search" v-if="multiple && showSearch"> <div class="layui-select-search" v-if="multiple && showSearch">
<lay-input <lay-input
v-model="searchValue" :modelValue="searchValue"
:placeholder="searchPlaceholder" :placeholder="searchPlaceholder"
@Input="handleSearch" @Input="handleSearch"
@compositionstart="onCompositionstart"
@compositionend="onCompositionend"
prefix-icon="layui-icon-search" prefix-icon="layui-icon-search"
size="sm" size="sm"
></lay-input> ></lay-input>

View File

@ -12,7 +12,7 @@ import {
inject, inject,
WritableComputedRef, WritableComputedRef,
Ref, Ref,
onMounted, ref,
} from "vue"; } from "vue";
export interface SelectOptionProps { export interface SelectOptionProps {
@ -34,13 +34,20 @@ const selectedValue: WritableComputedRef<any> = inject(
"selectedValue" "selectedValue"
) as WritableComputedRef<any>; ) as WritableComputedRef<any>;
const multiple: ComputedRef = inject("multiple") as ComputedRef; const multiple: ComputedRef = inject("multiple") as ComputedRef;
const checkboxRef = ref<HTMLElement>();
const handleSelect = () => { const handleSelect = () => {
if (!multiple.value && !props.disabled) { if (multiple.value) {
// @ts-ignore if (!props.disabled) {
selectRef.value.hide(); // @ts-ignore
selectedValue.value = props.value; checkboxRef.value?.toggle();
select(); }
} else {
if (!props.disabled) {
// @ts-ignore
selectRef.value.hide();
selectedValue.value = props.value;
}
} }
}; };
@ -52,18 +59,6 @@ const selected = computed(() => {
} }
}); });
const select = () => {
if (multiple.value) {
if (Array.isArray(selectedValue.value)) {
if (notChecked.value) selectedValue.value.push(props.value);
} else {
selectedValue.value = [props.value];
}
} else {
selectedValue.value = props.value;
}
};
const display = computed(() => { const display = computed(() => {
return ( return (
props.keyword?.toString().indexOf(searchValue.value) > -1 || props.keyword?.toString().indexOf(searchValue.value) > -1 ||
@ -71,34 +66,26 @@ const display = computed(() => {
); );
}); });
const notChecked = computed(() => { const classes = computed(() => {
return ( return [
selectedValue.value.find((item: any) => { "layui-select-option",
return item === props.value; {
}) === undefined "layui-this": selected.value,
); "layui-disabled": props.disabled,
}); },
];
onMounted(() => {
selected.value && select();
}); });
</script> </script>
<template> <template>
<dd <dd v-show="display" :class="classes" @click="handleSelect">
v-show="display"
:class="[
'layui-select-option',
{ 'layui-this': selected, 'layui-disabled': disabled },
]"
@click="handleSelect"
>
<template v-if="multiple"> <template v-if="multiple">
<lay-checkbox <lay-checkbox
skin="primary"
ref="checkboxRef"
v-model="selectedValue" v-model="selectedValue"
:disabled="disabled" :disabled="disabled"
:value="value" :value="value"
skin="primary"
></lay-checkbox> ></lay-checkbox>
</template> </template>
<slot>{{ label }}</slot> <slot>{{ label }}</slot>

View File

@ -366,10 +366,6 @@
box-sizing: border-box; box-sizing: border-box;
} }
.layui-table-cell .lay-tooltip-content {
display: inline;
}
.layui-table-cell .layui-form-checkbox[lay-skin="primary"] { .layui-table-cell .layui-form-checkbox[lay-skin="primary"] {
top: -1px; top: -1px;
padding: 0; padding: 0;

View File

@ -17,6 +17,7 @@ import {
ref, ref,
useSlots, useSlots,
withDefaults, withDefaults,
watch
} from "vue"; } from "vue";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
import { LayLayer } from "@layui/layer-vue"; import { LayLayer } from "@layui/layer-vue";
@ -68,6 +69,10 @@ export interface UploadProps {
disabledPreview?: boolean; disabledPreview?: boolean;
cut?: boolean; cut?: boolean;
cutOptions?: CutOptions; cutOptions?: CutOptions;
text?: string;
dragText?: string;
modelValue?: any;
auto?: boolean;
} }
const getCutDownResult = () => { const getCutDownResult = () => {
@ -81,6 +86,11 @@ const getCutDownResult = () => {
Object.assign({ currentTimeStamp, cutResult: imgData, orginal: orgInfo }) Object.assign({ currentTimeStamp, cutResult: imgData, orginal: orgInfo })
); );
let newFile = dataURLtoFile(imgData); let newFile = dataURLtoFile(imgData);
if (!props.auto) {
emit("update:modelValue", [newFile]);
clearLightCutEffect();
return;
}
commonUploadTransaction([newFile]); commonUploadTransaction([newFile]);
nextTick(() => clearAllCutEffect()); nextTick(() => clearAllCutEffect());
} else { } else {
@ -102,9 +112,20 @@ const clearAllCutEffect = () => {
_cropper = null; _cropper = null;
}; };
const clearLightCutEffect = () => {
activeUploadFiles.value = [];
activeUploadFilesImgs.value = [];
innerCutVisible.value = false;
_cropper = null;
};
const { t } = useI18n(); const { t } = useI18n();
const text = computed(() => t("upload.text")); const text = computed(() => {
const dragText = computed(() => t("upload.dragText")); return props.text ? props.text : t("upload.text");
});
const dragText = computed(() => {
return props.dragText ? props.dragText : t("upload.dragText");
});
const defaultErrorMsg = computed(() => t("upload.defaultErrorMsg")); const defaultErrorMsg = computed(() => t("upload.defaultErrorMsg"));
const urlErrorMsg = computed(() => t("upload.urlErrorMsg")); const urlErrorMsg = computed(() => t("upload.urlErrorMsg"));
const numberErrorMsg = computed(() => t("upload.numberErrorMsg")); const numberErrorMsg = computed(() => t("upload.numberErrorMsg"));
@ -142,6 +163,8 @@ const props = withDefaults(defineProps<UploadProps>(), {
disabledPreview: false, disabledPreview: false,
cut: false, cut: false,
cutOptions: void 0, cutOptions: void 0,
modelValue: null,
auto: true,
}); });
const slot = useSlots(); const slot = useSlots();
@ -149,19 +172,30 @@ const slots = slot.default && slot.default();
const context = getCurrentInstance(); const context = getCurrentInstance();
const emit = defineEmits([ const emit = defineEmits([
"choose", "choose",
"chooseAfter",
"before", "before",
"done", "done",
"error", "error",
"cutdone", "cutdone",
"cutcancel", "cutcancel",
"update:modelValue",
]); ]);
watch(
() => props.modelValue,
() => {
if (!props.modelValue) {
clearAllCutEffect();
}
}
);
const isDragEnter = ref(false); const isDragEnter = ref(false);
const activeUploadFiles = ref<any[]>([]); const activeUploadFiles = ref<any[]>([]);
const activeUploadFilesImgs = ref<any[]>([]); const activeUploadFilesImgs = ref<any[]>([]);
const orgFileInput = templateRef<HTMLElement>("orgFileInput"); const orgFileInput = templateRef<HTMLElement>("orgFileInput");
let _cropper: any = null;
let _cropper: any = null;
let computedCutLayerOption: ComputedRef<LayerModal>; let computedCutLayerOption: ComputedRef<LayerModal>;
if (props.cutOptions && props.cutOptions.layerOption) { if (props.cutOptions && props.cutOptions.layerOption) {
@ -213,7 +247,7 @@ const localUploadTransaction = (option: localUploadTransaction) => {
const dataURLtoFile = (dataurl: string) => { const dataURLtoFile = (dataurl: string) => {
let arr: any[] = dataurl.split(","); let arr: any[] = dataurl.split(",");
let mime: string = ""; let mime = "";
if (arr.length > 0) { if (arr.length > 0) {
mime = arr[0].match(/:(.*?);/)[1]; mime = arr[0].match(/:(.*?);/)[1];
} }
@ -231,14 +265,13 @@ const errorF = (errorText: string) => {
let errorMsg = errorText ? errorText : defaultErrorMsg; let errorMsg = errorText ? errorText : defaultErrorMsg;
errorMsg = `layui-vue:${errorMsg}`; errorMsg = `layui-vue:${errorMsg}`;
console.warn(errorMsg); console.warn(errorMsg);
layer.msg(errorMsg, { icon: 2, time: 1000 }, function (res: unknown) {}); layer.msg(errorMsg, { icon: 2, time: 1000 }, function (res: unknown) { });
emit("error", Object.assign({ currentTimeStamp, msg: errorMsg })); emit("error", Object.assign({ currentTimeStamp, msg: errorMsg }));
}; };
const localUpload = (option: localUploadOption, callback: Function) => { const localUpload = (option: localUploadOption, callback: Function) => {
let xhr: XMLHttpRequest, url; let xhr: XMLHttpRequest = new XMLHttpRequest();
xhr = new XMLHttpRequest(); let url = option.url;
url = option.url;
let formData = option.formData; let formData = option.formData;
const cb = callback; const cb = callback;
xhr.onreadystatechange = function () { xhr.onreadystatechange = function () {
@ -319,10 +352,12 @@ const uploadChange = (e: any) => {
props.cut && props.cut &&
props.acceptMime.indexOf("image") != -1 && props.acceptMime.indexOf("image") != -1 &&
props.multiple == false; props.multiple == false;
let arm2 = let arm2 =
props.cut && props.cut &&
props.acceptMime.indexOf("image") != -1 && props.acceptMime.indexOf("image") != -1 &&
props.multiple == true; props.multiple == true;
if (arm1) { if (arm1) {
innerCutVisible.value = true; innerCutVisible.value = true;
setTimeout(() => { setTimeout(() => {
@ -341,6 +376,10 @@ const uploadChange = (e: any) => {
if (arm2) { if (arm2) {
console.warn(cannotSupportCutMsg.value); console.warn(cannotSupportCutMsg.value);
} }
if (!props.auto) {
emit("update:modelValue", _files);
return;
}
commonUploadTransaction(_files); commonUploadTransaction(_files);
} }
}; };
@ -403,22 +442,9 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<div <div class="layui-upload layui-upload-wrap" :class="disabledPreview ? 'layui-upload-file-disabled' : ''">
class="layui-upload layui-upload-wrap" <input type="file" class="layui-upload-file" ref="orgFileInput" :name="field" :field="field" :multiple="multiple"
:class="disabledPreview ? 'layui-upload-file-disabled' : ''" :accept="acceptMime" :disabled="disabled" @click="clickOrgInput" @change="uploadChange" />
>
<input
type="file"
class="layui-upload-file"
ref="orgFileInput"
:name="field"
:field="field"
:multiple="multiple"
:accept="acceptMime"
:disabled="disabled"
@click="clickOrgInput"
@change="uploadChange"
/>
<div v-if="!drag"> <div v-if="!drag">
<div class="layui-upload-btn-box" @click.stop="chooseFile"> <div class="layui-upload-btn-box" @click.stop="chooseFile">
<template v-if="slot.default"> <template v-if="slot.default">
@ -426,24 +452,18 @@ onUnmounted(() => {
</template> </template>
<template v-else> <template v-else>
<lay-button type="primary" :disabled="disabled">{{ <lay-button type="primary" :disabled="disabled">{{
text text
}}</lay-button> }}</lay-button>
</template> </template>
</div> </div>
</div> </div>
<div <div v-else ref="dragRef" class="layui-upload-drag" :class="
v-else disabled
ref="dragRef" ? 'layui-upload-drag-disable'
class="layui-upload-drag" : isDragEnter
:class="
disabled
? 'layui-upload-drag-disable'
: isDragEnter
? 'layui-upload-drag-draging' ? 'layui-upload-drag-draging'
: '' : ''
" " @click.stop="chooseFile">
@click.stop="chooseFile"
>
<i class="layui-icon"></i> <i class="layui-icon"></i>
<p>{{ dragText }}</p> <p>{{ dragText }}</p>
<div class="layui-hide" id="uploadDemoView"> <div class="layui-hide" id="uploadDemoView">
@ -451,38 +471,17 @@ onUnmounted(() => {
<img src="" alt="上传成功后渲染" style="max-width: 196px" /> <img src="" alt="上传成功后渲染" style="max-width: 196px" />
</div> </div>
</div> </div>
<lay-layer <lay-layer v-model="innerCutVisible" :title="computedCutLayerOption.title" :move="computedCutLayerOption.move"
v-model="innerCutVisible" :resize="computedCutLayerOption.resize" :shade="computedCutLayerOption.shade"
:title="computedCutLayerOption.title" :shadeClose="computedCutLayerOption.shadeClose" :shadeOpacity="computedCutLayerOption.shadeOpacity"
:move="computedCutLayerOption.move" :zIndex="computedCutLayerOption.zIndex" :btnAlign="computedCutLayerOption.btnAlign"
:resize="computedCutLayerOption.resize" :area="computedCutLayerOption.area" :anim="computedCutLayerOption.anim"
:shade="computedCutLayerOption.shade" :isOutAnim="computedCutLayerOption.isOutAnim" :btn="computedCutLayerOption.btn" @close="clearAllCutEffect">
:shadeClose="computedCutLayerOption.shadeClose" <div class="copper-container" v-for="(base64str, index) in activeUploadFilesImgs" :key="`file${index}`">
:shadeOpacity="computedCutLayerOption.shadeOpacity" <img :src="base64str" :id="`_lay_upload_img${index}`" class="_lay_upload_img" />
:zIndex="computedCutLayerOption.zIndex"
:btnAlign="computedCutLayerOption.btnAlign"
:area="computedCutLayerOption.area"
:anim="computedCutLayerOption.anim"
:isOutAnim="computedCutLayerOption.isOutAnim"
:btn="computedCutLayerOption.btn"
@close="clearAllCutEffect"
>
<div
class="copper-container"
v-for="(base64str, index) in activeUploadFilesImgs"
:key="`file${index}`"
>
<img
:src="base64str"
:id="`_lay_upload_img${index}`"
class="_lay_upload_img"
/>
</div> </div>
</lay-layer> </lay-layer>
<div <div class="layui-upload-list" :class="disabledPreview ? 'layui-upload-list-disabled' : ''">
class="layui-upload-list"
:class="disabledPreview ? 'layui-upload-list-disabled' : ''"
>
<slot name="preview"></slot> <slot name="preview"></slot>
</div> </div>
</div> </div>

View File

@ -151,6 +151,7 @@ export default {
::: demo ::: demo
<template> <template>
{{ validateModel }}
<lay-form :model="validateModel" ref="layFormRef" required> <lay-form :model="validateModel" ref="layFormRef" required>
<lay-form-item label="账户" prop="username"> <lay-form-item label="账户" prop="username">
<lay-input v-model="validateModel.username"></lay-input> <lay-input v-model="validateModel.username"></lay-input>
@ -173,8 +174,11 @@ export default {
<lay-form-item label="描述" prop="desc"> <lay-form-item label="描述" prop="desc">
<lay-textarea placeholder="请输入描述" v-model="validateModel.desc"></lay-textarea> <lay-textarea placeholder="请输入描述" v-model="validateModel.desc"></lay-textarea>
</lay-form-item> </lay-form-item>
<lay-form-item label="文件" prop="file">
<lay-upload v-model="validateModel.file" acceptMime="image/*" :auto="false"/>
</lay-form-item>
<lay-form-item> <lay-form-item>
<lay-button @click="validate">提交</lay-button> <lay-button @click="validate3">提交</lay-button>
<lay-button @click="clearValidate">清除校验</lay-button> <lay-button @click="clearValidate">清除校验</lay-button>
<lay-button @click="reset">重置表单</lay-button> <lay-button @click="reset">重置表单</lay-button>
</lay-form-item> </lay-form-item>
@ -192,13 +196,15 @@ export default {
username: "", username: "",
password: "", password: "",
specialty: "1", specialty: "1",
hobbys: "" hobbys: "",
file: null,
}) })
const layFormRef = ref(null); const layFormRef = ref(null);
// 校验 // 校验
const validate = function() { const validate3= function() {
layFormRef.value.validate((isValidate, model, errors) => { layFormRef.value.validate((isValidate, model, errors) => {
console.log(JSON.stringify(model.file))
layer.open({ layer.open({
type: 1, type: 1,
title:"表单提交结果", title:"表单提交结果",
@ -225,7 +231,7 @@ export default {
return { return {
validateModel, validateModel,
layFormRef, layFormRef,
validate, validate3,
clearValidate, clearValidate,
reset reset
} }

View File

@ -13,8 +13,7 @@
::: demo 使用 `lay-input-number` 标签, 创建数字输入框 ::: demo 使用 `lay-input-number` 标签, 创建数字输入框
<template> <template>
{{data1}} <lay-input-number v-model="data1" :step="0.11"></lay-input-number>
<lay-input-number v-model="data1"></lay-input-number>
<lay-input-number v-model="data2" position="right"></lay-input-number> <lay-input-number v-model="data2" position="right"></lay-input-number>
</template> </template>

View File

@ -24,6 +24,9 @@ const handleBack=()=>{
::: :::
::: title 设置标题
:::
::: demo 使用 `backText` 属性 自定义返回文本 ::: demo 使用 `backText` 属性 自定义返回文本
<template> <template>
@ -38,8 +41,9 @@ const handleBack=()=>{
::: :::
::: title PageHeader 插槽 ::: title 使用插槽
::: :::
::: demo 使用 默认插槽可以自定义右侧内容 同时content属性将失效 ::: demo 使用 默认插槽可以自定义右侧内容 同时content属性将失效
<template> <template>
@ -71,7 +75,7 @@ const handleBack=()=>{
| ------ | ---- | -------------- | | ------ | ---- | -------------- |
| content| 标题,当前默认插槽不为空时失效 | -- | | content| 标题,当前默认插槽不为空时失效 | -- |
| backText| 返回文本 | 默认 "返回" | | backText| 返回文本 | 默认 "返回" |
| backIcon| 返回图标 | 内置图标集 |
::: :::
::: title PageHeader 事件 ::: title PageHeader 事件
@ -85,6 +89,19 @@ const handleBack=()=>{
::: :::
::: title PageHeader 插槽
:::
::: table
| 属性 | 描述 |
| ------ | ---- |
| default | 标题内容 |
| backIcon| 返回图标 |
:::
::: contributor pageHeader ::: contributor pageHeader
::: :::

View File

@ -16,7 +16,7 @@
<lay-select v-model="value"> <lay-select v-model="value">
<lay-select-option :value="1" label="学习"></lay-select-option> <lay-select-option :value="1" label="学习"></lay-select-option>
<lay-select-option :value="2" label="编码"></lay-select-option> <lay-select-option :value="2" label="编码"></lay-select-option>
<lay-select-option :value="3" v-if="true">运动</lay-select-option> <lay-select-option :value="3" label="运动"></lay-select-option>
</lay-select> </lay-select>
</template> </template>
@ -47,7 +47,7 @@ export default {
<lay-select-option :value="2" label="编码"></lay-select-option> <lay-select-option :value="2" label="编码"></lay-select-option>
<lay-select-option :value="3" label="运动"></lay-select-option> <lay-select-option :value="3" label="运动"></lay-select-option>
</lay-select> </lay-select>
<lay-button @click="change2"> change {{value2}}</lay-button> <lay-button @click="change2"> change {{value2}} </lay-button>
</lay-space> </lay-space>
</template> </template>
@ -117,15 +117,15 @@ export default {
<template> <template>
<lay-space> <lay-space>
<lay-select v-model="value3" :show-search="true" @search="search"> <lay-select v-model="value3" :show-search="true">
<lay-select-option value="1" label="学习"></lay-select-option> <lay-select-option value="1" label="学习"></lay-select-option>
<lay-select-option value="2" label="编码"></lay-select-option> <lay-select-option value="2" label="编码"></lay-select-option>
<lay-select-option value="3" :label="null"></lay-select-option> <lay-select-option value="3" label="运动"></lay-select-option>
</lay-select> </lay-select>
<lay-select v-model="value4" :show-search="true" :multiple="true" @search="search"> <lay-select v-model="value4" :show-search="true" :multiple="true">
<lay-select-option value="1" label="学习"></lay-select-option> <lay-select-option value="1" label="学习"></lay-select-option>
<lay-select-option value="2" label="编码"></lay-select-option> <lay-select-option value="2" label="编码"></lay-select-option>
<lay-select-option value="3" :label="null"></lay-select-option> <lay-select-option value="3" label="运动"></lay-select-option>
</lay-select> </lay-select>
</lay-space> </lay-space>
</template> </template>
@ -138,14 +138,10 @@ export default {
const value3 = ref('1') const value3 = ref('1')
const value4 = ref(['1']) const value4 = ref(['1'])
const search = function() {
console.log("触发")
}
return { return {
value3, value3,
value4, value4,
search
} }
} }
} }
@ -290,6 +286,35 @@ export default {
</script> </script>
::: :::
::: title 定制选项
:::
::: demo 使用 `lay-select` 标签, 创建下拉选择框
<template>
<lay-select v-model="value">
<lay-select-option :value="1" label="学习"></lay-select-option>
<lay-select-option :value="2" label="编码"></lay-select-option>
<lay-select-option :value="3" label="运动">运动</lay-select-option>
</lay-select>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const value = ref(null);
return {
value
}
}
}
</script>
:::
::: title Select 属性 ::: title Select 属性
::: :::

View File

@ -40,7 +40,7 @@ export default {
<template> <template>
<lay-space direction="vertical" fill wrap> <lay-space direction="vertical" fill wrap>
<lay-button v-for="idx of 5" type="normal" fluid="true">按钮 {{idx}}</lay-button> <lay-button v-for="idx of 5" type="normal" :fluid="true">按钮 {{idx}}</lay-button>
</lay-space> </lay-space>
</template> </template>

View File

@ -1387,7 +1387,6 @@ export default {
::: demo 使用了绝大部分属性的 table 案例 ::: demo 使用了绝大部分属性的 table 案例
<template> <template>
<lay-button @click="changeMaxHeight"></lay-button>
<lay-table <lay-table
id="id" id="id"
:max-height="maxHeight5" :max-height="maxHeight5"
@ -1428,10 +1427,6 @@ export default {
const defaultToolbar5 = ref(true) const defaultToolbar5 = ref(true)
const maxHeight5 = ref('600px'); const maxHeight5 = ref('600px');
const changeMaxHeight = () => {
maxHeight5.value = '200px'
}
const page5 = { const page5 = {
total: 100, total: 100,
limit: 10, limit: 10,

View File

@ -84,21 +84,21 @@ export default {
<template> <template>
<div style="padding: 100px;max-width:400px;"> <div style="padding: 100px;max-width:400px;">
<div style="text-align: center;"> <div style="text-align: center;">
<lay-tooltip content="假装这里有文字提示"> <lay-tooltip trigger="click" content="假装这里有文字提示">
<lay-button>上边</lay-button> <lay-button>上边</lay-button>
</lay-tooltip> </lay-tooltip>
</div> </div>
<div> <div>
<lay-tooltip content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="left"> <lay-tooltip trigger="click" content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="left">
<lay-button style="float:left;">左边</lay-button> <lay-button style="float:left;">左边</lay-button>
</lay-tooltip> </lay-tooltip>
<lay-tooltip content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="right"> <lay-tooltip trigger="click" content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="right">
<lay-button style="float:right;">右边</lay-button> <lay-button style="float:right;">右边</lay-button>
</lay-tooltip> </lay-tooltip>
<div style="clear: both;"></div> <div style="clear: both;"></div>
</div> </div>
<div style="text-align: center;"> <div style="text-align: center;">
<lay-tooltip content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="bottom"> <lay-tooltip trigger="click" content="假装这里有文字提示假装这里有文字提示假装这里有文字提示假装这里有文字提示" position="bottom">
<lay-button>下边</lay-button> <lay-button>下边</lay-button>
</lay-tooltip> </lay-tooltip>
</div> </div>

View File

@ -13,11 +13,9 @@
::: demo 使用 `lay-upload` 标签, 创建一个上传按钮 ::: demo 使用 `lay-upload` 标签, 创建一个上传按钮
<template> <template>
<lay-upload url="https://www.mocky.io/v2/5cc8019d300000980a055e76" @done="doneHandle" field="bigFile" @choose="beginChoose"> <lay-upload url="https://www.mocky.io/v2/5cc8019d300000980a055e76" field="file" @done="doneHandle">
<template #preview> <template #preview>
<div v-for="(item,index) in picList" :key="`demo1-pic-'${index}`"> <img v-if="data" :src="data.url" style="width: 100px;"/>
<img :src="item"/>
</div>
</template> </template>
</lay-upload> </lay-upload>
</template> </template>
@ -27,34 +25,47 @@ import { ref,reactive } from 'vue'
export default { export default {
  setup() {   setup() {
const picList = ref([]);
const filetoDataURL=(file,fn)=>{ const data = ref();
const reader = new FileReader();
reader.onloadend = function(e){ const doneHandle = (result) => {
fn(e.target.result); data.value = JSON.parse(result.data);
}; console.log(data.value.url)
reader.readAsDataURL(file);
};
const doneHandle=(files)=>{
console.log("触发")
if(Array.isArray(files)&&files.length>0){
files.forEach((file,index,array)=>{
filetoDataURL(file,(res)=>{
console.log(res);
picList.value.push(res);
console.log(picList.value);
});
});
}
};
const beginChoose =(e)=>{
console.log("beginChoose",e);
}; };
    return {     return {
doneHandle, doneHandle,
filetoDataURL, data
beginChoose,     }
picList   }
}
</script>
:::
::: title 手动上传
:::
::: demo 使用 `lay-upload` 标签, 创建一个上传按钮
<template>
<lay-upload url="https://www.mocky.io/v2/5cc8019d300000980a055e76" v-model="file1" field="file" :auto="false">
<template #preview>
{{ file1 }}
</template>
</lay-upload>
</template>
<script>
import { ref,reactive } from 'vue'
export default {
  setup() {
const file1 = ref();
    return {
file1
    }     }
  }   }
} }
@ -260,6 +271,9 @@ export default {
| disabledPreview | 设置文件预览插槽区域为禁用状态 | boolean | false | -- | | disabledPreview | 设置文件预览插槽区域为禁用状态 | boolean | false | -- |
| cut | 是否开启选择图片后检测,设置true可开启 | boolean | false | -- | | cut | 是否开启选择图片后检测,设置true可开启 | boolean | false | -- |
| cutOptions | 开启剪裁的模态弹窗与剪裁框的配置 | object | { layerOption,copperOption } | -- | | cutOptions | 开启剪裁的模态弹窗与剪裁框的配置 | object | { layerOption,copperOption } | -- |
| text | 普通上传描述 | string | -- | -- |
| dragText | 拖拽上传描述 | string | -- | -- |
| auto | 是否自动提交 | boolean | false | -- |
::: :::

View File

@ -11,19 +11,37 @@
<template> <template>
<lay-timeline> <lay-timeline>
<lay-timeline-item title="1.7.x"> <lay-timeline-item title="1.7.x">
<ul>
<a name="1-7-7"></a>
<li>
<h3>1.7.7 <span class="layui-badge-rim">2022-11-11</span></h3>
<ul>
<li>[新增] upload 组件 text 属性, 设置上传描述。</li>
<li>[新增] upload 组件 dragText 属性, 设置拖拽面板提示信息。</li>
<li>[修复] select-option 组件 default 插槽内容为多层元素时, 使用 label 属性值作为回显。</li>
<li>[修复] input-number 组件 step 设置为小数时精度丢失的问题。</li>
<li>[修复] tooltip 组件临近屏幕边界, 三角位置显示错误。</li>
<li>[优化] select-option 组件 多选 模式只能点击复选框的问题。</li>
<li>[优化] select 组件 search 事件在拼字时触发的问题。</li>
<li>[优化] select 组件 change 事件触发时机不恰当的问题。</li>
</ul>
</li>
</ul>
<ul> <ul>
<a name="1-7-6"></a> <a name="1-7-6"></a>
<li> <li>
<h3>1.7.6 <span class="layui-badge-rim">2022-11-07</span></h3> <h3>1.7.6 <span class="layui-badge-rim">2022-11-09</span></h3>
<ul> <ul>
<li>[新增] page-header 组件 back-icon 插槽, 自定义返回图标。</li>
<li>[新增] page-header 组件 back-icon 属性, 自定义返回图标。</li> <li>[新增] page-header 组件 back-icon 属性, 自定义返回图标。</li>
<li>[修复] input-number 组件 step 设置为小数时精度丢失的问题。</li>
<li>[修复] datePicker 组件 年选择器 清空后再点击确定回显错误。</li>
<li>[修复] select 组件 单选模式 与 多选模式 清空操作样式不统一的问题。</li> <li>[修复] select 组件 单选模式 与 多选模式 清空操作样式不统一的问题。</li>
<li>[修复] select 组件 单选模式 与 多选模式 下拉宽度不一致的问题。</li> <li>[修复] select 组件 单选模式 与 多选模式 下拉宽度不一致的问题。</li>
<li>[修复] select 组件 多选模式 @search 事件不生效的问题。</li> <li>[修复] select 组件 多选模式 @search 事件不生效的问题。</li>
<li>[优化] select 组件 label 属性不兼容 number 类型。</li> <li>[优化] select 组件 label 属性不兼容 number 类型。</li>
<li>[优化] select-option 组件 label 属性为 null 时, 单选不展示。</li> <li>[优化] select-option 组件 label 属性为 null 时, 单选不展示。</li>
<li>[优化] select-option 组件 label 属性为 null 时, 搜索报错。</li> <li>[优化] select-option 组件 label 属性为 null 时, 搜索报错。</li>
<li>[修复] datePicker 组件 年选择器 清空后再点击确定回显错误。</li>
<li>[优化] datePicker 组件 新增change,blur,foucs事件。</li> <li>[优化] datePicker 组件 新增change,blur,foucs事件。</li>
</ul> </ul>
</li> </li>