[修复] select组件中外部参数变更后组件内的数值变化不生效的问题

This commit is contained in:
castleiMac 2022-01-08 12:36:27 +08:00
parent 150499ced8
commit 010bac5d85
4 changed files with 275 additions and 208 deletions

View File

@ -27,6 +27,40 @@ export default {
}
</script>
::: title 数据联动
:::
::: demo
<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>
<lay-button @click="change1">点击切换(当前值:{{value}})</lay-button>
</template>
<script>
import { ref } from 'vue'
export default {
name:'selectChange',
setup() {
const value = ref(null);
var i = 1;
function change1(){
value.value=i++%3+1
}
return {
value,
change1
}
}
}
</script>
:::
::: title 选择禁用
@ -74,6 +108,7 @@ export default {
<lay-select-option value="6" label="打篮球"></lay-select-option>
<lay-select-option value="7" label="rap"></lay-select-option>
</lay-select>
<lay-button @click="mvalue=[1,5,7]">点击切换(当前值:{{mvalue.join()}})</lay-button>
</template>
<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

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