init
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
::: anchor
|
||||
:::
|
||||
|
||||
::: title 基本介绍
|
||||
:::
|
||||
|
||||
::: describe 通过鼠标或键盘,输入范围内的数值。
|
||||
:::
|
||||
|
||||
::: title 基础使用
|
||||
:::
|
||||
|
||||
::: demo 使用 `lay-tag-input` 标签, 创建标签输入框。
|
||||
|
||||
<template>
|
||||
<lay-tag-input
|
||||
v-model="data1"
|
||||
v-model:inputValue="inputValue1"
|
||||
allowClear
|
||||
placeholder="请输入"
|
||||
style="width:320px"
|
||||
>
|
||||
</lay-tag-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data1 = ref([{value:1,label:'Vue',closable: true}]);
|
||||
const inputValue1 = ref("");
|
||||
|
||||
return {
|
||||
data1,
|
||||
inputValue1
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 数量限制
|
||||
:::
|
||||
|
||||
::: demo 使用 `max` 控制最大标签数量。
|
||||
|
||||
<template>
|
||||
<lay-tag-input v-model="data2" v-model:inputValue="inputValue2" :max="3" placeholder="最多输入3个" style="width:320px"></lay-tag-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data2 = ref([]);
|
||||
const inputValue2 = ref("");
|
||||
|
||||
return {
|
||||
data2,
|
||||
inputValue2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 折叠标签
|
||||
:::
|
||||
|
||||
::: demo 通过`minCollapsedNum` 设置最小折叠数,超过这个数的标签会被折叠,0表示不折叠, `collapseTagsTooltip`启用鼠标悬停显示具体折叠标签。
|
||||
|
||||
<template>
|
||||
<lay-space direction="vertical" size="md">
|
||||
minCollapsedNum = 3<lay-tag-input v-model="data3" v-model:inputValue="inputValue3" :minCollapsedNum="3" style="width:auto"></lay-tag-input>
|
||||
collapseTagsTooltip <lay-tag-input v-model="data3" v-model:inputValue="inputValue3" :minCollapsedNum="3" collapseTagsTooltip style="width:auto"></lay-tag-input>
|
||||
</lay-space>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data3 = ref(['标签1','标签2','标签3','标签4']);
|
||||
const inputValue3 = ref("");
|
||||
|
||||
return {
|
||||
data3,
|
||||
inputValue3
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 禁用状态
|
||||
:::
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<lay-tag-input v-model="data4" v-model:inputValue="inputValue4" disabled style="width:320px"></lay-tag-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data4 = ref(['标签1','标签2']);
|
||||
const inputValue4 = ref("");
|
||||
|
||||
return {
|
||||
data4,
|
||||
inputValue4
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 允许清空
|
||||
:::
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<lay-tag-input v-model="data5" v-model:inputValue="inputValue5" allow-clear style="width:320px"></lay-tag-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data5 = ref(['标签1','标签2']);
|
||||
const inputValue5 = ref("");
|
||||
|
||||
return {
|
||||
data5,
|
||||
inputValue5
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 不同尺寸
|
||||
:::
|
||||
|
||||
::: demo
|
||||
|
||||
<template>
|
||||
<div style="width:320px;display:flex;flex-direction: column;gap: 16px;">
|
||||
<lay-tag-input v-model="data6" v-model:inputValue="inputValue6" size="xs"></lay-tag-input>
|
||||
<lay-tag-input v-model="data6" v-model:inputValue="inputValue6" size="sm"></lay-tag-input>
|
||||
<lay-tag-input v-model="data6" v-model:inputValue="inputValue6" size="md"></lay-tag-input>
|
||||
<lay-tag-input v-model="data6" v-model:inputValue="inputValue6" size="lg"></lay-tag-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data6 = ref(['标签1','标签2']);
|
||||
const inputValue6 = ref("");
|
||||
|
||||
return {
|
||||
data6,
|
||||
inputValue6
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title 不同主题
|
||||
:::
|
||||
|
||||
::: demo 使用 `tagProps` 控制标签属性。
|
||||
|
||||
<template>
|
||||
<lay-space direction="vertical" fill style="width:320px">
|
||||
<lay-tag-input v-model="data7" v-model:inputValue="inputValue7" :tagProps="{color:'#86909c',variant:'light', bordered:false}"></lay-tag-input>
|
||||
<lay-tag-input v-model="data7" v-model:inputValue="inputValue7" :tagProps="{color:'#ffb400',variant:'light'}"></lay-tag-input>
|
||||
<lay-tag-input v-model="data7" v-model:inputValue="inputValue7" :tagProps="{color:'#0fc6c2',variant:'light'}"></lay-tag-input>
|
||||
<lay-tag-input v-model="data7" v-model:inputValue="inputValue7" :tagProps="{color:'#409EFF',variant:'light'}"></lay-tag-input>
|
||||
</lay-space>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref,watch } from 'vue'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const data7 = ref(['标签1','标签2']);
|
||||
const inputValue7 = ref("");
|
||||
|
||||
return {
|
||||
data7,
|
||||
inputValue7
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
::: title TagInput 属性
|
||||
:::
|
||||
|
||||
::: table
|
||||
|
||||
| 属性 | 描述 | 类型 | 默认值 | 可选值 |
|
||||
| ----------- | -------- | ------ | ------ | ------ |
|
||||
| modelValue | 绑定值 | `string[]` `number[]` `TagData[]`| -| -|
|
||||
| size | 输入框大小 |`string` | `md` | `lg` `md` `sm` `xs`|
|
||||
| inputValue | 输入框的值 | `string` | -| - |
|
||||
| placeholder | 占位符 | `string` | - | - |
|
||||
| readonly | 是否可只读 | `boolean` | `false` | `true` `false`|
|
||||
| allowClear | 允许清空 | `boolean` | `false` | `true` `false`|
|
||||
| disabled | 是否禁用 | `boolean` | `false` | `true` `false`|
|
||||
| max | 最大输入标签数量 | `number` | -|-|
|
||||
| minCollapsedNum | 最小折叠数量 | `number`| - | -|
|
||||
| collapseTagsTooltip|是否悬浮显示折叠标签| `boolean` | `false` | `true` `false`|
|
||||
| tagProps| tag 属性| `LayTagProps`|-|-|
|
||||
| disabledInput|是否禁用内部输入框|`boolean` | `false` | `true` `false`|
|
||||
|
||||
:::
|
||||
|
||||
:::title TagInput 事件
|
||||
:::
|
||||
|
||||
:::table
|
||||
| 名称 | 描述 | 参数 |
|
||||
|------ |----------|-----------|
|
||||
| change | 值改变时触发 | (value: (string | number | TagData)[]) |
|
||||
| inputValueChange |输入框值改变时触发 | (inputValue: string) |
|
||||
| remove|删除标签时触发| (value: string | number, e: Event) |
|
||||
| clear | 点击清除按钮时触发| (e: Event) |
|
||||
| focus | 获得焦点时触发| (e: Event) |
|
||||
| blur | 失去焦点时触发| (e: Event) |
|
||||
| pressEnter| 按下 Enter 键时触发| (inputValue: string, e: Event) |
|
||||
:::
|
||||
|
||||
:::title TagInput 方法
|
||||
:::
|
||||
|
||||
:::table
|
||||
| 名称 | 描述 | 参数 |
|
||||
|------ |----------|-----------|
|
||||
| focus | 获取焦点 | - |
|
||||
| blur |失去焦点 | - |
|
||||
:::
|
||||
|
||||
:::title TagInput 插槽
|
||||
:::
|
||||
|
||||
:::table
|
||||
| 插槽 | 描述 | 参数 |
|
||||
|------ |----------|-----------|
|
||||
| prefix | 前置插槽 | - |
|
||||
| suffix | 后置插槽 | - |
|
||||
:::
|
||||
@@ -0,0 +1,17 @@
|
||||
## 背景
|
||||
|
||||
- 1.描述你希望解决的问题
|
||||
|
||||
- 2.陈述问题的现状
|
||||
|
||||
- 3.合理的建议
|
||||
|
||||
- 4.当前版本
|
||||
|
||||
## 思路
|
||||
|
||||
描述大概的解决思路,可以包含 API 设计和伪代码等
|
||||
|
||||
## 跟进
|
||||
|
||||
后续编辑,附上对应的 Pull Request 地址,可以用 `- [ ] some task` 的方式。
|
||||
@@ -0,0 +1,206 @@
|
||||
<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;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<InputProps>(), {
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
allowClear: false,
|
||||
autofocus: false,
|
||||
password: false,
|
||||
modelValue: "",
|
||||
size: "md",
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
watch(
|
||||
() => props.type,
|
||||
() => {
|
||||
type.value = props.type;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
currentValue.value = String(
|
||||
props.modelValue == null ? "" : props.modelValue
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const onInput = function (event: Event) {
|
||||
const inputElement = event.target as HTMLInputElement;
|
||||
const value = inputElement.value;
|
||||
emit("input", value);
|
||||
if (composing.value) return;
|
||||
emit("update:modelValue", value);
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
emit("update:modelValue", "");
|
||||
emit("clear");
|
||||
};
|
||||
|
||||
const onFocus = (event: Event) => {
|
||||
emit("focus", event);
|
||||
};
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const inputElement = event.target as HTMLInputElement;
|
||||
const value = inputElement.value;
|
||||
emit("change", value);
|
||||
};
|
||||
|
||||
const onBlur = (event: Event) => {
|
||||
if (props.type === "number") {
|
||||
onNumberBlur(event);
|
||||
}
|
||||
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();
|
||||
}
|
||||
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"
|
||||
/>
|
||||
<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>
|
||||
@@ -0,0 +1,3 @@
|
||||
import "../badge/index2.js";
|
||||
export { c as default } from "./index2.js";
|
||||
import "vue";
|
||||
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
Reference in New Issue
Block a user