Vue 進階之從 0 到 1 搭建元件庫(四)
阿新 • • 發佈:2021-01-03
Vue 進階之從 0 到 1 搭建元件庫(四)
Vue 進階之從 0 到 1 搭建元件庫(四)
4 Input 元件
4.1 引數支援
引數名稱 | 引數描述 | 引數型別 | 預設值 |
---|---|---|---|
placeholder | 佔位符 | string | 無 |
type | 文字框型別(text/password | string | text |
disabled | 禁用 | boolean | false |
clearable | 是否顯示清空按鈕 | boolean | false |
show-password | 是否顯示密碼切換按鈕 | boolean | false |
name | name 屬性 | string | 無 |
4.2 事件支援
事件名稱 | 事件描述 |
---|---|
blur | 失去焦點事件 |
change | 內容改變事件 |
focus | 獲取焦點事件 |
4.3 基本結構
- 初始化,步驟與前面元件相同
components
資料夾下新建input
資料夾,input
資料夾下新建檔案index.vue
和index.scss
src/components/input/index.vue
<template> <
main.js
中註冊input
元件
// 引入 Input 元件 import HmInput from './components/input/index' // 全域性註冊 Vue.
App.vue
中使用input
,此時瀏覽器頁面應該有input元件
字樣
<template> <div id="app"> <hm-input></hm-input> </div> </template>
- 基本結構
<template>
<div class="hm-input">
<input type="text" class="hm-input__inner" />
</div>
</template>
<script>
export default {
name: 'HmInput'
}
</script>
<style lang="scss">
@import 'index.scss';
</style>
- 樣式
index.scss
.hm-input {
width: 180px;
position: relative;
font-size: 14px;
display: inline-block;
.hm-input__inner {
cursor: pointer;
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
color: #000;
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, 0.045, 0.355, 1);
width: 100%;
&:focus {
outline: none;
border-color: #409eff;
}
&.is-disabled {
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor: not-allowed;
}
}
}
.hm-input--suffix {
.hm-input__inner {
padding-right: 30px;
}
.hm-input__suffix {
position: absolute;
height: 100%;
right: 10px;
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);
}
}
}
- 效果
4.4 placeholder
, type
, name
, disabled
屬性
- 都是通過
props
來實現的,直接貼程式碼
<template>
<div class="hm-input">
<input
:type="type"
:placeholder="placeholder"
:name="name"
:disabled="disabled"
:class="[
'hm-input__inner',
{
'is-disabled': disabled
}
]"
/>
</div>
</template>
<script>
export default {
name: 'HmInput',
props: {
placeholder: {
type: String,
default: ''
},
type: {
// input 型別:text | password
type: String,
default: 'text'
},
name: {
type: String,
default: ''
},
disabled: {
// 禁用
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss">
@import 'index.scss';
</style>
- 使用
<template>
<div id="app">
<hm-input placeholder="請輸入使用者名稱" name="username"></hm-input>
<br /><br />
<hm-input placeholder="請輸入密碼" type="password"></hm-input>
<br /><br />
<hm-input placeholder="請輸入使用者名稱" disabled></hm-input>
</div>
</template>
- 效果
4.5 v-model
語法糖
v-model
對資料進行雙向繫結,如下就是將input
的輸入內容與屬性username
繫結在一起,當我們在inpunt
中輸入內容時候,該Vue
例項的username
屬性也同步改變,當我們修改Vue
例項的username
,input
框中內容也隨之而改變
<template>
<div id="app">
<input type="text" v-model="username" />
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'zhangsan'
}
}
}
</script>
v-model
本質是一個語法糖,等價於以下寫法
<template>
<div id="app">
<input type="text" :value="username" @input="username = $event.target.value" />
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'zhangsan'
}
}
}
</script>
- 將
v-model
封裝至我們的元件中- 首先看看如何使用
<template> <div id="app"> <hm-input placeholder="請輸入使用者名稱" v-model="username"></hm-input> </div> </template> <script> export default { name: 'App', data() { return { username: 'zhangsan' } } } </script>
- 由上述對
v-model
本質的剖析,可以知道:
a. 上面的寫法可以翻譯成:<hm-input placeholder="請輸入使用者名稱" v-model="username"></hm-input>
<hm-input placeholder="請輸入使用者名稱" :value="username" @input="username=newValue"></hm-input>
- 所以可以在
input
元件中這樣進行封裝
a. 接收value
屬性,將其賦給元件內部的input
框
b. 當元件內部input
框觸發input
事件時,將該事件通過$emit
派發出去
- 程式碼:
<template>
<div class="hm-input">
<input
:type="type"
:placeholder="placeholder"
:name="name"
:disabled="disabled"
:value="value"
:class="[
'hm-input__inner',
{
'is-disabled': disabled
}
]"
@input="handleInput"
/>
</div>
</template>
<script>
export default {
name: 'HmInput',
props: {
placeholder: {
type: String,
default: ''
},
type: {
// input 型別
type: String,
default: 'text'
},
name: {
type: String,
default: ''
},
disabled: {
// 禁用
type: Boolean,
default: false
},
value: {
type: String,
default: ''
}
},
methods: {
handleInput(e) {
this.$emit('input', e.target.value)
}
}
}
</script>
- 使用:
<template>
<div id="app">
<hm-input placeholder="請輸入使用者名稱" v-model="username" name="username"></hm-input>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'zhangsan'
}
}
}
</script>
- 效果
4.6 clearable
和 show-password
功能
- 結構:
- 元件接收
clearable
和show-password
屬性 - 當
clearable
或show-password
為true
的時候,新增hm-input--suffix
樣式,顯示包含小圖示的span
- 定義一個計算屬性
showSuffix
動態控制hm-input--suffix
樣式以及span
標籤圖示的動態顯示 - 根據上一節實現
v-model
的邏輯,清空內容只需要this.$emit('input', '')
即可,另外需要注意的是,只有當clearable
為true
且input
的value
有值時,才顯示清空按鈕 - 顯示密碼的基本思路是將
input
框的型別由password
改為text
a. 首先不能直接修改props
的type
屬性,所以單獨在data
中定義一個passwordVisiable
屬性來標識
b. 動態控制type
屬性::type="showPassword ? (passwordVisiable ? 'text' : 'password') : type"
c. 當選中的時候給圖示添加個樣式
- 元件接收
<template>
<div :class="['hm-input', { 'hm-input--suffix': showSuffix }]">
<!-- 如果傳了showPassword, 判斷是否需要切換密碼的顯示 如果不傳 不判斷 -->
<input
:type="showPassword ? (passwordVisiable ? 'text' : 'password') : type"
:placeholder="placeholder"
:name="name"
:disabled="disabled"
:value="value"
:class="[
'hm-input__inner',
{
'is-disabled': disabled
}
]"
@input="handleInput"
/>
<span v-if="showSuffix" class="hm-input__suffix">
<!-- 清空按鈕 -->
<i v-if="clearable && value" class="hm-input__icon hm-icon-circle-close" @click="clear"></i>
<!-- 顯示密碼 -->
<i
v-if="showPassword"
:class="[
'hm-input__icon',
'hm-icon-view',
{
'hm-icon-view-active': passwordVisiable
}
]"
@click="handlePassword"
></i>
</span>
</div>
</template>
<script>
export default {
name: 'HmInput',
props: {
placeholder: {
type: String,
default: ''
},
type: {
// input 型別
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
}
},
data() {
return {
// 用於控制是否顯示密碼框
passwordVisiable: false
}
},
computed: {
showSuffix() {
return this.clearable || this.showPassword
}
},
methods: {
// ......
clear() {
// 把內容清空
this.$emit('input', '')
},
handlePassword() {
this.passwordVisiable = !this.passwordVisiable
}
}
}
</script>
- 樣式
.hm-input--suffix {
.hm-input__inner {
padding-right: 30px;
}
.hm-input__suffix {
position: absolute;
height: 100%;
right: 10px;
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);
&.hm-icon-view-active {
color: blue;
}
}
}
}
- 使用
<template>
<div id="app">
<hm-input placeholder="請輸入使用者名稱" v-model="username" name="username" clearable></hm-input>
<br /><br />
<hm-input placeholder="請輸入密碼" v-model="password" type="password" show-password></hm-input>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: 'zhangsan',
password: ''
}
}
}
</script>
- 效果