Element-UI 源码简析——Radio单选框(下)

899 阅读4分钟

26d8116a7588ac4a91a8398280e436fe.png

序言

这篇的话,来分享一下Radio剩下的两个组件,radio-group、radio-button. 这两个组件的大致看了一下很多的地方和上一篇radio 90%以上是超不多的,radio和radio-button他俩最主要的区别还是样式上的不一样,还有一个原因就是,radio-button是和radio-group配合起来用的,所以这里就主要的讲一下radio-group的东西吧😁😁。

结构分析

老样子还是根据三个角度来分析,Dom、数据属性、事件

Dom

     <component is=_elTag class=el-radio-group role=radiogroup @keydown=handleKeydown>
        <slot></slot>
    </component>

radio-group的dom结构还是非常的少的,便于理解和参考,

首先引入眼帘的就是咱们的 component 这个组件了,这个就是vue自带的组件了,还有一个就是slot。

Vue自带的标签有component,transition,transition-group,keep-alive,slot。

component标签它是Vue内置的标签,它的用途是可以动态绑定我们的组件,根据数据不同更换不同的组件,详细的可以看看官网的描述了,这里就不做很详细的描述了。

role : 这个属性在上一篇我提过 无障碍网页应用属性 大家也可以去参考看一看,这里也不多介绍了。

keydown:键盘按下事件

数据属性

    const keyCode = Object.freeze({
        LEFT 37,
        UP 38,
        RIGHT 39,
        DOWN 40,
    });
    export default {
        name ElRadioGroup,
        componentName ElRadioGroup,
        inject {
            elFormItem {
                default ,
            },
        },
        mixins [Emitter],
        props {
            value {},
            size String,
            textColor String,
            disabled Boolean,
        },
        computed {
            _elFormItemSize() {
                return (this.elFormItem  {}).elFormItemSize;
            },
            _elTag() {
                return (this.$vnode.data  {}).tag  div;
            },
            radioGroupSize() {
                return this.size  this._elFormItemSize  (this.$ELEMENT  {}).size;
            },
        },

属性这块的话,大部分也是之前分析过的,大家也可以参考之前的,但是这样有一个属性,大家可能平时可能用的比较少

Object.freeze: (冻结一个对象)一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

computed

_elFormItemSize:用来判断当前from的

_elTag: 这个就是用来区分 按钮的组件和普通的组件了

radioGroupSize:Group的大小

事件

    created() {
        this.$on(handleChange, (value) = {
            this.$emit(change, value);
        });
    },
    mounted() {
         当radioGroup没有默认选项时,第一个可以选中Tab导航
        const radios = this.$el.querySelectorAll([type=radio]);
        const firstLabel = this.$el.querySelectorAll([role=radio])[0];
        if (![].some.call(radios, (radio) = radio.checked) && firstLabel) {
            firstLabel.tabIndex = 0;
        }
    },
    methods {
            左右上下按键 可以在radio组内切换不同选项
        handleKeydown(e) {
            const target = e.target;
             当前按下元素的事件对象
            const className = target.nodeName === INPUT  [type=radio]  [role=radio];
             判断当前的元素是否是对应的INPUT,然后再来选择对应的input或者label
            const radios = this.$el.querySelectorAll(className);
             获取所有的className
            const length = radios.length;
             获取对应input或者label的数量
            const index = [].indexOf.call(radios, target);
             在this.$el.querySelectorAll的集合中查找evevt.target当前的下标
             可以理解为radios的对象继承了空数组的indexOf方法,按下时找到radios出现的位置
            const roleRadios = this.$el.querySelectorAll([role=radio]);
             获取所有的 label标签
            switch (e.keyCode) {
                  左 
                case keyCode.LEFTcase 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.RIGHTcase keyCode.DOWNif (index === length - 1) {
                        e.stopPropagation();
                        e.preventDefault();
                        roleRadios[0].click();
                        roleRadios[0].focus();
                    } else {
                        roleRadios[index + 1].click();
                        roleRadios[index + 1].focus();
                    }
                    break;
                default
                    break;
            }
        },
    },

created : 主要是来监听子组件的handleChange,并且把这个事件抛出来。

handleKeydown:这个方法主要的作用就是左右上下按键 可以在radio组内切换不同选项,详细的看上方注释

小知识点(续)

在关于 Radio-group 这篇文章中有一个疑问,之前没有注意到 这里的话解释一下!

在handleKeydown事件中有这么一行代码

    源码
    const index = [].indexOf.call(radios, target);
    
    完整的写法是
    
    const index = [].indexOf.call(this.$el.querySelectorAll('[type=radio]'), e.target);

问题1: 这里为什么要用到call方法

       首先通过 querySelectorAll 等方法获取到指定元素列表,这个元素列表被称为类数组
       
       类数组定义
       1)拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);
       2)类数组不具有数组所具有的方法;
       3)类数组是一个普通对象,他的原型是Object,而真实的数组是Array类型
       4)常见的类数组有: 函数的参数 arguments, DOM 对象列表(比如通过 document.querySelectorAll 得到的列表)
       
       类数组转数组的方法 (这只是一部分)
       1)[].slice.call([类数组]);
       2)[...[类数组]];
       3)Array.from([类数组]);

问题2: 这里为什么要用IndexOf.call() 他的作用是什么

      其实这里有一个场景,一个父级下有多个子级,我们要给按下某个子级的时候做对应的操作。
      1)循环遍历 给每个子级添加对应的方法
      2)写很多判断 进行区分
      3)利用事件委托的形式来区分子级

招聘广告

言重式招聘 寻人!!!寻志同道合之人、寻竭忠尽智之人、寻深思远虑之人、寻勤恳至诚之人
浙江大华技术股份有限公司-软研-智慧城市产品研发部招聘高级前端!!!!!
欢迎大家来聊,有意向可发送简历到chen_zhen@dahuatech.com

树大招风风撼树,人为高名名丧人 ——————无奖竞猜