element-ui源码阅读笔记(radio篇)

1,000 阅读1分钟

按照element-ui文档的顺序,button后的第二个组件就是radio了。

第一眼看到的就是class的绑定不一般,罒ω罒

:class="[
  border && radioSize ? 'el-radio--' + radioSize : '',
  { 'is-disabled': isDisabled },
  { 'is-focus': focus },
  { 'is-bordered': border },
  { 'is-checked': model === label }
]"

对着vue文档的Class绑定一节看了半天,发现数组绑定是有对象绑定不能替代的部分,即

  border && radioSize ? 'el-radio--' + radioSize : '',

className可以变化,所以class的数组绑定方式是万金油的写法(虽然有些繁琐)。(className用了is-*,讲究)

第二眼就看到了aria-*,这为辅助设备提供相应的标识(这也是为什么盲人也可以使用饿了么点外卖,点赞)

:aria-checked="model === label"
:aria-disabled="isDisabled" 

第三眼(真是每行都是精华呀)看到了:tabindex="tabIndex",这是规定页面元素的 tab 键控制次序,element-ui的表单元素支持按tab键选中,按enter或者space键点击的。

第四眼,radio的层级有很多,还不清楚是为什么,最后的html是

<span class="el-radio__label" @keydown.stop>
  <slot></slot>
  <template v-if="!$slots.default">{{label}}</template>
</span>

这里对<el-radio></el-radio>的标签中是否添加文字做了判断,如果添加文字,会放在$slots.default中。

最后统一讲一下值传递的过程:

当v-model用在组件上时,是这样的

<input v-model="searchText">

等于

<custom-input
    v-bind:value="searchText"
    v-on:input="searchText = $event"
></custom-input>

所以需要从props: { value: {}}里取得在组件上用v-model绑定的值。

然后在计算方法里转换为绑定在真实radio上的值

  <input
    class="el-radio__original"
    :value="label"
    type="radio"
    aria-hidden="true"
    v-model="model"

model即为下面计算方法中的model,同时起到了双向绑定的作用。值得注意的是,此处的set只提交了input改变,没提交change改变,从应用的角度来说,就是js修改而不是点击修改的,不会提交change(自己代码修改带来的变化自己处理,element只是更新数据了)

  model: {
    get() {
      return this.isGroup ? this._radioGroup.value : this.value;
    },
    set(val) {
      if (this.isGroup) {
        this.dispatch('ElRadioGroup', 'input', [val]);
      } else {
        this.$emit('input', val);
      }
    }
  },

change方法是在nextTick,就是更新dom之后才提交更新,学到了,记笔记

    this.$nextTick(() => {
      this.$emit('change', this.model);
      this.isGroup && this.dispatch('ElRadioGroup', 'handleChange', this.model);
    });

单选按钮组就添加了监控上下左右按键的监听,做了边界判断

      case keyCode.LEFT:
      case keyCode.UP:
        e.stopPropagation();
        e.preventDefault();
        if (index === 0) {
          roleRadios[length - 1].click();
          roleRadios[length - 1].focus();
        } else {
          roleRadios[index - 1].click();
          roleRadios[index - 1].focus();
        }
        break;
      case keyCode.RIGHT:
      case keyCode.DOWN:
        if (index === (length - 1)) {
          e.stopPropagation();
          e.preventDefault();
          roleRadios[0].click();
          roleRadios[0].focus();
        } else {
          roleRadios[index + 1].click();
          roleRadios[index + 1].focus();
        }
        break;