在观看element的源码以后,开始封装自己的input组件,相对于源码封装还有很多不完善,后期后继续努力。
一、实现功能
1. input中内容的删除图标,2. 密码的加密和解密,3. input的获取焦点和失去焦点事件。
4. placeHolder和禁用等。5. 自动获取焦点。
其中的字体图标需要自己去图标库自己下载哦。
二、子组件接受的属性
props: {
value: [String, Number],
placeholder: {
type: String,
default: "请输入"
},
disabled: {
type: Boolean,
default: false
},
type: {
type: String,
default: "text"
},
prefixIcon: String,
suffixIcon: String,
showPasswrod: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
autoFoucs: {
type: Boolean,
default: false
}
},
三、功能实现
和源码相差还很大,自己完善完善一起学习吧。
代码如下:
<template>
<div
:class="[
type === 'textarea' ? 'zc-textarea' : 'zc-input',
{
'zc-input-group--prepend': $slots.prepend,
'zc-input-group--append': $slots.append,
'zc-input-group': $slots.prepend || $slots.append,
'zc-input--prefix': $slots.prefix || prefixIcon,
'zc-input--suffix': $slots.suffix || suffixIcon
}
]"
>
<template v-if="type !== 'textarea'">
<!-- 前置元素 -->
<div v-if="$slots.prepend" class="zc-input-group__prepend">
<slot name="prepend"></slot>
</div>
<input
:type="showPasswrod ? (passwordVisible ? 'text' : 'password') : type"
:disabled="disabled"
@focus="handleFocus"
@blur="handelBlur"
@change="handleChange"
@input="handleInput"
ref="input"
:placeholder="placeholder"
class="el-input_inner"
:class="getClass"
/>
<!-- 前置内容 -->
<span class="zc-input__prefix" v-if="$slots.prefix || prefixIcon">
<slot name="prefix"></slot>
<i class="zc-input__icon" v-if="prefixIcon" :class="prefixIcon"></i>
</span>
<!-- 后置内容 -->
<span class="zc-input__suffix">
<template v-if="!showPasswrod">
<slot name="suffix"></slot>
<i class="zc-input__icon" v-if="suffixIcon" :class="suffixIcon"></i>
</template>
<!-- 密码展示 -->
<i
class="zc-input__icon zc-input_show"
:class="passwordVisible ? 'zc-icon-shared' : 'zc-icon-collect'"
v-if="showPasswrod && nativeInputValue() && !disabled"
@click="handlePasswordVisible"
></i>
<!-- 清空按钮 -->
<i
class="zc-input__icon zc-input_clear"
:class="clearable && nativeInputValue() ? 'zc-icon-shared' : ''"
@mousedown.prevent
@click="handleClear"
></i>
</span>
<!-- 后置元素 -->
<div class="zc-input-group__append" v-if="$slots.append">
<slot name="append"></slot>
</div>
</template>
</div>
</template>
js代码
<script>
export default {
name: "ZcInput",
data() {
return {
passwordVisible: false,
focus: false
}
},
props: {
value: [String, Number],
placeholder: {
type: String,
default: "请输入"
},
disabled: {
type: Boolean,
default: false
},
type: {
type: String,
default: "text"
},
prefixIcon: String,
suffixIcon: String,
showPasswrod: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
autoFoucs: {
type: Boolean,
default: false
}
},
computed: {
getClass() {
return [
{ "is-disabled": this.disabled, "zc-input_inner": this.$slots.prepend }
]
}
},
mounted() {
// this.setNativeInputValue()
// eslint-disable-next-line eqeqeq
if (this.autoFoucs) {
this.$refs.input.focus()
}
},
methods: {
nativeInputValue() {
return this.value === null || this.value === undefined
? ""
: String(this.value)
},
getInput() {
return this.$refs.input || this.$refs.textarea
},
handleFocus(event) {
this.focus = true
this.$emit("focus", event)
},
handelBlur(event) {
this.focus = false
this.$emit("blur", event)
},
handlePasswordVisible() {
this.passwordVisible = !this.passwordVisible
},
setNativeInputValue() {
const input = this.getInput()
if (!input) return
if (input.value === this.nativeInputValue()) return
input.value = this.nativeInputValue()
},
handleClear() {
this.$emit("input", "")
this.$emit("change", "")
this.$emit("clear")
this.$nextTick(() => {
this.setNativeInputValue()
})
},
handleInput(event) {
// should not emit input during composition
// see: https://github.com/ElemeFE/element/issues/10516
// if (this.isComposing) return
// hack for https://github.com/ElemeFE/element/issues/8548
// should remove the following line when we don't support IE
// if (event.target.value === this.nativeInputValue) return
this.$emit("input", event.target.value)
// ensure native input value is controlled
// see: https://github.com/ElemeFE/element/issues/12850
// this.$nextTick(this.setNativeInputValue())
},
handleChange(event) {
this.$emit("change", event.target.value)
}
}
}
</script>
css样式
<style lang="scss">
.zc-input {
position: relative;
width: 100%;
font-size: 14px;
display: inline-block;
}
.el-input_inner {
width: 100%;
height: 40px;
border: 1px solid #dcdfe6;
padding: 0 15px;
box-sizing: border-box;
border-radius: 4px;
color: #606266;
font-size: inherit;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
&:focus {
outline: none;
border-color: #409eff;
}
}
.zc-input_inner {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.is-disabled {
cursor: not-allowed;
background: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
}
.zc-input-group {
display: inline-table;
border-spacing: 0;
}
.zc-input-group__append,
.zc-input-group__prepend {
display: table-cell;
background: #f5f7fa;
color: #909399;
width: 1px;
padding: 0 20px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
border-radius: 4px;
}
.zc-input-group__prepend {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 0;
}
.zc-input__prefix {
position: absolute;
top: 0;
left: 5px;
color: #c0c4cc;
}
.zc-input__icon,
.zc-input__prefix {
height: 100%;
text-align: center;
transition: all 0.3s;
}
.zc-input__icon {
width: 25px;
line-height: 40px;
}
.zc-input--prefix .el-input_inner {
padding-left: 30px;
}
.zc-input--suffix .el-input_inner {
padding-right: 30px;
}
.zc-input__suffix {
position: absolute;
right: 5px;
top: 0;
color: #c0c4cc;
}
.zc-input_clear,
.zc-input_show {
cursor: pointer;
}
.zc-input-group__append {
border-left: 0;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.zc-input-group--append .el-input_inner {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
</style>