手寫(radio)element-ui組件

前言

在用戶使用過程當中提出一鍵導入的功能,需求以下:點擊導入按鈕顯示提示框,而後是單選框以及上傳按鈕。pc端常使用element-ui組件,可是這個項目是vue1的老項目,而且沒有element-ui組件。因此須要本身動手實現單選功能和上傳功能。 css

需求

radio 屬性及方法

  • name: 用於定義同一類型的 radio 同一 name 的 radio 只能選中一個(單選實現)
  • id: 用於和 label 標籤關聯起來 實現點擊 label 標籤內的元素也能選中 radio
  • value:單選按鈕的值,選中某個單選按鈕至關於拿到 value 值 tip:用於識別組中的哪一個單選按鈕被選中。
  • checked 用於設置默認選中的 radio
  • v-model 建立雙向數據綁定。 會忽略全部表單元素的 value、checked、selected 特性的初始值而老是將 Vue 實例的數據做爲數據來源。
// html
 <div v-for="day in weekSelectList"
    :key="day.id"
    class="select__day">
    <input type="radio"
      name="week"
      :id="day.label"
      :value="day.value"
      v-model="selectedDay">
    <label :for="day.label">{{day.label}}({{day.value}})</label>
  </div>
複製代碼
// 暫定的數據
data(){
  return {
  weekSelectList: [
      { label: '週一', value: '2018-12', id: 1 },
      { label: '週二', value: '2018-13', id: 2 },
      { label: '週三', value: '2018-14', id: 3 },
      { label: '週四', value: '2018-15', id: 4 },
      { label: '週五', value: '2018-16', id: 5 }
    ]
  },
  selectedDay: '2018-12',
}
複製代碼

經過 v-model 綁定 selectedDay,匹配到相同的值會將該 radio 選中,當改變 radio 的選擇,selectedDay 也會動態的變動成選中的 radio 的 valuehtml

上傳文件

屬性

  • accept 屬性接受一個(多個值時)逗號分隔的字符串 如:accept="image/png, image/jpeg"
  • id
  • name
  • 注意:accept 屬性並不會驗證選中文件的類型只是在用戶瀏覽時只顯示指定文件類型

缺點

  1. 在未上傳文件時,顯示"未選擇文件",用戶界面不友好,不可配置
  2. 同一個文件名即便內容改變了,從新上傳也不會觸發 change 事件
  3. 用戶若是在上傳過程當中點擊了「取消」,已經上傳的文件會被移除

解決方式

<div class="upload__button"
    :class="{'upload__button--uploaded':isUploaded}"
    @click="onUploadClick">點擊上傳</div>
  <input type="file"
    class="upload__file"
    v-el:upload
    accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
    @change="onFileChange" />
複製代碼
methods:{
  onUploadClick() {
    if (!this.isUploaded) {
      this.$els.upload.click()
    }
  },
  onFileChange(e) {
  const file = e.target.files[0]
  if (file === undefined) {
    return
  }
  this.fileName = file.name
  const result = /[xls|xlsx]$/.test(this.fileName)
    if (result) {
      this.isUploaded = true
      this.showAlert('上傳成功')
      this.$els.upload.value = null
    } else {
      this.showAlert('文件格式錯誤,請確認後重試。')
    }
  },
}
複製代碼

當點擊上傳按鈕觸發 onUploadClick 事件後,獲取到 upload 綁定的 DOM (因爲是老的項目使用的是$els,vue2 使用 ref)手動觸發 click 事件而且能夠在change事件中默認接收一個文件信息對象其中target.files[0]包含文件的更多信息,以下圖:vue

判斷文件類型

能夠看到 change 事件的返回值包含着文件屬性,這裏咱們須要判斷是文件名是否爲 excel,使用正則的 test 方法。element-ui

重置change事件

在最後 this.$refs.uploadFile.value = null; 移除文件,能夠保證上傳一樣的文件時,也會觸發 change 事件bash

優化樣式

至此關於表單方面的功能都已經實現了,因爲原始的radio樣式比較醜,並且不能更改。下面咱們就想辦法將它作的漂亮些。app

// template
 <label v-for="(item,index) in radioList"
        :key="item.value"
        :for="item.linkLabel"
        :accesskey="index">
        <span class="content__input">
          <span class="radio__replace"
            :class="{'radio__replace--checked':selectedRadio===item.value,'radio__replace--disable':item.isDisabled}">
          </span>
          <input v-model="selectedRadio"
            type="radio"
            class="radio__button"
            name="radio"
            :id="item.linkLabel"
            :tabindex="index"
            :value="item.value"
            :disabled="item.isDisabled"
            @focus="item.isFocus = true"
            @blur="item.isFocus = false" />
        </span>
        <span class="content__text">{{item.label}}</span>
      </label>
複製代碼
// data
  data() {
    return {
      radioList: [
        {
          linkLabel: 'label1',
          value: '1',
          isDisabled: false,
          isFocus: false,
          label: '標籤1'
        },
        {
          linkLabel: 'label2',
          value: '2',
          isDisabled: false,
          isFocus: false,
          label: '標籤2'
        },
        {
          linkLabel: 'label3',
          value: '3',
          isDisabled: true,
          isFocus: false,
          label: '標籤3'
        }
      ],
      selectedRadio: '1'
    }
複製代碼
  1. 這裏使用遍歷的方式在data中定義多個radio,在前面咱們講到過radio的基本用法,使用label的for屬性和input的for屬性實現關聯起來。(這裏我將input放在label內,這樣點擊整個label都會選中,沒有label和radio元素之間的間隙)。
  2. name相同的radio會實現單選效果tabindex表明使用"Tab"鍵的遍歷順序 ,value是選中時v-model綁定的selectedRadio也就會跟着變動
  3. 實現個性化樣式的關鍵在於結構就是用一個類名content__input標籤將類名radio__replace和radio包起來。設置定位層級(至關於radio被覆蓋了,然而只要點擊到labelradio就會被選中)
  4. 經過selectedRadio選中的值和當前radio值作對比,以及isDisabled這些Boolean值動態綁定class實現咱們自定義的radio樣式切換

效果以下:優化

其實radio__replace類名對應的標籤就是咱們自定義的radio,其中的白色原點是經過僞類生成的css代碼放在最後,感興趣能夠看下ui

僞類樣式修改

若是想經過類名來改變白色原點的樣式,能夠經過權重來改變。以下經過isShow來給外層添加test類名 而起始的時候設置的權重爲兩層,以後添加一層能夠起到修改樣式的效果。(ps:僞類不能經過預先設定好的類名來修改樣式)例子代碼以下:this

<div :class="{test:isShow}"
      @click="onRedClick">
      <div class="text__item"></div>
    </div>
複製代碼
.text__item {
  &:after {
    content: '';
    width: 30px;
    height: 30px;
    background-color: #f00;
    position: absolute;
    bottom: 20px;
  }
}
.test {
  .text__item {
    &:after {
      background-color: #ff0;
    }
  }
}
複製代碼
// css
 .radio {
        &__replace {
          border: 1px solid #dcdfe6;
          border-radius: 100%;
          width: 14px;
          height: 14px;
          background-color: #fff;
          position: relative;
          cursor: pointer;
          display: inline-block;
          box-sizing: border-box;
          z-index: 999;
          transition: 0.15s ease-in;
          &--checked {
            border-color: #409eff;
            background-color: #409eff;
          }
          &--disable {
            cursor: not-allowed;
          }
          &:after {
            width: 4px;
            height: 4px;
            border-radius: 100%;
            background-color: #fff;
            content: '';
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
          }
        }
        &__button {
          opacity: 0;
          outline: none;
          position: absolute;
          z-index: -1;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          margin: 0;
        }
      }
複製代碼

總結

  1. 介紹了radio基本屬性,使用案例並優化了radio的樣式
  2. 原始上傳文件元素的缺點以及改善方法
相關文章
相關標籤/搜索