参数支持:
参数名称 | 参数描述 | 参数类型 | 默认值 |
---|---|---|---|
placeholder | 占位符 | string | 无 |
type | 文本框类型(text/password) | string | text |
disabled | 禁用 | boolean | false |
clearable | 是否显示清空按钮 | boolean | false |
show-password | 是否显示密码切换按钮 | boolean | false |
name | name属性 | string | 无 |
事件支持:
事件名称 | 事件描述 |
---|---|
blur | 失去焦点事件 |
change | 内容改变事件 |
focus | 获取焦点事件 |
因为这部分与前面介绍的内容相同且比较简单,所以将这部分放在一起,不多做介绍了。
这里需要注意的是,disabled属性为true时,输入框禁用,并且需要改变样式,之前在button组件封装的时候也用到了相同的方法,获取到值后动态设置组件样式。
input组件的框架以及样式,获取到的数据以及数据处理:
<template>
<div class="one-input">
<input
class="one-input_inner"
:class="{'is-disabled': disabled}"
:placeholder="placeholder"
:type="type"
:name="name"
:disabled="disabled">
</div>
</template>
<script>
export default {
name: 'oneInput',
components: {
},
props: {
placeholder: {
type: String,
default: ''
},
type: {
type: String,
default: 'text'
},
name: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
}
},
data () {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped>
.one-input{
width: 100%;
position: relative;
font-size: 14px;
display: inline-block;
.one-input_inner{
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border: 1px solid #dcdfe6;
border-radius: 4px;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,045,.355,1);
width: 100%;
&:focus{
outline: none;
border-color: #409eff;
}
// input禁用样式
&.is-disabled{
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor:not-allowed;
}
}
}
</style>
父组件中传值也是与之前一样的:
<one-input placeholder="请输入密码" type="password" name="name" disabled=true></one-input>
当我们给一个input标签进行双向数据绑定时,我们需要使用value绑定数据,再使用input事件监听标签内数据的变动,如下:
<input :value="username" @input="username=$event.target.value"/>
在封装input组件时,这样显然是不合适的,所以这里我们需要使用到v-model语法糖。
显然,我们是不能给我们封装的input组件直接使用v-model绑定数据的,但是由于v-model的特性,他将value值绑定在了组件上,所以,我们组件内部通过接收value值的方式,就可以接收到传入的数据;并且v-model也实现了input事件,在组件内部绑定的input事件作为回调,把value值返回给父组件,这样就实现了input组件的双向绑定了。
父组件中的使用v-model绑定:
<one-input v-model="username"></one-input>
组件内部绑定value值以及实现回调:
//绑定value值和input事件
<input
class="one-input_inner"
:class="{'is-disabled': disabled}"
:placeholder="placeholder"
:type="type"
:name="name"
:value="value"
@input="handleInput"
:disabled=disabled>
//绑定input事件进行回调
handleInput (e) {
this.$emit('input', e.target.value)
}
当我们在组件中键入clearable属性时,我们希望组件可以有一个一键删除数据得功能。
当input组件的type属性是password时,我们希望在给与show-password属性时,可以有一个显示和隐藏密码的按钮。
实现这个两个功能,除了基本的父子组件传值外,还要添加i标签的icon字体图标,以及实现功能。
<div class="one-input" :class="{'one-input_suffix':showSuffix}">
<input
class="one-input_inner"
:class="{'is-disabled': disabled}"
:placeholder="placeholder"
:type="type"
:name="name"
:value="value"
@input="handleInput"
:disabled=disabled>
<span class="one-input_suffix">
<i class="on-input_icon one-icon-cancel" v-if="clearable && value" @click="clear"></i>
<i class="on-input_icon one-icon-visible" v-if="showPassword && type=='password'" @click="handlePassword"></i>
</span>
</div>
样式:
.one-input_suffix{
.one-input_inner{
padding-right: 30px;
}
.one-input_suffix{
position: absolute;
right: 10px;
height: 100%;
top: 0;
line-height: 40px;
text-align: center;
color: #c0c4cc;
transition: all .3s;
z-index: 900;
i{
color: #c0c4cc;
font-size: 14px;
cursor: pointer;
transition: color .2s cubic-bezier(.645,.045,.355,1);
}
}
}
5.3.1实现clearable功能
首先获取父组件传递的clearable值,然后给i标签绑定一个点击事件,这个事件触发input事件回调,当点击叉号字体图标时,将父组件的value清空:
clear () {
this.$emit('input', '')
}
5.3.2实现showPassword功能
实现showPassword功能的思路很简单,就是改变input的type类型即可。但是,我们不能直接改变父组件传递过来的type值,但是我们可以使用判断type值的方式,实现type的改变。
首先设置一个布尔类型的变量,并且设置点击事件改变这个变量:
data () {
return {
// 显示是否显示密码框
passwordVisible: false
}
},
methods: {
handlePassword () {
this.passwordVisible = !this.passwordVisible
}
}
然后我们需要在绑定type值时,进行两重判断。
第一步、判断showPassword是否为真;第二步、如果为真则通过passwordVisible去判断type为text还是password,以此来控制隐藏和现实,否则type值就为传入的type值即可:
:type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
--------------------------------------------------至此,input组件封装完成-------------------------------------------------
附组件全部代码:
<template>
<div class="one-input" :class="{'one-input_suffix':showSuffix}">
<input
class="one-input_inner"
:class="{'is-disabled': disabled}"
:placeholder="placeholder"
:type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
:name="name"
:value="value"
@input="handleInput"
:disabled=disabled>
<span class="one-input_suffix">
<i class="on-input_icon one-icon-cancel" v-if="clearable && value" @click="clear"></i>
<i class="on-input_icon one-icon-visible" v-if="showPassword && type=='password'" @click="handlePassword"></i>
</span>
</div>
</template>
<script>
export default {
name: 'oneInput',
components: {
},
props: {
placeholder: {
type: String,
default: ''
},
type: {
type: String,
default: 'text'
},
name: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
},
clearable: {
type: Boolean,
default: false
},
showPassword: {
type: Boolean,
default: false
}
},
watch: {},
computed: {
showSuffix () {
return this.clearable || this.showPassword
}
},
data () {
return {
// 显示是否显示密码框
passwordVisible: false
}
},
methods: {
handleInput (e) {
this.$emit('input', e.target.value)
},
clear () {
this.$emit('input', '')
},
handlePassword () {
this.passwordVisible = !this.passwordVisible
}
}
}
</script>
<style lang="scss" scoped>
.one-input{
width: 100%;
position: relative;
font-size: 14px;
display: inline-block;
.one-input_inner{
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border: 1px solid #dcdfe6;
border-radius: 4px;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,045,.355,1);
width: 100%;
&:focus{
outline: none;
border-color: #409eff;
}
// input禁用样式
&.is-disabled{
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor:not-allowed;
}
}
}
.one-input_suffix{
.one-input_inner{
padding-right: 30px;
}
.one-input_suffix{
position: absolute;
right: 10px;
height: 100%;
top: 0;
line-height: 40px;
text-align: center;
color: #c0c4cc;
transition: all .3s;
z-index: 900;
i{
color: #c0c4cc;
font-size: 14px;
cursor: pointer;
transition: color .2s cubic-bezier(.645,.045,.355,1);
}
}
}
</style>
参数支持:
参数名 | 参数描述 | 参数类型 | 默认值 |
---|---|---|---|
v-model | 双向绑定 | 布尔类型 | false |
name | name属性 | string | text |
activeColor | 自定义的激活颜色 | string | #1ec63b |
inactiveColor | 自定义的不激活颜色 | string | #dd001b |
事件支持:
事件名称 | 事件描述 |
---|---|
change | change时触发的事件 |
switch组件基本框架:
<template>
<div class="one-switch">
<span class="on-switch_core">
<span class="one-switch_button"></span>
</span>
</div>
</template>
switch组件样式:
<style lang="scss" scoped>
.one-switch{
display: inline-block;
align-items: center;
position: relative;
font-size: 14px;
line-height: 20px;
vertical-align: middle;
.one-switch_core{
margin: 0;
display: inline-block;
position: relative;
width: 40px;
height: 20px;
border: 1px solid #dcdfe6;
outline: none;
border-radius: 10px;
box-sizing: border-box;
background: #dcdfe6;
cursor: pointer;
transition: border-color .3s,background-color .3s;
vertical-align: middle;
.one-switch_button{
position:absolute;
top: 1px;
left: 1px;
border-radius: 100%;
transition: all .3s;
width: 16px;
height: 16px;
background-color: #fff;
}
}
}
</style>
实现switch组件数据双向绑定和input组件相同,使用v-model语法糖即可。
在父组件种通过v-model绑定数据,在组件内部获取value属性,并且定义一个回调函数与父组件通信,改变父组件中的绑定值即可。
父组件:
<one-switch v-model="active" ></one-switch>
子组件,点击时改变is-checked类状态,触发滑块滑动:
<div class="one-switch" :class="{'is-checked':value}" @click="handleClick">
<span class="one-switch_core">
<span class="one-switch_button"></span>
</span>
</div>
methods: {
handleClick () {
this.$emit('input', !this.value)
}
}
滑动样式:
// 选中样式
.is-checked {
.one-switch_core{
border-color: #409eff;
background-color: #409eff;
.one-switch_button {
transform: translateX(20px);
}
}
}
自定义switch组件的颜色,首先需要传入颜色的值,在子组件中获取后,使用ref获取节点,将背景颜色改变为对应颜色即可。
父组件传递色彩参数:
<one-switch
v-model="active"
active-color="#13ce66"
inactive-color="#ff4949"
></one-switch>
子组件中定义ref="core"以确定节点:
<div class="one-switch" :class="{'is-checked':value}" @click="handleClick">
<span class="one-switch_core" ref="core">
<span class="one-switch_button"></span>
</span>
</div>
通过mouted钩子和watch监听,在刚进入页面以及value改变时对颜色进行改变:
mounted () {
// 修改开关颜色
if (this.activeColor || this.inactiveColor) {
var color = !this.value ? this.activeColor : this.inactiveColor
this.$refs.core.style.borderColor = color
this.$refs.core.style.backgroundColor = color
}
},
watch: {
'value' (e) {
// 修改开关颜色
if (this.activeColor || this.inactiveColor) {
var color = !e ? this.activeColor : this.inactiveColor
this.$refs.core.style.borderColor = color
this.$refs.core.style.backgroundColor = color
}
}
}
用户在使用switch组件的时候,实质上是当成表单元素来使用的。因此可能会用到组件的name属性。所以需要在switch组件中添加一个checkbox,并且当值改变的时候,也需要设置checkbox的value值。
加入input标签:
<template>
<div class="one-switch" :class="{'is-checked':value}" @click="handleClick">
<span class="one-switch_core" ref="core">
<span class="one-switch_button"></span>
</span>
<input type="checkbox" class="one-switch_input" :name="name" ref="input">
</div>
</template>
设置标签样式,因为input标签只作为name绑定使用,所以将其隐藏起来:
// 隐藏input标签
.one-switch_input{
position:absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
我们在页面加载和点击时修改input的checked值,保证可以和value值同步:
mounted () {
// 修改开关颜色
if (this.activeColor || this.inactiveColor) {
var color = !this.value ? this.activeColor : this.inactiveColor
this.$refs.core.style.borderColor = color
this.$refs.core.style.backgroundColor = color
}
// 控制checkbox的值,input值同步value值
this.$refs.input.checked = this.value
},
methods: {
handleClick () {
this.$emit('input', !this.value)
// 控制checkbox的值,input值同步value值
this.$refs.input.checked = this.value
}
}
--------------------------------------------------------------至此,switch组件封装完成--------------------------------------------------
附switch组件代码:
<template>
<div class="one-switch" :class="{'is-checked':value}" @click="handleClick">
<span class="one-switch_core" ref="core">
<span class="one-switch_button"></span>
</span>
<input type="checkbox" class="one-switch_input" :name="name" ref="input">
</div>
</template>
<script>
export default {
name: 'oneSwitch',
components: {
},
props: {
value: {
type: Boolean,
defualt: false
},
activeColor: {
type: String,
defualt: ''
},
inactiveColor: {
type: String,
defualt: ''
},
name: {
type: String,
defualt: ''
}
},
mounted () {
// 修改开关颜色
if (this.activeColor || this.inactiveColor) {
var color = !this.value ? this.activeColor : this.inactiveColor
this.$refs.core.style.borderColor = color
this.$refs.core.style.backgroundColor = color
}
// 控制checkbox的值,input值同步value值
this.$refs.input.checked = this.value
},
watch: {
'value' (e) {
// 修改开关颜色
if (this.activeColor || this.inactiveColor) {
var color = !e ? this.activeColor : this.inactiveColor
this.$refs.core.style.borderColor = color
this.$refs.core.style.backgroundColor = color
}
}
},
data () {
return {}
},
methods: {
handleClick () {
this.$emit('input', !this.value)
// 控制checkbox的值,input值同步value值
this.$refs.input.checked = this.value
}
}
}
</script>
<style lang="scss" scoped>
.one-switch{
display: inline-block;
align-items: center;
position: relative;
font-size: 14px;
line-height: 20px;
vertical-align: middle;
.one-switch_core{
margin: 0;
display: inline-block;
position: relative;
width: 40px;
height: 20px;
border: 1px solid #dcdfe6;
outline: none;
border-radius: 10px;
box-sizing: border-box;
background: #dcdfe6;
cursor: pointer;
transition: border-color .3s,background-color .3s;
vertical-align: middle;
.one-switch_button{
position:absolute;
top: 1px;
left: 1px;
border-radius: 100%;
transition: all .3s;
width: 16px;
height: 16px;
background-color: #fff;
}
}
}
// 选中样式
.is-checked {
.one-switch_core{
border-color: #409eff;
background-color: #409eff;
.one-switch_button {
transform: translateX(20px);
}
}
}
// 隐藏input标签
.one-switch_input{
position:absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
</style>
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}