1. 程式人生 > 其它 >Vue 進階之從 0 到 1 搭建元件庫(四)

Vue 進階之從 0 到 1 搭建元件庫(四)

技術標籤:Vue2進階vuejs前端sass

Vue 進階之從 0 到 1 搭建元件庫(四)

Vue 進階之從 0 到 1 搭建元件庫(四)

4 Input 元件

4.1 引數支援

引數名稱引數描述引數型別預設值
placeholder佔位符string
type文字框型別(text/password
)
stringtext
disabled禁用booleanfalse
clearable是否顯示清空按鈕booleanfalse
show-password是否顯示密碼切換按鈕booleanfalse
namename 屬性string

4.2 事件支援

事件名稱事件描述
blur失去焦點事件
change內容改變事件
focus獲取焦點事件

4.3 基本結構

  • 初始化,步驟與前面元件相同
    1. components 資料夾下新建 input 資料夾,input 資料夾下新建檔案 index.vueindex.scss
    2. src/components/input/index.vue
    <template>
      <
    div
    class="hm-input">
    input元件</div> </template> <script> export default { name: 'HmInput' } </script> <style lang="scss"> @import 'index.scss'; </style>
    1. main.js 中註冊 input 元件
    // 引入 Input 元件
    import HmInput from './components/input/index'
    // 全域性註冊
    Vue.
    component(HmInput.name, HmInput)
    1. 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 例項的 usernameinput 框中內容也隨之而改變
<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 封裝至我們的元件中
    1. 首先看看如何使用
    <template>
      <div id="app">
        <hm-input placeholder="請輸入使用者名稱" v-model="username"></hm-input>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data() {
        return {
          username: 'zhangsan'
        }
      }
    }
    </script>
    
    1. 由上述對 v-model 本質的剖析,可以知道:
      <hm-input placeholder="請輸入使用者名稱" v-model="username"></hm-input>
      
      a. 上面的寫法可以翻譯成:
      <hm-input placeholder="請輸入使用者名稱" :value="username" @input="username=newValue"></hm-input>
      
    2. 所以可以在 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 clearableshow-password 功能

  • 結構:
    1. 元件接收 clearableshow-password 屬性
    2. clearableshow-passwordtrue 的時候,新增 hm-input--suffix 樣式,顯示包含小圖示的 span
    3. 定義一個計算屬性 showSuffix 動態控制 hm-input--suffix 樣式以及 span 標籤圖示的動態顯示
    4. 根據上一節實現 v-model 的邏輯,清空內容只需要 this.$emit('input', '') 即可,另外需要注意的是,只有當 clearabletrueinputvalue 有值時,才顯示清空按鈕
    5. 顯示密碼的基本思路是input 框的型別由 password 改為 text
      a. 首先不能直接修改 propstype 屬性,所以單獨在 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>
  • 效果
    在這裡插入圖片描述