Merge branch 'develop' of https://gitee.com/layui-vue/layui-vue into develop
This commit is contained in:
commit
545d8ac48a
@ -81,7 +81,7 @@ export default {
|
||||
<lay-input v-model="validateModel.password" type="password">></lay-input>
|
||||
</lay-form-item>
|
||||
<lay-form-item label="爱好" prop="hobby">
|
||||
<lay-select v-model="validateModel.hobby">
|
||||
<lay-select v-model="validateModel.hobby" multiple>
|
||||
<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>
|
||||
@ -410,14 +410,14 @@ export default {
|
||||
|
||||
| 属性 | 描述 | 类型 | 可选值 | 默认值 |
|
||||
| ------------- | -------------------------------------------------------------- | --------- | -------------- | ------- |
|
||||
| model | 表单绑定值 | `object` | - | {} |
|
||||
| v-model | 表单绑定值 | `object` | - | {} |
|
||||
| required | 是否必填 | `boolean` | `true` `false` | `false` |
|
||||
| rules | 表单校验规则; <br>可查看[async-validator](https://github.com/yiminghe/async-validator) | `object` | - | - |
|
||||
| initValidate | 是否一开始就校验表单 | `boolean` | `true` `false` | `false` |
|
||||
| useCN | 是否使用中文错误提示 | `boolean` | `true` `false` | `false` |
|
||||
| requiredIcons | 必填前缀图标`class` | `string` | - | `*` |
|
||||
| required-erroer-message | 必填错误提示信息 | `string` | - | `%s不能为空`|
|
||||
| validate-message | 自定义校验错误提示信息; <br>由于内置了中文错误提示,可按需求增量增加<br>可参考 [layui-vue 内置中文错误提示](https://gitee.com/layui-vue/layui-vue/tree/master/src/module/formItem/cnValidateMessage.ts) | `string` | - | `%s不能为空`|
|
||||
| validate-message | 自定义校验错误提示信息; <br>由于内置了中文错误提示,可按需求增量增加<br>可查看 [async-validator 内置错误提示](https://github.com/yiminghe/async-validator/blob/master/src/messages.ts)<br>也可参考 [layui-vue 内置中文错误提示](https://gitee.com/layui-vue/layui-vue/tree/develop/src/module/formItem/cnValidateMessage.ts) | `string` | - | `%s不能为空`|
|
||||
|
||||
:::
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<lay-select>
|
||||
<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>
|
||||
@ -16,8 +16,9 @@ import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
|
||||
const value = ref(null);
|
||||
return {
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,7 +34,7 @@ export default {
|
||||
<template>
|
||||
<lay-select v-model="selected">
|
||||
<lay-select-option value="1" label="学习"></lay-select-option>
|
||||
<lay-select-option value="2" label="编码" disabled="true"></lay-select-option>
|
||||
<lay-select-option value="2" label="编码" disabled></lay-select-option>
|
||||
<lay-select-option value="3" label="运动"></lay-select-option>
|
||||
</lay-select>
|
||||
</template>
|
||||
@ -55,15 +56,56 @@ export default {
|
||||
|
||||
:::
|
||||
|
||||
::: title 多选使用
|
||||
:::
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<lay-select v-model="mvalue" @change="change" multiple>
|
||||
<lay-select-option value="1" label="学习"></lay-select-option>
|
||||
<lay-select-option value="2" label="编码" disabled></lay-select-option>
|
||||
<lay-select-option value="3" label="运动"></lay-select-option>
|
||||
<lay-select-option value="4" label="唱歌"></lay-select-option>
|
||||
<lay-select-option value="5" label="跳舞"></lay-select-option>
|
||||
<lay-select-option value="6" label="打篮球"></lay-select-option>
|
||||
<lay-select-option value="7" label="rap"></lay-select-option>
|
||||
</lay-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const mvalue = ref(['1','2']);
|
||||
const change = function(val){
|
||||
console.log(val, mvalue.value)
|
||||
}
|
||||
return {
|
||||
mvalue,
|
||||
change
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title select 属性
|
||||
:::
|
||||
|
||||
::: table
|
||||
|
||||
| Name | Description | Accepted Values |
|
||||
| ------- | -------------- | --------------- |
|
||||
| name | 原生 name 属性 | -- |
|
||||
| v-model | 选中值 | -- |
|
||||
| 属性 | 描述 | 类型 | 可选值 | 默认值 |
|
||||
| ------------ | --------------------- | ------------------------- | -------------- | -------- |
|
||||
| v-model | 选中值 | `string`/`number`/`Array` | - | - |
|
||||
| name | 原生 name 属性 | `string` | - | - |
|
||||
| placeholder | 默认空提示语 | `string` | - | `请选择` |
|
||||
| disabled | 是否禁用 | `boolean` | `true` `false` | `false` |
|
||||
| showEmpty | 是否增加空提示选项 | `boolean` | `true` `false` | `true` |
|
||||
| multiple | 是否为多选 | `boolean` | `true` `false` | `false` |
|
||||
|
||||
|
||||
:::
|
||||
|
||||
@ -72,10 +114,14 @@ export default {
|
||||
|
||||
::: table
|
||||
|
||||
| Name | Description | Accepted Values |
|
||||
| ----- | ----------- | --------------- |
|
||||
| label | 标签 | -- |
|
||||
| value | 值 | -- |
|
||||
|
||||
::: table
|
||||
|
||||
| 属性 | 描述 | 类型 | 可选值 | 默认值 |
|
||||
| ------------ | --------------------- | ------------------------- | -------------- | -------- |
|
||||
| label | 标签值(`必填`) | `string` | - | - |
|
||||
| value | 值 | `string` / `number` | - | - |
|
||||
| disabled | 是否禁用 | `boolean` | `true` `false` | `false` |
|
||||
|
||||
:::
|
||||
|
||||
@ -84,9 +130,9 @@ export default {
|
||||
|
||||
::: table
|
||||
|
||||
| Name | Description | Accepted Values |
|
||||
| ------- | ----------- | --------------- |
|
||||
| default | 默认 | -- |
|
||||
| 属性 | 描述 | 接收值 |
|
||||
| ------- | ----------------- | --------------- |
|
||||
| default | 默认(`label`) | - |
|
||||
|
||||
:::
|
||||
|
||||
@ -95,8 +141,8 @@ export default {
|
||||
|
||||
::: table
|
||||
|
||||
| Name | Description | Accepted Values |
|
||||
| ------ | ----------- | --------------- |
|
||||
| 属性 | 描述 | 接收值 |
|
||||
| ------ | ---------- | --------------- |
|
||||
| change | 切换事件 | value |
|
||||
|
||||
:::
|
||||
|
@ -68,7 +68,7 @@ const ruleItems = computed(()=>{
|
||||
|
||||
// 值 计算 和 监听
|
||||
const filedValue = computed(()=> props.prop ? layForm.model[props.prop] : undefined);
|
||||
watch(()=>filedValue.value, (val)=> validate());
|
||||
watch(()=>filedValue.value, (val)=> validate(), {deep: true});
|
||||
|
||||
// 错误状态和信息
|
||||
const errorStatus = ref(false);
|
||||
|
41
src/module/select/index.less
Normal file
41
src/module/select/index.less
Normal file
@ -0,0 +1,41 @@
|
||||
dl.layui-anim-upbit>dd input[type=checkbox] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
dl.layui-anim-upbit>dd .layui-form-checkbox
|
||||
,.layui-form-item dl.layui-anim-upbit>dd .layui-form-checkbox[lay-skin] {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
// 多选样式
|
||||
.layui-multiple-select-row {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 30px;
|
||||
padding: 5px 0 5px 10px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
.layui-multiple-select-badge{
|
||||
width: ms-max-content;
|
||||
width: max-content;
|
||||
.layui-badge {
|
||||
margin-left: 5px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
&:first-of-type{
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
.layui-icon {
|
||||
font-size: 12px;
|
||||
padding-left: 3px;
|
||||
&:hover{
|
||||
cursor: pointer;
|
||||
color: #FF5722;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,27 +2,54 @@
|
||||
<div
|
||||
ref="selectRef"
|
||||
class="layui-unselect layui-form-select"
|
||||
:class="[openState ? 'layui-form-selected' : '']"
|
||||
:class="{'layui-form-selected' : openState}"
|
||||
>
|
||||
<div class="layui-select-title" @click="open">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="请选择"
|
||||
:value="selectItem.label"
|
||||
readonly=""
|
||||
: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"
|
||||
/><i class="layui-edge" />
|
||||
:class="['layui-input', 'layui-unselect', {'layui-disabled': disabled}]"
|
||||
/>
|
||||
<i :class="['layui-edge', {'layui-disabled': disabled}]" />
|
||||
<!-- 多选 -->
|
||||
<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"></lay-select-option>
|
||||
</template>
|
||||
<slot />
|
||||
</dl>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="LaySelect" lang="ts">
|
||||
import { defineProps, provide, reactive, ref, watch } from 'vue'
|
||||
import './index.less';
|
||||
import LaySelectOption from '../selectOption/index.vue'
|
||||
import { defineProps, provide, isProxy, ref, watch, computed, reactive, toRefs, Ref } from 'vue'
|
||||
import { useClickOutside } from '@layui/hooks-vue'
|
||||
import { SelectItem} from '../type'
|
||||
|
||||
const selectRef = ref<null | HTMLElement>(null)
|
||||
const isClickOutside = useClickOutside(selectRef)
|
||||
@ -33,35 +60,92 @@ watch(isClickOutside, () => {
|
||||
}
|
||||
})
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
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
|
||||
})
|
||||
|
||||
const openState = ref(false)
|
||||
|
||||
const open = function () {
|
||||
// 禁用
|
||||
if (props.disabled) {
|
||||
openState.value = false;
|
||||
return;
|
||||
}
|
||||
openState.value = !openState.value
|
||||
}
|
||||
|
||||
const selectItem = reactive({ label: null, value: props.modelValue })
|
||||
|
||||
provide('selectItem', selectItem)
|
||||
provide('openState', openState)
|
||||
|
||||
// select update 时, 通知 change 事件
|
||||
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
|
||||
} as SelectItem);
|
||||
|
||||
watch(selectItem, function (item) {
|
||||
emit('change', item.value)
|
||||
emit('update:modelValue', item.value)
|
||||
|
||||
watch(()=>selectItem.value.value, (val) =>{
|
||||
emit('update:modelValue', val)
|
||||
emit('change', val)
|
||||
}, {
|
||||
deep : true
|
||||
})
|
||||
|
||||
watch(()=>props.modelValue, function (value) {
|
||||
if (!value) {
|
||||
selectItem.label = null;
|
||||
selectItem.value = '';
|
||||
emit('update:modelValue', null);
|
||||
watch(()=>props.modelValue, (value) => {
|
||||
selectItem.value.value = value;
|
||||
if (!value && value !== 0) {
|
||||
props.multiple && (selectItem.value.value = []);
|
||||
selectItem.value.label = props.multiple ? [] : null;
|
||||
}
|
||||
})
|
||||
|
||||
// 禁止操作子项
|
||||
const disabledItemMap : {[key: string|number]:boolean} = {};
|
||||
const selectItemHandle = function(_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;
|
||||
}
|
||||
}
|
||||
|
||||
const removeItemHandle = function(e : MouseEvent, _selectItem : SelectItem) {
|
||||
e.stopPropagation();
|
||||
selectItemHandle(_selectItem, false);
|
||||
}
|
||||
|
||||
provide('selectItemHandle', selectItemHandle)
|
||||
provide('selectItem', selectItem)
|
||||
|
||||
</script>
|
||||
|
@ -2,47 +2,59 @@
|
||||
<dd
|
||||
:value="value"
|
||||
:class="[
|
||||
selectItem.value === value ? 'layui-this' : '',
|
||||
disabled ? 'layui-disabled' : '',
|
||||
{'layui-this' : selected},
|
||||
{'layui-disabled' : disabled}
|
||||
]"
|
||||
@click="selectHandle"
|
||||
>
|
||||
{{ label }}
|
||||
<template v-if="selectItem.multiple">
|
||||
<lay-checkbox skin="primary" v-model="selected" @change="selectHandle" label=""></lay-checkbox>
|
||||
</template>
|
||||
<slot>{{ label }}</slot>
|
||||
</dd>
|
||||
</template>
|
||||
|
||||
<script setup name="LaySelectOption" lang="ts">
|
||||
import { SelectItem } from '../type'
|
||||
import { defineProps, inject, onMounted, Ref } from 'vue'
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name : 'LaySelectOption'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LayCheckbox from '../checkbox';
|
||||
import { SelectItem, SelectItemHandle } from '../type'
|
||||
import { computed, defineProps, inject, onMounted, Ref} from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value: string
|
||||
label: string
|
||||
disabled?: boolean | string
|
||||
value: string | null | undefined
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
}
|
||||
)
|
||||
|
||||
const selectItem = inject('selectItem') as SelectItem
|
||||
const openState = inject('openState') as Ref<boolean>
|
||||
const selectItemHandle = inject('selectItemHandle') as SelectItemHandle
|
||||
const selectItem = inject('selectItem') as Ref<SelectItem>
|
||||
|
||||
const selectHandle = function () {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
openState.value = false
|
||||
selectItem.value = props.value
|
||||
selectItem.label = props.label
|
||||
!props.disabled && callSelectItemHandle(!selected.value);
|
||||
}
|
||||
|
||||
// init selected
|
||||
onMounted(() => {
|
||||
if (selectItem.value === props.value) {
|
||||
selectItem.value = props.value
|
||||
selectItem.label = props.label
|
||||
const callSelectItemHandle = function(isChecked ?: boolean){
|
||||
selectItemHandle({
|
||||
value : props.value,
|
||||
label : props.label,
|
||||
disabled : props.disabled
|
||||
}, isChecked);
|
||||
}
|
||||
const selected = computed(()=>{
|
||||
const selectValues = selectItem.value.value;
|
||||
if (Array.isArray(selectValues)) {
|
||||
return (selectValues as any[]).indexOf(props.value) > -1;
|
||||
}
|
||||
return selectItem.value.value === props.value
|
||||
})
|
||||
onMounted(() => selected.value && callSelectItemHandle())
|
||||
</script>
|
||||
|
@ -1,4 +1,11 @@
|
||||
export type SelectValueType = string | string[] | number | number[] | null;
|
||||
export interface SelectItem {
|
||||
label?: string
|
||||
value?: string
|
||||
value?: SelectValueType
|
||||
label?: null | string | string[]
|
||||
disabled ?: boolean
|
||||
multiple ?: boolean
|
||||
}
|
||||
|
||||
export interface SelectItemHandle {
|
||||
(selectItem: SelectItem, isChecked ?: boolean) : void
|
||||
}
|
Loading…
Reference in New Issue
Block a user