Element源码分析系列4-Radio(单选框)

简介

单选框这个组件看似简单,实则知识点众多,较为复杂,如果写一个html的原生单选框,那确实很简单,但是封装一个完整的单选组件就不那么简单了,接下来我们先介绍Vue的单选框的一些原理,然后再分析Element的单选框实现

原生单选 Vs Vue单选

原生单选框很简单,如果我们要实现一个男女性别的单选按钮组,代码只需如下几句

<input type="radio" name="sex" value="male" checked>男</input>
<input type="radio" name="sex" value="female">女</input>
复制代码

上面的男的单选按钮添加了checked属性,表示被选中,value属性表示单选按钮的值,可以给每个input添加onchangeonclick事件来通过点击获取其值,也可以通过一个按钮点击后遍历所有单选的input按钮,获取checked属性为true的那一项,然后再获取其value
注意如何让一组单选互斥,也就是说同一时刻只能有一个单选被选中,name属性就是这个作用, 通过把一些单选按钮的name设置为同一个值,就达到了互斥的效果

而Vue的单选框则有所不同,代码如下

它只需要一个 v-model即可达到互斥效果, v-model的值是data里面的数据,进行了双向绑定,由此可见并没有通过 name属性来达到互斥,那么时怎么实现的呢?首先先来了解下v-model的本质,v-model本质上是语法糖

官网说的很清楚,这就相当于进行了一个双向绑定,对input输入框的input事件进行监听,当键盘敲下时就实时改变searchText的值,同时修改searchText的值,输入框的value也跟着变化。那么底层是怎么处理互斥的呢?通过查看v-model相关源码

function genRadioModel (
  el: ASTElement,
  value: string,
  modifiers: ?ASTModifiers
) {
  const number = modifiers && modifiers.number
  let valueBinding = getBindingAttr(el, 'value') || 'null'
  valueBinding = number ? `_n(${valueBinding})` : valueBinding
  addProp(el, 'checked', `_q(${value},${valueBinding})`)
  addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true)
}
复制代码

上述代码是处理单选框model的代码,genRadioModel参数中的value就是input的value的值,而valueBinding的值就是v-model中的v-bind:value的值

 <input type="radio" id="jack" value="Jack" v-model="name">
复制代码

如果示例如上,那么addProp这个方法就会把checked属性的值_q('Jack',name)放入属性列表,这里_q是looseEqual方法的简写,表示宽松比较(如果是对象,则通过JSON.stringify转成字符串比较,否则直接String()转换比较)2个值是否相同,这样这里的逻辑就明确了,如果单选框的value的值和v-model的值相同,那么就加上一个checked属性,表示该单选被选中,自然而然其他单选框value的值和v-model的值不同,所以就不是选中状态,没有checked属性,所以达到了互斥效果

源码分析

整个单选组件的源码不算太长,但是里面知识点很多,先上源码,官网代码点此

<template>
  <label
    class="el-radio"
    :class="[
      border && radioSize ? 'el-radio--' + radioSize : '',
      { 'is-disabled': isDisabled },
      { 'is-focus': focus },
      { 'is-bordered': border },
      { 'is-checked': model === label }
    ]"
    role="radio"
    :aria-checked="model === label"
    :aria-disabled="isDisabled"
    :tabindex="tabIndex"
    @keydown.space.stop.prevent="model = isDisabled ? model : label"
  >
    <span class="el-radio__input"
      :class="{
        'is-disabled': isDisabled,
        'is-checked': model === label
      }"
    >
      <span class="el-radio__inner"
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值