ElementUI radio 小改造

博客原文html

ElementUI 是本身比較鍾愛的一套 vue 組件庫,本身好幾個項目裏都在用它。一直以來這些豐富的組件,讓我能快速的搞定各類後臺管理頁面,極大地提升了工做效率。vue

可是無論什麼軟件,確定都沒辦法稱之爲完美,而最近的幾個小需求中,也發現了 element ui 的一些不足(也多是由於本身的需求比較奇葩吧)。其中一點就是本文要提到的,radio 綁定對象類型值的問題。git

具體現象就是,當經過 mapState 方法自動一個計算對象數組,而後將它綁定到 el-radio 上時,el-radio-group 裏的 el-radio 沒法根據其綁定值正確的顯示 checked 狀態。github

例以下面這段代碼:vuex

<template>
  <div id="app">
    <el-radio-group
      v-model="checkedUser"
    >
      <el-radio
        v-for="(user, index) in users"
        :key="index"
        :label="user"
        :value="user"
      >
        {{ `${user.name}(${user.age}歲)` }}
      </el-radio >
    </el-radio-group>

    <h2>當前選中</h2>
    <pre>{{ checkedUser }}</pre>
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  name: 'app',

  data () {
    return {
      checkedUser: {
        name: 'C',
        age: 1,
      },
    }
  },

  computed: {
    ...mapState({
      users: state => state.users
    })
  },
}
</script>

其中 users 爲 vuex store 中的 state。element-ui

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    users: [
      {
        name: 'A',
        age: 18,
      },
      {
        name: 'B',
        age: 20,
      },
      {
        name: 'C',
        age: 1,
      },
    ]

  },
})

export default store

但當運行代碼以後看到,第三個 el-radio 並無像預期的那樣處於選中狀態。數組

clipboard.png

查看代碼時發現,el-radio 裏的 checked 是根據 this.model === this.label 來判斷的(見代碼),而當 this.model 和 this.label 都是對象是,它們必須是引用同一個對象纔會「恆等」。app

得益於 Vue 提供的 extends 屬性,咱們能夠輕鬆的擴展官方原來的 el-radio 組件,對其稍加改造,就能夠解決這個問題。post

<template>
  <label
    class="el-radio"
    :class="[
      border && radioSize ? 'el-radio--' + radioSize : '',
      { 'is-disabled': isDisabled },
      { 'is-focus': focus },
      { 'is-bordered': border },
      { 'is-checked': isChecked }
    ]"
    role="radio"
    :aria-checked="isChecked"
    :aria-disabled="isDisabled"
    :tabindex="tabIndex"
    @keydown.space.stop.prevent="model = isDisabled ? model : label"
  >
    <span class="el-radio__input"
          :class="{
        'is-disabled': isDisabled,
        'is-checked': isChecked
      }"
    >
      <span class="el-radio__inner"></span>
      <input
        ref="radio"
        class="el-radio__original"
        :value="label"
        type="radio"
        aria-hidden="true"
        v-model="model"
        @focus="focus = true"
        @blur="focus = false"
        @change="handleChange"
        :name="name"
        :disabled="isDisabled"
        tabindex="-1"
      >
    </span>
    <span class="el-radio__label" @keydown.stop>
      <slot></slot>
      <template v-if="!$slots.default">{{label}}</template>
    </span>
  </label>
</template>

<script>
import { isEqual } from 'lodash'
import { Radio } from 'element-ui'

export default {
  name: 'MyRadio',

  // 使用 extemds 選項來擴展官方的 el-radio
  extends: Radio,

  computed: {
    // IMPORTANT: 改寫部分,主要是支持 object 類型的值
    isChecked () {
      return isEqual(this.model, this.label)
    },
  },
}
</script>

改造完成後,引用這個組件並替換掉原來模板裏用到的 el-radio,刷新頁面後會發現,radio 的初始選中狀態正常了。ui

clipboard.png

實際上,el-checkbox/el-checkbox-group 也有相似的問題,也是能夠解決的,但看過源碼以後,發現 el-checkbox 的一些邏輯與 el-radio 又有不小差異,畢竟它綁定的可能就是對象數組,因此具體處理起來會有些不同,本文就不具體介紹了,若是各位有興趣能夠自行探索。

相關文章
相關標籤/搜索