五、封装一个element-ui风格的input组件
参数支持:
参数名称
参数描述
参数类型
默认值
placeholder
占位符
string
无
type
文本框类型(text/password)
string
text
disabled
禁用
boolean
false
clearable
是否显示清空按钮
boolean
false
show-password
是否显示密码切换按钮
boolean
false
name
name属性
string
无
事件支持:
事件名称
事件描述
blur
失去焦点事件
change
内容改变事件
focus
获取焦点事件
5.1input组件的基本框架和样式以及处理placeholde、type、name、disabled
因为这部分与前面介绍的内容相同且比较简单,所以将这部分放在一起,不多做介绍了。
这里需要注意的是,disabled属性为true时,输入框禁用,并且需要改变样式,之前在button组件封装的时候也用到了相同的方法,获取到值后动态设置组件样式。
input组件的框架以及样式,获取到的数据以及数据处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78<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>
父组件中传值也是与之前一样的:
1
2<input :value="username" @input="username=$event.target.value"/>
5.2v-model语法糖——实现双向数据绑定
当我们给一个input标签进行双向数据绑定时,我们需要使用value绑定数据,再使用input事件监听标签内数据的变动,如下:
-
:value=“username” 使得我们可以设置变量修改表单的value的值 控制值
-
@input=“username=$event.target.value”/ 使得表单的值改动后会更新我们的变量 值反馈
<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绑定:
1
2<one-input v-model="username"></one-input>
- 注意v-model=“username” 等价于 :value=“username” @input=“username=$event.target.value” 子组件会接受到父组件传的value (注意需要接受)
- 组件内部需要修改value的值 但不能直接 this.value = e.target.value 无法直接修改父组件传过来的值 这里又用到了v-model的实质 这里通过传递事件的方式 触发@input方法 并把我们的值传过去
组件内部绑定value值以及实现回调:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//绑定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) }
5.3实现clearable功能和showPassword功能
当我们在组件中键入clearable属性时,我们希望组件可以有一个一键删除数据得功能。
当input组件的type属性是password时,我们希望在给与show-password属性时,可以有一个显示和隐藏密码的按钮。
实现这个两个功能,除了基本的父子组件传值外,还要添加i标签的icon字体图标,以及实现功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<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>
样式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23.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清空:
1
2
3
4clear () { this.$emit('input', '') }
5.3.2实现showPassword功能
实现showPassword功能的思路很简单,就是改变input的type类型即可。但是,我们不能直接改变父组件传递过来的type值,但是我们可以使用判断type值的方式,实现type的改变。
首先设置一个布尔类型的变量,并且设置点击事件改变这个变量:
1
2
3
4
5
6
7
8
9
10
11
12data () { return { // 显示是否显示密码框 passwordVisible: false } }, methods: { handlePassword () { this.passwordVisible = !this.passwordVisible } }
然后我们需要在绑定type值时,进行两重判断。
第一步、判断showPassword是否为真;第二步、如果为真则通过passwordVisible去判断type为text还是password,以此来控制隐藏和现实,否则type值就为传入的type值即可:
1
2:type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
切换显示按钮点击时的颜色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34<i class="my-input_icon my-icon-visible" v-if="showPassword && type == 'password'" @click="handlePassword" :class="{'my-icon-view-active':passwordVisible}" ></i> .my-input_suffix { .my-input_inner { padding-right: 30px; } .my-input_suffix { position: absolute; right: 10px; height: 100%; top: 0; line-height: 40px; text-align: center; color: #c0c4cc; transition: all 0.3s; z-index: 900; i { color: #c0c4cc; font-size: 14px; cursor: pointer; transition: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); } .my-icon-view-active { color: blue; } } }
--------------------------------------------------至此,input组件封装完成-------------------------------------------------
附组件全部代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149<template> <div class="my-input" :class="{ 'my-input_suffix': showSuffix }"> <input class="my-input_inner" :class="{ 'is-disabled': disabled }" :name="name" :type="showPassword ? (passwordVisible ? 'text' : 'password') : type" :placeholder="placeholder" :disabled="disabled" :value="value" @input="handleInput" /> <span class="my-input_suffix"> <i class="my-input_icon my-icon-cancel" v-if="clearable && value" @click="clear" ></i> <i class="my-input_icon my-icon-visible" v-if="showPassword && type == 'password'" @click="handlePassword" :class="{'my-icon-view-active':passwordVisible}" ></i> </span> </div> </template> <script> export default { name: "my-input", data() { return { // 显示是否显示密码框 passwordVisible: false }; }, props: { placeholder: { type: String, default: "", }, type: { type: String, default: "password", }, name: { type: String, default: "", }, disabled: { type: Boolean, default: false, }, value: { type: String, default: "", }, clearable: { type: Boolean, default: false, }, showPassword: { type: Boolean, default: false, }, }, computed: { showSuffix() { return this.clearable || this.showPassword } }, methods: { handleInput(e) { this.$emit("input", e.target.value); }, clear() { this.$emit("input", ""); }, handlePassword () { this.passwordVisible = !this.passwordVisible } }, }; </script> <style lang="scss" scoped> .my-input { width: 100%; position: relative; font-size: 14px; display: inline-block; .my-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 0.2s cubic-bezier(0.645, 045, 0.355, 1); width: 100%; &:focus { outline: none; border-color: #409eff; } // input禁用样式 &.is-disabled { background-color: #f5f7fa; border-color: #e4e7ed; color: #c0c4cc; cursor: not-allowed; } } } .my-input_suffix { .my-input_inner { padding-right: 30px; } .my-input_suffix { position: absolute; right: 10px; height: 100%; top: 0; line-height: 40px; text-align: center; color: #c0c4cc; transition: all 0.3s; z-index: 900; i { color: #c0c4cc; font-size: 14px; cursor: pointer; transition: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); } .my-icon-view-active { color: blue; } } } </style>
六、封装一个element-ui风格的switch组件
参数支持:
参数名
参数描述
参数类型
默认值
v-model
双向绑定
布尔类型
false
name
name属性
string
text
activeColor
自定义的激活颜色
string
#1ec63b
inactiveColor
自定义的不激活颜色
string
#dd001b
事件支持:
事件名称
事件描述
change
change时触发的事件
6.1switch组件的基本框架和样式
switch组件基本框架:
1
2
3
4
5
6
7
8<template> <div class="one-switch"> <span class="on-switch_core"> <span class="one-switch_button"></span> </span> </div> </template>
switch组件样式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36<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>
6.2实现switch组件的数据双向绑定
实现switch组件数据双向绑定和input组件相同,使用v-model语法糖即可。
在父组件种通过v-model绑定数据,在组件内部获取value属性,并且定义一个回调函数与父组件通信,改变父组件中的绑定值即可。
父组件:
1
2<one-switch v-model="active" ></one-switch>
子组件,点击时改变is-checked类状态,触发滑块滑动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<div class="one-switch" :class="{'is-checked':value}" @click="handleClick"> <span class="one-switch_core"> <span class="one-switch_button"></span> </span> </div> props: { value: { type: Boolean, default: false, }, }, methods: { handleClick () { this.$emit('input', !this.value) } }
滑动样式:
1
2
3
4
5
6
7
8
9
10
11// 选中样式 .is-checked { .one-switch_core{ border-color: #409eff; background-color: #409eff; .one-switch_button { transform: translateX(20px); } } }
6.3实现switch组件颜色自定义
自定义switch组件的颜色,首先需要传入颜色的值,在子组件中获取后,使用ref获取节点,将背景颜色改变为对应颜色即可。
父组件传递色彩参数:
1
2
3
4
5
6<one-switch -model="active" ctive-color="#13ce66" inactive-color="#ff4949" ></one-switch>
子组件中定义ref="core"以确定节点:
1
2
3
4
5
6<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>
方式1:通过mouted钩子和watch监听,在刚进入页面以及value改变时对颜色进行改变:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19mounted () { // 修改开关颜色 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 } } }
方式2: nexttick 解决子组件上传给父组件 父组件反馈子组件
-
首先在mounted加载后修改颜色值
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15methods: { setColor() { console.log(123); console.log(this.activeColor || this.inactiveColor); if(this.activeColor || this.inactiveColor){ let color = this.value?this.activeColor:this.inactiveColor; this.$refs.core.style.borderColor = color this.$refs.core.style.backgroundColor = color } } }, mounted() { this.setColor() }
发现颜色一致[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHEFfOvz-1658968721486)(switch.gif)]
因为switch是切换两种颜色 mounted只触发一次
-
绑定点击事件进行改动
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18methods: { handleClick() { this.$emit("input", !this.value); this.setColor() }, setColor() { if(this.activeColor || this.inactiveColor){ let color = this.value?this.activeColor:this.inactiveColor; console.log(color); this.$refs.core.style.borderColor = color this.$refs.core.style.backgroundColor = color } } }, mounted() { this.setColor() }
发现新的问题 初始状态switch状态时false 但是组件内查询到按钮事件点击后 switch状态依旧为false 因为状态更新后 父组件没有及时更新给子组件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5JYQRvY-1658968721487)(Animation.gif)]
-
添加this.$nexttick解决问题
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27//写法1 handleClick() { this.$emit("input", !this.value); this.$nextTick(() => { this.setColor(); }); }, //写法2 handleClick() { this.$emit("input", !this.value); this.$nextTick().then(() => { this.setColor(); }); }, //写法3 async handleClick() { this.$emit("input", !this.value); // this.$nextTick(() => { // this.setColor(); // }); // this.$nextTick().then(() => { // this.setColor(); // }); await this.$nextTick(); this.setColor(); },
6.4name属性支持
用户在使用switch组件的时候,实质上是当成表单元素来使用的。因此可能会用到组件的name属性。所以需要在switch组件中添加一个checkbox,并且当值改变的时候,也需要设置checkbox的value值。
加入input标签:
1
2
3
4
5
6
7
8
9<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绑定使用,所以将其隐藏起来:
1
2
3
4
5
6
7
8
9// 隐藏input标签 .one-switch_input{ position:absolute; width: 0; height: 0; opacity: 0; margin: 0; }
我们在页面加载和点击时修改input的checked值,保证可以和value值同步:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18mounted () { // 修改开关颜色 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组件代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117<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>
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
最后
以上就是刻苦小刺猬最近收集整理的关于vue封装自己的组件库 03.封装input+switch组件五、封装一个element-ui风格的input组件六、封装一个element-ui风格的switch组件的全部内容,更多相关vue封装自己的组件库内容请搜索靠谱客的其他文章。
发表评论 取消回复