Merge branch 'develop' of https://gitee.com/dingyongya/layui-vue into split-panel

 Conflicts:
	src/index.ts
This commit is contained in:
dingyongya
2022-01-20 13:34:18 +08:00
60 changed files with 859 additions and 532 deletions

View File

@@ -2610,7 +2610,6 @@ body .layui-table-tips .layui-layer-content {
display: none;
position: absolute;
left: 0;
top: 38px;
z-index: 899;
min-width: 100%;
max-height: 360px;

View File

@@ -9,6 +9,7 @@ import { layer } from "@layui/layer-vue";
import LayLayer from "./module/layer/index";
import LayBacktop from "./module/backTop/index";
import LayAvatar from "./module/avatar/index";
import LayAvatarList from "./module/avatarList/index";
import LayRadio from "./module/radio/index";
import LayButton from "./module/button/index";
import LayButtonContainer from "./module/buttonContainer/index";
@@ -112,6 +113,7 @@ const components: Record<string, IDefineComponent> = {
LayBreadcrumb,
LayBreadcrumbItem,
LayAvatar,
LayAvatarList,
LayField,
LaySelect,
LayScroll,
@@ -191,6 +193,7 @@ export {
LayBreadcrumb,
LayBreadcrumbItem,
LayAvatar,
LayAvatarList,
LayField,
LaySelect,
LayScroll,

View File

@@ -40,3 +40,8 @@
height: 28px;
width: 28px;
}
.layui-avatar-list .layui-avatar {
margin-left: -10px;
display: inline-block;
}

View File

@@ -3,7 +3,7 @@ import Component from "./index.vue";
import type { IDefineComponent } from "../type/index";
Component.install = (app: App) => {
app.component(Component.name || "LayCount", Component);
app.component(Component.name || "LayAvatarList", Component);
};
export default Component as IDefineComponent;

View File

@@ -0,0 +1,15 @@
<script lang="ts">
export default {
name: "LayAvatarList",
};
</script>
<script setup lang="ts">
import { defineProps } from "vue";
</script>
<template>
<div class="layui-avatar-list">
<slot></slot>
</div>
</template>

View File

@@ -27,6 +27,14 @@ const props = withDefaults(defineProps<LayButtonProps>(), {
nativeType: "button",
});
const emit = defineEmits(["click"]);
const onClick = (event : any) => {
if(!props.disabled) {
emit("click", event);
}
}
const classes = computed(() => {
return [
props.type ? `layui-btn-${props.type}` : "",
@@ -48,6 +56,7 @@ const classes = computed(() => {
classes,
]"
:type="nativeType"
@click="onClick"
>
<i
v-if="loading"

View File

@@ -1,5 +0,0 @@
<template>
<span class="layui-count"></span>
</template>
<script setup name="LayCount" lang="ts"></script>

View File

@@ -1,9 +1,7 @@
.layui-layout {
display: flex;
flex: 1;
display: flex;
flex-basis: auto;
height: 100%;
width: 100%;
box-sizing: border-box;
}

View File

@@ -11,7 +11,7 @@ const slots = useSlots();
const props = defineProps<{
id: string;
title: string;
title?: string;
}>();
const selectedKey: Ref<string> = inject("selectedKey") as Ref<string>;

View File

@@ -1,122 +1,163 @@
<template>
<div class="layui-box layui-laypage layui-laypage-default">
<span v-if="showCount" class="layui-laypage-count"> {{ total }} </span
><a
href="javascript:;"
class="layui-laypage-prev"
:class="[currentPage === 1 ? 'layui-disabled' : '']"
@click="prev()"
><slot v-if="slots.prev" name="prev"></slot>
<template v-else>上一页</template></a
>
<template v-if="showPage">
<template v-for="index of totalPage" :key="index">
<span v-if="index === currentPage" class="layui-laypage-curr"
><em
class="layui-laypage-em"
:class="[theme ? 'layui-bg-' + theme : '']"
></em
><em>{{ index }}</em></span
>
<a v-else href="javascript:;" @click="jump(index)">
{{ index }}
</a>
</template>
</template>
<div class="layui-box layui-laypage layui-laypage-default">
<span v-if="showCount" class="layui-laypage-count"
> {{ total }} {{ maxPage }} </span
>
<a
href="javascript:;"
class="layui-laypage-prev"
:class="[currentPage === 1 ? 'layui-disabled' : '']"
@click="prev()"
>
<slot v-if="slots.prev" name="prev"></slot>
<template v-else>上一页</template>
</a>
<template v-if="showPage">
<template v-for="index of totalPage" :key="index">
<span v-if="index === currentPage" class="layui-laypage-curr">
<em
class="layui-laypage-em"
:class="[theme ? 'layui-bg-' + theme : '']"
></em>
<em>{{ index }}</em>
</span>
<a v-else href="javascript:;" @click="jump(index)">{{ index }}</a>
</template>
</template>
<a
href="javascript:;"
class="layui-laypage-next"
:class="[currentPage === totalPage ? 'layui-disabled' : '']"
@click="next()"
><slot v-if="slots.next" name="next"></slot>
<template v-else>下一页</template></a
><span v-if="showLimit" class="layui-laypage-limits"
><select v-model="inlimit">
<option value="10">10 /</option>
<option value="20">20 /</option>
<option value="30">30 /</option>
<option value="40">40 /</option>
<option value="50">50 /</option>
</select></span
><a v-if="showRefresh" href="javascript:;" class="layui-laypage-refresh"
><i class="layui-icon layui-icon-refresh"></i></a
><span v-if="showSkip" class="layui-laypage-skip"
>到第<input
v-model="currentPageShow"
type="number"
class="layui-input layui-input-number"
/><button type="button" class="layui-laypage-btn" @click="jumpPage()">
确定
</button></span
>
</div>
<a
href="javascript:;"
class="layui-laypage-next"
:class="[currentPage === maxPage ? 'layui-disabled' : '']"
@click="next()"
>
<slot v-if="slots.next" name="next"></slot>
<template v-else>下一页</template>
</a>
<span v-if="showLimit" class="layui-laypage-limits">
<select v-model="inlimit">
<option v-for="val of limits" :key="val" :value="val">
{{ val }} /
</option>
</select>
</span>
<a v-if="showRefresh" href="javascript:;" class="layui-laypage-refresh">
<i class="layui-icon layui-icon-refresh"></i>
</a>
<span v-if="showSkip" class="layui-laypage-skip">
到第
<input
v-model="currentPageShow"
@keypress.enter="jumpPage()"
type="number"
class="layui-input layui-input-number"
/>
<button
type="button"
class="layui-laypage-btn"
@click="jumpPage()"
:disabled="currentPageShow > maxPage"
>
确定
</button>
</span>
</div>
</template>
<script setup name="LayPage" lang="ts">
import { defineProps, Ref, ref, watch, useSlots, computed, ComputedRef } from "vue";
import { defineProps, Ref, ref, watch, useSlots, computed } from "vue";
const slots = useSlots();
const props = withDefaults(
defineProps<{
total: number;
limit: number;
theme?: string;
showPage?: boolean | string;
showSkip?: boolean | string;
showCount?: boolean | string;
showLimit?: boolean | string;
showInput?: boolean | string;
showRefresh?: boolean | string;
}>(),
{
limit: 10,
theme: "green",
showPage: false,
showSkip: false,
showCount: false,
showLimit: true,
showInput: false,
showRefresh: false,
}
defineProps<{
total: number;
limit: number;
theme?: string;
showPage?: boolean | string;
showSkip?: boolean | string;
showCount?: boolean | string;
showLimit?: boolean | string;
showInput?: boolean | string;
showRefresh?: boolean | string;
pages?: number;
limits?: number[];
}>(),
{
limit: 10,
theme: "green",
showPage: false,
showSkip: false,
showCount: false,
showLimit: true,
showInput: false,
showRefresh: false,
pages: 10,
limits: () => [10, 20, 30, 40, 50],
}
);
const inlimit = ref(props.limit);
const totalPage = ref(Math.ceil(props.total / inlimit.value));
const limits = ref(props.limits);
const pages = props.pages / 2;
const inlimit = computed({
get() {
return props.limit;
},
set(v: number) {
emit("limit", v);
},
});
const maxPage = ref(0);
const totalPage = computed(() => {
maxPage.value = Math.ceil(props.total / props.limit);
let r: number[] = [],
start =
maxPage.value <= props.pages
? 1
: currentPage.value > pages
? currentPage.value - pages
: 1;
for (let i = start; ; i++) {
if (r.length >= props.pages || i > maxPage.value) {
break;
}
r.push(i);
}
return r;
});
const currentPage: Ref<number> = ref(1);
const currentPageShow: Ref<number> = ref(currentPage.value);
const emit = defineEmits(["jump"]);
const emit = defineEmits(["jump", "limit"]);
const prev = function () {
if (currentPage.value === 1) {
return;
}
currentPage.value--;
if (currentPage.value === 1) {
return;
}
currentPage.value--;
};
const next = function () {
if (currentPage.value === totalPage.value) {
return;
}
currentPage.value++;
if (currentPage.value === maxPage.value) {
return;
}
currentPage.value++;
};
const jump = function (page: number) {
currentPage.value = page;
currentPage.value = page;
};
const jumpPage = function () {
currentPage.value = currentPageShow.value;
currentPage.value = currentPageShow.value;
};
watch(inlimit, function () {
currentPage.value = 1;
totalPage.value = Math.ceil(props.total / inlimit.value);
currentPage.value = 1;
// maxPage.value = Math.ceil(props.total / inlimit.value);
});
watch(currentPage, function () {
currentPageShow.value = currentPage.value;
emit("jump", { current: currentPage.value });
currentPageShow.value = currentPage.value;
emit("jump", { current: currentPage.value });
});
</script>
</script>

View File

@@ -1,91 +1,91 @@
<template>
<div
ref="selectRef"
class="layui-unselect layui-form-select"
:class="{ 'layui-form-selected': openState }"
>
<div class="layui-select-title" @click="open">
<input
type="text"
:placeholder="
selectItem.value !== null &&
Array.isArray(selectItem.value) &&
selectItem.value.length > 0
? ''
: emptyMessage ?? placeholder
"
:disabled="disabled"
readonly
:value="
!selectItem.multiple && selectItem.value !== null
? selectItem.label
: null
"
:name="name"
:class="[
'layui-input',
'layui-unselect',
{ 'layui-disabled': disabled },
]"
/>
<i :class="['layui-edge', { 'layui-disabled': disabled }]"></i>
<!-- 多选 -->
<div
v-if="selectItem.multiple && Array.isArray(selectItem.label)"
class="layui-multiple-select-row"
>
<div class="layui-multiple-select-badge">
<template v-for="(item, index) in selectItem.label" :key="index">
<lay-badge theme="green">
<span>{{ item }}</span>
<i
:class="['layui-icon', { 'layui-icon-close': true }]"
v-if="
!disabled &&
!(
Array.isArray(selectItem.value) &&
selectItem.value.length > 0 &&
disabledItemMap[selectItem.value[index]]
)
"
@click="
removeItemHandle($event, {
label: item,
value: Array.isArray(selectItem.value)
? selectItem.value[index]
: null,
})
"
>
</i>
</lay-badge>
</template>
</div>
</div>
</div>
<dl class="layui-anim layui-anim-upbit">
<!-- 多选不支持空提示 -->
<template v-if="!multiple && showEmpty">
<lay-select-option :value="null" :label="emptyMessage ?? placeholder" />
</template>
<slot></slot>
</dl>
</div>
<div
ref="selectRef"
class="layui-unselect layui-form-select"
:class="{ 'layui-form-selected': openState }"
>
<div class="layui-select-title" @click="open">
<input
type="text"
:placeholder="
selectItem.value !== null &&
Array.isArray(selectItem.value) &&
selectItem.value.length > 0
? ''
: emptyMessage ?? placeholder
"
:disabled="disabled"
readonly
:value="
!selectItem.multiple && selectItem.value !== null
? selectItem.label
: null
"
:name="name"
:class="[
'layui-input',
'layui-unselect',
{ 'layui-disabled': disabled },
]"
/>
<i :class="['layui-edge', { 'layui-disabled': disabled }]"></i>
<!-- 多选 -->
<div
v-if="selectItem.multiple && Array.isArray(selectItem.label)"
class="layui-multiple-select-row"
>
<div class="layui-multiple-select-badge">
<template v-for="(item, index) in selectItem.label" :key="index">
<lay-badge theme="green">
<span>{{ item }}</span>
<i
:class="['layui-icon', { 'layui-icon-close': true }]"
v-if="
!disabled &&
!(
Array.isArray(selectItem.value) &&
selectItem.value.length > 0 &&
disabledItemMap[selectItem.value[index]]
)
"
@click="
removeItemHandle($event, {
label: item,
value: Array.isArray(selectItem.value)
? selectItem.value[index]
: null,
})
"
>
</i>
</lay-badge>
</template>
</div>
</div>
</div>
<dl class="layui-anim layui-anim-upbit">
<!-- 多选不支持空提示 -->
<template v-if="!multiple && showEmpty">
<lay-select-option :value="null" :label="emptyMessage ?? placeholder" />
</template>
<slot></slot>
</dl>
</div>
</template>
<script setup name="LaySelect" lang="ts">
import "./index.less";
import LaySelectOption from "../selectOption/index.vue";
import {
defineProps,
provide,
isProxy,
ref,
watch,
computed,
reactive,
toRefs,
Ref,
defineProps,
provide,
isProxy,
ref,
watch,
computed,
reactive,
toRefs,
Ref,
} from "vue";
import { useClickOutside } from "@layui/hooks-vue";
import { SelectItem } from "../type";
@@ -94,115 +94,127 @@ const selectRef = ref<null | HTMLElement>(null);
const isClickOutside = useClickOutside(selectRef);
watch(isClickOutside, () => {
if (isClickOutside.value) {
openState.value = false;
}
if (isClickOutside.value) {
openState.value = false;
}
});
const props = withDefaults(
defineProps<{
modelValue?: string | number | [] | null;
name?: string;
placeholder?: string;
disabled?: boolean;
showEmpty?: boolean;
emptyMessage?: string;
multiple?: boolean;
}>(),
{
modelValue: null,
placeholder: "请选择",
disabled: false,
showEmpty: true,
multiple: false,
}
defineProps<{
modelValue?: string | number | [] | null;
name?: string;
placeholder?: string;
disabled?: boolean;
showEmpty?: boolean;
emptyMessage?: string;
multiple?: boolean;
}>(),
{
modelValue: null,
placeholder: "请选择",
disabled: false,
showEmpty: true,
multiple: false,
}
);
const openState = ref(false);
const open = function () {
// 禁用
if (props.disabled) {
openState.value = false;
return;
}
openState.value = !openState.value;
// 禁用
if (props.disabled) {
openState.value = false;
return;
}
openState.value = !openState.value;
};
const emit = defineEmits(["update:modelValue", "change"]);
const selectItem = ref<SelectItem>({
value: !props.multiple
? props.modelValue
: props.modelValue
? ([] as any[]).concat(props.modelValue)
: [],
label: props.multiple ? [] : null,
multiple: props.multiple,
value: !props.multiple
? props.modelValue
: props.modelValue
? ([] as any[]).concat(props.modelValue)
: [],
label: props.multiple ? [] : null,
multiple: props.multiple,
} as SelectItem);
watch(
() => selectItem.value.value,
(val) => {
emit("update:modelValue", val);
emit("change", val);
},
{
deep: true,
}
() => selectItem.value.value,
(val) => {
emit("update:modelValue", val);
emit("change", val);
},
{
deep: true,
}
);
watch(
() => props.modelValue,
(value) => {
selectItem.value.value = value;
if (!value && value !== 0) {
props.multiple && (selectItem.value.value = []);
selectItem.value.label = props.multiple ? [] : null;
}
}
);
watch(props, () => {
let value = props.modelValue;
if (props.multiple) {
if (Array.isArray(value)) {
selectItem.value.value = value;
selectItem.value.label = value.map((o) => ItemsMap.value[o]);
} else {
console.error("多选时请传入数组值");
}
} else {
selectItem.value.value = value;
//@ts-ignore
selectItem.value.label = ItemsMap.value[value] || "";
}
});
// 禁止操作子项
const disabledItemMap: { [key: string | number]: boolean } = {};
const selectItemHandle = function (
_selectItem: SelectItem,
isChecked?: boolean
_selectItem: SelectItem,
isChecked?: boolean
) {
if (!props.multiple) {
openState.value = false;
}
disabledItemMap[_selectItem.value as string | number] =
_selectItem.disabled as boolean;
if (typeof isChecked !== "boolean") {
props.multiple
? (selectItem.value.label as any[]).push(_selectItem.label)
: (selectItem.value.label = _selectItem.label);
return;
}
let values = selectItem.value.value;
if (props.multiple && Array.isArray(values)) {
const _values = values as any[];
const _labels = selectItem.value.label as any[];
if (isChecked) {
_values.push(_selectItem.value);
_labels.push(_selectItem.label);
} else {
_values.splice(_values.indexOf(_selectItem.value), 1);
_labels.splice(_labels.indexOf(_selectItem.label), 1);
}
selectItem.value.value = _values;
selectItem.value.label = _labels;
} else {
selectItem.value.value = _selectItem.value;
selectItem.value.label = _selectItem.label;
}
if (!props.multiple) {
openState.value = false;
}
disabledItemMap[_selectItem.value as string | number] =
_selectItem.disabled as boolean;
if (typeof isChecked !== "boolean") {
props.multiple
? (selectItem.value.label as any[]).push(_selectItem.label)
: (selectItem.value.label = _selectItem.label);
return;
}
let values = selectItem.value.value;
if (props.multiple && Array.isArray(values)) {
const _values = values as any[];
const _labels = selectItem.value.label as any[];
if (isChecked) {
_values.push(_selectItem.value);
_labels.push(_selectItem.label);
} else {
_values.splice(_values.indexOf(_selectItem.value), 1);
_labels.splice(_labels.indexOf(_selectItem.label), 1);
}
selectItem.value.value = _values;
selectItem.value.label = _labels;
} else {
selectItem.value.value = _selectItem.value;
selectItem.value.label = _selectItem.label;
}
};
const removeItemHandle = function (e: MouseEvent, _selectItem: SelectItem) {
e.stopPropagation();
selectItemHandle(_selectItem, false);
e.stopPropagation();
selectItemHandle(_selectItem, false);
};
const ItemsMap: Ref<{ [index: string]: string }> = ref({});
const selectItemPush = function (p: SelectItem) {
if (p.value !== null) {
//@ts-ignore
ItemsMap.value[p.value] = p.label;
}
};
provide("selectItemHandle", selectItemHandle);
provide("selectItem", selectItem);
provide("selectItemPush", selectItemPush);
</script>

View File

@@ -1,65 +1,81 @@
<template>
<dd
:value="value"
:class="[{ 'layui-this': selected }, { 'layui-disabled': disabled }]"
@click="selectHandle"
>
<template v-if="selectItem.multiple">
<lay-checkbox
skin="primary"
v-model="selected"
@change="selectHandle"
label=""
/>
</template>
<slot>{{ label }}</slot>
</dd>
<dd
:value="value"
:class="[{ 'layui-this': selected }, { 'layui-disabled': disabled }]"
@click="selectHandle"
>
<template v-if="selectItem.multiple">
<lay-checkbox
skin="primary"
v-model="selected"
@change="selectHandle"
label=""
/>
</template>
<slot>{{ label }}</slot>
</dd>
</template>
<script lang="ts">
export default {
name: "LaySelectOption",
name: "LaySelectOption",
};
</script>
<script setup lang="ts">
import LayCheckbox from "../checkbox";
import { SelectItem, SelectItemHandle } from "../type";
import { SelectItem, SelectItemHandle, SelectItemPush } from "../type";
import { computed, defineProps, inject, onMounted, Ref } from "vue";
const props = withDefaults(
defineProps<{
value: string | null | undefined;
label?: string;
disabled?: boolean;
}>(),
{
disabled: false,
}
defineProps<{
value: string | null | undefined;
label?: string;
disabled?: boolean;
}>(),
{
disabled: false,
}
);
const selectItemHandle = inject("selectItemHandle") as SelectItemHandle;
const selectItem = inject("selectItem") as Ref<SelectItem>;
const selectItemPush = inject("selectItemPush") as Ref<SelectItemPush>;
const selectHandle = function () {
!props.disabled && callSelectItemHandle(!selected.value);
}
const callSelectItemHandle = function(isChecked ?: boolean){
selectItemHandle({
value : props.value,
label : props.label,
disabled : props.disabled
}, isChecked);
}
!props.disabled && callSelectItemHandle(!selected.value);
};
const callSelectItemHandle = function (isChecked?: boolean) {
// console.log("callSelectItemHandle");
selectItemHandle(
{
value: props.value,
label: props.label,
disabled: props.disabled,
},
isChecked
);
};
const selected = computed({
get(){
const selectValues = selectItem.value.value;
if (Array.isArray(selectValues)) {
return (selectValues as any[]).indexOf(props.value) > -1;
}
return selectItem.value.value === props.value
},
set(val){}
})
onMounted(() => selected.value && callSelectItemHandle())
get() {
const selectValues = selectItem.value.value;
if (Array.isArray(selectValues)) {
return (selectValues as any[]).indexOf(props.value) > -1;
}
return selectItem.value.value === props.value;
},
set(val) {},
});
const callSelectItemPush = function () {
let item = {
value: props.value,
label: props.label,
disabled: props.disabled,
};
selectItemPush(item);
};
onMounted(() => {
callSelectItemPush();
selected.value && callSelectItemHandle();
});
</script>

View File

@@ -149,10 +149,24 @@ const vertical_style = reactive({
height: props.modelValue,
});
function throttle(func: Function) {
let timer: any = null;
return function (args: any) {
if (!timer) {
timer = setTimeout(() => {
timer = null;
func(args);
}, 60);
}
};
}
const moveAction = throttle(handle_mousemove);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function handle_mousedown() {
on("selectstart", window, handle_select, { once: true });
on("mouseup", window, handle_mouseup);
on("mousemove", window, handle_mousemove);
on("mousemove", window, moveAction);
}
function handle_mousemove(e: MouseEvent) {
@@ -179,7 +193,7 @@ function handle_mousemove(e: MouseEvent) {
function handle_mouseup() {
// off('selectstart', document, handle_select)
off("mouseup", window, handle_mouseup);
off("mousemove", window, handle_mousemove);
off("mousemove", window, moveAction);
}
function handle_select(e: Event): void {

View File

@@ -11,7 +11,7 @@ const slots = useSlots();
const props = defineProps<{
id: string;
title: string;
title?: string;
}>();
const isTree = inject("isTree");

View File

@@ -13,7 +13,7 @@
>
{{ children.props.title }}
<i
v-if="allowClose"
v-if="allowClose && children.props.closable != false"
class="layui-icon layui-icon-close layui-unselect layui-tab-close"
@click.stop="close(index, children.props.id)"
></i>

View File

@@ -9,3 +9,7 @@ export interface SelectItem {
export interface SelectItemHandle {
(selectItem: SelectItem, isChecked?: boolean): void;
}
export interface SelectItemPush {
(selectItem: SelectItem): void
}

View File

@@ -3,7 +3,7 @@
* <p>
* @param elem dom
* */
export function getTop(elem) {
export function getTop(elem: any) : any {
return (
elem.offsetTop + ((elem.offsetParent && getTop(elem.offsetParent)) || 0)
);
@@ -14,7 +14,7 @@ export function getTop(elem) {
* <p>
* @param elem dom
* */
export function getLeft(elem) {
export function getLeft(elem: any) : any {
return (
elem.offsetLeft + ((elem.offsetParent && getLeft(elem.offsetParent)) || 0)
);
@@ -27,7 +27,7 @@ export function getLeft(elem) {
* @param events
* @param handler
* */
export function on(elem, events, handler) {
export function on(elem: any, events: any, handler: any) {
[]
.concat(events)
.forEach((event) => elem.addEventListener(event, handler, false));
@@ -40,8 +40,8 @@ export function on(elem, events, handler) {
* @param events
* @param handler
* */
export function once(elem, events, handler) {
const listener = function (_this, args) {
export function once(elem: any, events: any, handler: any) {
const listener = function (_this: any, args: any) {
handler.apply(_this, args);
off(elem, events, listener);
};
@@ -55,7 +55,7 @@ export function once(elem, events, handler) {
* @param events
* @param handler
* */
export function off(elem, events, handler) {
export function off(elem: any, events: any, handler: any) {
[]
.concat(events)
.forEach((event) => elem.removeEventListener(event, handler, false));