267 lines
6.5 KiB
Vue
267 lines
6.5 KiB
Vue
<script lang="ts">
|
|
export default {
|
|
name: "LayInput",
|
|
};
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import "./index.less";
|
|
import { LayIcon } from "@layui/icons-vue";
|
|
import { computed, ref, useSlots, watch } from "vue";
|
|
import PasswordIcon from "./svg/Password.vue";
|
|
import UnPasswordIcon from "./svg/unPassword.vue";
|
|
import { InputSize } from "./interface";
|
|
|
|
export interface InputProps {
|
|
name?: string;
|
|
type?: string;
|
|
prefixIcon?: string;
|
|
suffixIcon?: string;
|
|
modelValue?: string | number | string[] | undefined;
|
|
allowClear?: boolean;
|
|
autocomplete?: string;
|
|
placeholder?: string;
|
|
autofocus?: boolean;
|
|
disabled?: boolean;
|
|
readonly?: boolean;
|
|
password?: boolean;
|
|
size?: InputSize;
|
|
maxlength?: number;
|
|
max?: number;
|
|
min?: number;
|
|
qfw?: boolean;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<InputProps>(), {
|
|
disabled: false,
|
|
readonly: false,
|
|
allowClear: false,
|
|
autofocus: false,
|
|
password: false,
|
|
modelValue: "",
|
|
size: "md",
|
|
qfw: false,
|
|
});
|
|
|
|
interface InputEmits {
|
|
(e: "blur", event: Event): void;
|
|
(e: "input", value: string): void;
|
|
(e: "update:modelValue", value: string): void;
|
|
(e: "change", value: string): void;
|
|
(e: "focus", event: Event): void;
|
|
(e: "clear"): void;
|
|
}
|
|
|
|
const emit = defineEmits<InputEmits>();
|
|
|
|
const slots = useSlots();
|
|
const type = ref(props.type);
|
|
const currentValue = ref<string>(
|
|
String(props.modelValue == null ? "" : props.modelValue)
|
|
);
|
|
const hasContent = computed(() => (props.modelValue as string)?.length > 0);
|
|
const isPassword = computed(() => type.value == "password");
|
|
const composing = ref(false);
|
|
|
|
const formatMoney = function (s: string) {
|
|
if (s == "") {
|
|
return "";
|
|
}
|
|
var noNegative = true;
|
|
s = parseFloat((s + "").replace(/[^\d\.-]/g, "")) + "";
|
|
if (parseFloat(s) < 0) {
|
|
s = Math.abs(s) + "";
|
|
noNegative = false;
|
|
}
|
|
|
|
var l = s.split(".")[0].split("").reverse(),
|
|
r = s.split(".")[1];
|
|
var t = "";
|
|
for (let i = 0; i < l.length; i++) {
|
|
if (i % 3 == 2 && i != l.length - 1) {
|
|
t += l[i] + ",";
|
|
} else {
|
|
t += l[i] + ""; //加上空格
|
|
}
|
|
}
|
|
let z: any = (noNegative ? "" : "-") + t.split("").reverse().join("");
|
|
// z = isNaN(z) ? 0 : z;
|
|
if (r) {
|
|
return z + "." + r;
|
|
} else {
|
|
return isNaN(parseInt(z)) ? 0 : z;
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => props.type,
|
|
() => {
|
|
type.value = props.type;
|
|
}
|
|
);
|
|
const input: any = ref<Element>();
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
() => {
|
|
console.log(input);
|
|
if (!(input.value == document.activeElement) && props.qfw) {
|
|
currentValue.value = formatMoney(props.modelValue.toString());
|
|
return;
|
|
}
|
|
currentValue.value = String(
|
|
props.modelValue == null ? "" : props.modelValue
|
|
);
|
|
}
|
|
);
|
|
|
|
const onInput = function (event: Event) {
|
|
const inputElement = event.target as HTMLInputElement;
|
|
let value = inputElement.value;
|
|
emit("input", value);
|
|
if (composing.value) return;
|
|
if (props.qfw) {
|
|
value = value.replace(/,/g, "");
|
|
}
|
|
emit("update:modelValue", value);
|
|
};
|
|
|
|
const onClear = () => {
|
|
emit("update:modelValue", "");
|
|
emit("clear");
|
|
};
|
|
|
|
const onFocus = (event: Event) => {
|
|
currentValue.value = new String(props.modelValue).replace(/,/g, "");
|
|
emit("focus", event);
|
|
};
|
|
|
|
const onChange = (event: Event) => {
|
|
const inputElement = event.target as HTMLInputElement;
|
|
let value = inputElement.value;
|
|
if (props.qfw) {
|
|
value = value.replace(/,/g, "");
|
|
}
|
|
emit("change", value);
|
|
};
|
|
|
|
const onBlur = (event: Event) => {
|
|
if (props.type === "number") {
|
|
onNumberBlur(event);
|
|
}
|
|
if (props.qfw) {
|
|
try {
|
|
let reg = /\d{1,3}(?=(\d{3})+$)/g;
|
|
// new String(props.modelValue).replace(reg, '$&,');
|
|
console.log("添加,", formatMoney(props.modelValue.toString()));
|
|
currentValue.value = formatMoney(props.modelValue.toString());
|
|
} catch {
|
|
currentValue.value = "输入错误";
|
|
}
|
|
}
|
|
|
|
emit("blur", event);
|
|
};
|
|
|
|
const onNumberBlur = (event: Event) => {
|
|
let value = (event.target as HTMLInputElement).value;
|
|
if (value === "") {
|
|
value = props.min ? String(props.min) : "0";
|
|
} else {
|
|
if (props.max && props.max < Number(value)) value = props.max.toString();
|
|
if (props.min && props.min > Number(value)) value = props.min.toString();
|
|
}
|
|
if (props.qfw) {
|
|
value = value.replace(/,/g, "");
|
|
}
|
|
emit("update:modelValue", value);
|
|
};
|
|
|
|
const onCompositionstart = () => {
|
|
composing.value = true;
|
|
};
|
|
|
|
const onCompositionend = (event: Event) => {
|
|
composing.value = false;
|
|
onInput(event);
|
|
};
|
|
|
|
const classes = computed(() => {
|
|
return {
|
|
"layui-input-disabled": props.disabled,
|
|
"layui-input-has-prefix": slots.prefix || props.prefixIcon,
|
|
};
|
|
});
|
|
|
|
const showPassword = () => {
|
|
if (isPassword.value) {
|
|
type.value = "text";
|
|
} else {
|
|
type.value = "password";
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="layui-input" :class="classes" :size="size">
|
|
<div class="layui-input-prepend" v-if="slots.prepend">
|
|
<slot name="prepend"></slot>
|
|
</div>
|
|
<div class="layui-input-wrapper">
|
|
<span class="layui-input-prefix" v-if="slots.prefix || props.prefixIcon">
|
|
<slot name="prefix" v-if="slots.prefix"></slot>
|
|
<lay-icon
|
|
v-else
|
|
:type="props.prefixIcon"
|
|
class="layui-input-prefix-icon"
|
|
></lay-icon>
|
|
</span>
|
|
<input
|
|
:type="type"
|
|
:name="name"
|
|
:disabled="disabled"
|
|
:placeholder="placeholder"
|
|
:autofocus="autofocus"
|
|
:autocomplete="autocomplete"
|
|
:maxlength="maxlength"
|
|
:max="max"
|
|
:min="min"
|
|
:readonly="readonly"
|
|
:value="currentValue"
|
|
@input="onInput"
|
|
@change="onChange"
|
|
@focus="onFocus"
|
|
@blur="onBlur"
|
|
@compositionstart="onCompositionstart"
|
|
@compositionend="onCompositionend"
|
|
ref="input"
|
|
/>
|
|
<span
|
|
class="layui-input-password"
|
|
@click="showPassword"
|
|
v-if="password && hasContent"
|
|
>
|
|
<password-icon v-if="isPassword"></password-icon>
|
|
<un-password-icon v-else></un-password-icon>
|
|
</span>
|
|
<span
|
|
class="layui-input-clear"
|
|
v-if="allowClear && hasContent && !disabled"
|
|
>
|
|
<lay-icon type="layui-icon-close-fill" @click.stop="onClear"></lay-icon>
|
|
</span>
|
|
<span class="layui-input-suffix" v-if="slots.suffix || props.suffixIcon">
|
|
<slot name="suffix" v-if="slots.suffix"></slot>
|
|
<lay-icon
|
|
v-else
|
|
:type="props.suffixIcon"
|
|
class="layui-input-suffix-icon"
|
|
></lay-icon>
|
|
</span>
|
|
</div>
|
|
<div class="layui-input-append" v-if="slots.append">
|
|
<slot name="append"></slot>
|
|
</div>
|
|
</div>
|
|
</template>
|