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

This commit is contained in:
sight 2021-12-20 23:36:55 +08:00
commit 545d8ac48a
7 changed files with 259 additions and 69 deletions

View File

@ -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不能为空`|
:::

View File

@ -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 |
:::

View File

@ -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);

View 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;
}
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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
}