从0搭建vue3组件库: Input组件(上)

简介: 从0搭建vue3组件库: Input组件(上)

image.png


基础用法



首先先新建一个input.vue文件,然后写入一个最基本的input输入框

<template>
  <div class="k-input">
    <input class="k-input__inner" />
  </div>
</template>

然后在我们的 vue 项目examples下的app.vue引入Input组件

<template>
  <div class="Shake-demo">
    <Input />
  </div>
</template>
<script lang="ts" setup>
import { Input } from "kitty-ui";
</script>

此时页面上便出现了原生的输入框,所以需要对这个输入框进行样式的添加,在input.vue同级新建style/index.less,Input样式便写在这里

.k-input {
  font-size: 14px;
  display: inline-block;
  position: relative;
  .k-input__inner {
    background-color: #fff;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    box-sizing: border-box;
    color: #606266;
    display: inline-block;
    font-size: inherit;
    height: 40px;
    line-height: 40px;
    outline: none;
    padding: 0 15px;
    width: 100%;
    &::placeholder {
      color: #c2c2ca;
    }
    &:hover {
      border: 1px solid #c0c4cc;
    }
    &:focus {
      border: 1px solid #409eff;
    }
  }
}

image.png

接下来要实现Input组件的核心功能:双向数据绑定。当我们在 vue 中使用input输入框的时候,我们可以直接使用v-model来实现双向数据绑定,v-model其实就是value @input结合的语法糖。而在 vue3 组件中使用v-model则表示的是modelValue @update:modelValue的语法糖。比如Input组件为例

<Input v-model="tel" />

其实就是


<Input :modelValue="tel" @update:modelValue="tel = $event" />

所以在input.vue中我们就可以根据这个来实现Input组件的双向数据绑定,这里我们使用setup语法

<template>
  <div class="k-input">
    <input
      class="k-input__inner"
      :value="inputProps.modelValue"
      @input="changeInputVal"
    />
  </div>
</template>
<script lang="ts" setup>
//组件命名
defineOptions({
  name: "k-input",
});
//组件接收的值类型
type InputProps = {
  modelValue?: string | number;
};
//组件发送事件类型
type InputEmits = {
  (e: "update:modelValue", value: string): void;
};
//withDefaults可以为props添加默认值等
const inputProps = withDefaults(defineProps<InputProps>(), {
  modelValue: "",
});
const inputEmits = defineEmits<InputEmits>();
const changeInputVal = (event: Event) => {
  inputEmits("update:modelValue", (event.target as HTMLInputElement).value);
};
</script>

image.png

到这里基础用法就完成了,接下来开始实现禁用状态


禁用状态



这个比较简单,只要根据propsdisabled来赋予禁用类名即可

<template>
  <div class="k-input" :class="styleClass">
    <input
      class="k-input__inner"
      :value="inputProps.modelValue"
      @input="changeInputVal"
      :disabled="inputProps.disabled"
    />
  </div>
</template>
<script lang="ts" setup>
//...
type InputProps = {
  modelValue?: string | number;
  disabled?: boolean;
};
//...
//根据props更改类名
const styleClass = computed(() => {
  return {
    "is-disabled": inputProps.disabled,
  };
});
</script>

然后给is-disabled写些样式

//...
.k-input.is-disabled {
  .k-input__inner {
    background-color: #f5f7fa;
    border-color: #e4e7ed;
    color: #c0c4cc;
    cursor: not-allowed;
    &::placeholder {
      color: #c3c4cc;
    }
  }
}

image.png


尺寸



按钮尺寸包括medium,small,mini,不传则是默认尺寸。同样的根据propssize来赋予不同类名

const styleClass = computed(() => {
  return {
    "is-disabled": inputProps.disabled,
    [`k-input--${inputProps.size}`]: inputProps.size,
  };
});

然后写这三个类名的不同样式

//...
.k-input.k-input--medium {
  .k-input__inner {
    height: 36px;
    &::placeholder {
      font-size: 15px;
    }
  }
}
.k-input.k-input--small {
  .k-input__inner {
    height: 32px;
    &::placeholder {
      font-size: 14px;
    }
  }
}
.k-input.k-input--mini {
  .k-input__inner {
    height: 28px;
    &::placeholder {
      font-size: 13px;
    }
  }
}


继承原生 input 属性



原生的inputtype,placeholder等属性,这里可以使用 vue3 中的useAttrs来实现props穿透.子组件可以通过v-bindprops绑定

<template>
  <div class="k-input" :class="styleClass">
    <input
      class="k-input__inner"
      :value="inputProps.modelValue"
      @input="changeInputVal"
      :disabled="inputProps.disabled"
      v-bind="attrs"
    />
  </div>
</template>
<script lang="ts" setup>
//...
const attrs = useAttrs();
</script>


可清空



通过clearable属性、Input的值是否为空以及是否鼠标是否移入来判断是否需要显示可清空图标。图标则使用组件库的Icon组件

<template>
  <div
    class="k-input"
    @mouseenter="isEnter = true"
    @mouseleave="isEnter = false"
    :class="styleClass"
  >
    <input
      class="k-input__inner"
      :disabled="inputProps.disabled"
      v-bind="attrs"
      :value="inputProps.modelValue"
      @input="changeInputVal"
    />
    <div
      @click="clearValue"
      v-if="inputProps.clearable && isClearAbled"
      v-show="isFoucs"
      class="k-input__suffix"
    >
      <Icon name="error" />
    </div>
  </div>
</template>
<script setup lang="ts">
//...
import Icon from "../icon/index";
//...
//双向数据绑定&接收属性
type InputProps = {
  modelValue?: string | number;
  disabled?: boolean;
  size?: string;
  clearable?: boolean;
};
//...
const isClearAbled = ref(false);
const changeInputVal = (event: Event) => {
  //可清除clearable
  (event.target as HTMLInputElement).value
    ? (isClearAbled.value = true)
    : (isClearAbled.value = false);
  inputEmits("update:modelValue", (event.target as HTMLInputElement).value);
};
//清除input value
const isEnter = ref(true);
const clearValue = () => {
  inputEmits("update:modelValue", "");
};
</script>

清除图标部分 css 样式

.k-input__suffix {
  position: absolute;
  right: 10px;
  height: 100%;
  top: 0;
  display: flex;
  align-items: center;
  cursor: pointer;
  color: #c0c4cc;
}

image.png


密码框 show-password



通过传入show-password属性可以得到一个可切换显示隐藏的密码框。这里要注意的是如果传了clearable则不会显示切换显示隐藏的图标

<template>
  <div
    class="k-input"
    @mouseenter="isEnter = true"
    @mouseleave="isEnter = false"
    :class="styleClass"
  >
    <input
      ref="ipt"
      class="k-input__inner"
      :disabled="inputProps.disabled"
      v-bind="attrs"
      :value="inputProps.modelValue"
      @input="changeInputVal"
    />
    <div class="k-input__suffix" v-show="isShowEye">
      <Icon @click="changeType" :name="eyeIcon" />
    </div>
  </div>
</template>
<script setup lang="ts">
//...
const attrs = useAttrs();
//...
//显示隐藏密码框 showPassword
const ipt = ref();
Promise.resolve().then(() => {
  if (inputProps.showPassword) {
    ipt.value.type = "password";
  }
});
const eyeIcon = ref("browse");
const isShowEye = computed(() => {
  return (
    inputProps.showPassword && inputProps.modelValue && !inputProps.clearable
  );
});
const changeType = () => {
  if (ipt.value.type === "password") {
    eyeIcon.value = "eye-close";
    ipt.value.type = attrs.type || "text";
    return;
  }
  ipt.value.type = "password";
  eyeIcon.value = "browse";
};
</script>

这里是通过获取input元素,然后通过它的type属性进行切换,其中browseeye-close分别是Icon组件中眼睛开与闭,效果如下

image.png


相关文章
|
6天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
19 7
|
7天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
25 3
|
6天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
24 1
|
6天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
25 1
|
9天前
|
前端开发 JavaScript
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
|
10天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
3天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
3天前
|
存储 JavaScript
Vue 状态管理工具vuex
Vue 状态管理工具vuex
|
10天前
|
缓存 JavaScript 搜索推荐
Vue SSR(服务端渲染)预渲染的工作原理
【10月更文挑战第23天】Vue SSR 预渲染通过一系列复杂的步骤和机制,实现了在服务器端生成静态 HTML 页面的目标。它为提升 Vue 应用的性能、SEO 效果以及用户体验提供了有力的支持。随着技术的不断发展,Vue SSR 预渲染技术也将不断完善和创新,以适应不断变化的互联网环境和用户需求。
29 9
|
9天前
|
缓存 JavaScript UED
Vue 中实现组件的懒加载
【10月更文挑战第23天】组件的懒加载是 Vue 应用中提高性能的重要手段之一。通过合理运用动态导入、路由配置等方式,可以实现组件的按需加载,减少资源浪费,提高应用的响应速度和用户体验。在实际应用中,需要根据具体情况选择合适的懒加载方式,并结合性能优化的其他措施,以打造更高效、更优质的 Vue 应用。