阅读element-radio有感

radio.vue

 

<template>

<!-- label用于控制位置和公共样式的 -->

  <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"

  >

  <!-- 按钮部分 el-radio__input控制样式-->

    <span class="el-radio__input"

      :class="{

        'is-disabled': isDisabled,

        'is-checked': model === label

      }"

    >

    <!-- el-radio__inner 控制形状和样式 -->

      <span class="el-radio__inner"></span>

      <!-- input来控制交互 

        @focus="focus = true"

        @blur="focus = false"

        通过focus和blur来改变focus的值

 

        input的值就是label

      -->

      <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 Emitter from 'element-ui/src/mixins/emitter';

 

  export default {

    name: 'ElRadio',

 

    mixins: [Emitter],

 

    inject: {

      elForm: {

        default: ''

      },

 

      elFormItem: {

        default: ''

      }

    },

 

    componentName: 'ElRadio',

 

    props: {

      value: {},

      label: {},

      disabled: Boolean,

      name: String,

      border: Boolean,

      size: String

    },

 

    data() {

      return {

        focus: false

      };

    },

    computed: {

      isGroup() {

        let parent = this.$parent;

        while (parent) {// 通过循环向上找 看是否为单项群组

          if (parent.$options.componentName !== 'ElRadioGroup') {

            parent = parent.$parent;

          } else {

            this._radioGroup = parent;

            return true;

          }

        }

        return false;

      },

      // 当我们点击单选框的时候会触发这个set方法 从而将label的值传给父组件并改变父组件v-model绑定的值

      // 从而触发组件的重新渲染 而此时model的值也就改变了 样式也就切换了

      model: {

        get() {

          // this.value 是指的父组件传进来的props value值  也就是我们的v-model绑定的

          return this.isGroup ? this._radioGroup.value : this.value;

        },

        set(val) {

          // 这里的val实际上就是this.label

          // 如果是调用了el-radio-group

          if (this.isGroup) {

            this.dispatch('ElRadioGroup', 'input', [val]);

          } else {

            // 调用父组件的@input 并将传进来的label传给父组件

            /**

             * 父组件

             * <el-radio v-model="radio" label="1">备选项</el-radio>

             * 当我们点击input时就会执行以下@input赋值操作

             * 这里的v-model='radio' 其实就相当于@input = "(val)=>radio=val" :value='radio'

             * */ 

 

            this.$emit('input', val);

          }

          // 重置input的状态 this.model就是this.value

          this.$refs.radio && (this.$refs.radio.checked = this.model === this.label);

        }

      },

      _elFormItemSize() {

        return (this.elFormItem || {}).elFormItemSize;

      },

      radioSize() {

        const temRadioSize = this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;

        return this.isGroup

          ? this._radioGroup.radioGroupSize || temRadioSize

          : temRadioSize;

      },

      isDisabled() {

        return this.isGroup

          ? this._radioGroup.disabled || this.disabled || (this.elForm || {}).disabled

          : this.disabled || (this.elForm || {}).disabled;

      },

      tabIndex() {

        return (this.isDisabled || (this.isGroup && this.model !== this.label)) ? -1 : 0;

      }

    },

 

    methods: {

      handleChange() {

        this.$nextTick(() => {

          this.$emit('change', this.model);

          this.isGroup && this.dispatch('ElRadioGroup', 'handleChange', this.model);

        });

      }

    }

  };

</script>

 

 

 

 

 

mixins中

 

Emitter.js

function broadcast(componentName, eventName, params) {

  this.$children.forEach(child => {

    var name = child.$options.componentName;

 

    if (name === componentName) {

      child.$emit.apply(child, [eventName].concat(params));

    } else {

      broadcast.apply(child, [componentName, eventName].concat([params]));

    }

  });

}

export default {

  methods: {

    // ElRadioGroup/input/[3]

    dispatch(componentName, eventName, params) {

      var parent = this.$parent || this.$root;

      var name = parent.$options.componentName;

      // 找到与componentName匹配的祖先组件

      while (parent && (!name || name !== componentName)) {

        parent = parent.$parent;

 

        if (parent) {

          name = parent.$options.componentName;

        }

      }

      // 这里不是很懂 为啥是parent.$emit 而不是parent的最近childen

 

      /**

       * 其实这里涉及到一个.vue文件定义和组件调用的关系了

       * 这里的parent 其实是该组件.vue定义的时候而parent.$emit其实是相当于在定义的地方去调用该组件被调用时

       * 的v-model(@input)或者是其他方法

       * 

       * */ 

      if (parent) {

        parent.$emit.apply(parent, [eventName].concat(params));

      }

    },

    broadcast(componentName, eventName, params) {

      broadcast.call(this, componentName, eventName, params);

    }

  }

};

 

 

 

其实这里的关键还是v-model的理解  它实际上是@input=(val)=>xxx=val;:value=’xxx’ 的简写

为什么我们点击单选按钮会触发计算属性的set方法 就是这个原因,先调用了@input方法,修改了计算属性 然后再进入到set方法

 

这里需要注意的是 vue3中获取组件名的方式改变了  不再是componentName  而是name

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值