zoukankan      html  css  js  c++  java
  • element radio源码

    src/radio.vue

    <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"></span>
          <input
            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 / v-model    绑定值    string / number / boolean
          value: {},
          // Radio 的 value    string / number / boolean
          label: {},
          // 是否禁用    boolean    —    false
          disabled: Boolean,
          // 原生 name 属性    string
          name: String,
          // Radio 的尺寸,仅在 border 为真时有效    string    medium / small / mini
          border: Boolean,
          // 是否显示边框    boolean    —    false
          size: String
        },
    
        data() {
          return {
            focus: false
          };
        },
        computed: {
          // 是否是radioGroup
          isGroup() {
            let parent = this.$parent;
            while (parent) {
              if (parent.$options.componentName !== 'ElRadioGroup') {
                parent = parent.$parent;
              } else {
                this._radioGroup = parent;
                return true;
              }
            }
            return false;
          },
          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);
              }
            }
          },
          _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(() => {
              // 向外抛出chang事件并传值
              this.$emit('change', this.model);
              // 如果是group,通知ElRadioGroup,执行handleChange事件,并传值this.model
              this.isGroup && this.dispatch('ElRadioGroup', 'handleChange', this.model);
            });
          }
        }
      };
    </script>

    src/radio-group.vue

    <template>
      <div
        class="el-radio-group"
        role="radiogroup"
        @keydown="handleKeydown"
      >
        <slot></slot>
      </div>
    </template>
    <script>
      import Emitter from 'element-ui/src/mixins/emitter';
      // Object.freeze,冻结对象
      const keyCode = Object.freeze({
        LEFT: 37,
        UP: 38,
        RIGHT: 39,
        DOWN: 40
      });
      export default {
        name: 'ElRadioGroup',
    
        componentName: 'ElRadioGroup',
    
        inject: {
          elFormItem: {
            default: ''
          }
        },
    
        mixins: [Emitter],
    
        props: {
          // 绑定值    string / number / boolean    
          value: {},
          // 单选框组尺寸,仅对按钮形式的 Radio 或带有边框的 Radio 有效    string    medium / small / mini    
          size: String,
          // 按钮形式的 Radio 激活时的填充色和边框色    string    —    #409EFF
          fill: String,
          // 按钮形式的 Radio 激活时的文本颜色    string    —    #ffffff
          textColor: String,
          // 是否禁用
          disabled: Boolean
        },
    
        computed: {
          _elFormItemSize() {
            return (this.elFormItem || {}).elFormItemSize;
          },
          // 大小
          radioGroupSize() {
            return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
          }
        },
    
        created() {
          // 接收handleChange事件
          this.$on('handleChange', value => {
            // 向外抛出change并传值
            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: {
          handleKeydown(e) { // 左右上下按键 可以在radio组内切换不同选项
            const target = e.target;
            const className = target.nodeName === 'INPUT' ? '[type=radio]' : '[role=radio]';
            const radios = this.$el.querySelectorAll(className);
            const length = radios.length;
            const index = [].indexOf.call(radios, target);
            const roleRadios = this.$el.querySelectorAll('[role=radio]');
            switch (e.keyCode) {
              // 点击左箭头和上箭头
              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;
              default:
                break;
            }
          }
        },
        watch: {
          value(value) {
            // 通知ElFormItem组件,执行el.form.change方法,并传值[this.value]
            this.dispatch('ElFormItem', 'el.form.change', [this.value]);
          }
        }
      };
    </script>

    src/radio-button.vue

    <template>
      <label
        class="el-radio-button"
        :class="[
          size ? 'el-radio-button--' + size : '',
          { 'is-active': value === label },
          { 'is-disabled': isDisabled },
          { 'is-focus': focus }
        ]"
        role="radio"
        :aria-checked="value === label"
        :aria-disabled="isDisabled"
        :tabindex="tabIndex"
        @keydown.space.stop.prevent="value = isDisabled ? value : label"
      >
        <input
          class="el-radio-button__orig-radio"
          :value="label"
          type="radio"
          v-model="value"
          :name="name"
          @change="handleChange"
          :disabled="isDisabled"
          tabindex="-1"
          @focus="focus = true"
          @blur="focus = false"
        >
        <span
          class="el-radio-button__inner"
          :style="value === label ? activeStyle : null"
          @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: 'ElRadioButton',
    
        mixins: [Emitter],
    
        inject: {
          elForm: {
            default: ''
          },
          elFormItem: {
            default: ''
          }
        },
    
        props: {
          // Radio 的 value    string / number
          label: {},
          // 是否禁用    boolean    —    false
          disabled: Boolean,
          // 原生 name 属性    string
          name: String
        },
        data() {
          return {
            focus: false
          };
        },
        computed: {
          // 动态计算value
          value: {
            // 取值
            get() {
              return this._radioGroup.value;
            },
            // 设置值
            set(value) {
              this._radioGroup.$emit('input', value);
            }
          },
          // radioGroup组件
          _radioGroup() {
            let parent = this.$parent;
            while (parent) {
              if (parent.$options.componentName !== 'ElRadioGroup') {
                parent = parent.$parent;
              } else {
                return parent;
              }
            }
            return false;
          },
          // 激活的样式
          activeStyle() {
            return {
              backgroundColor: this._radioGroup.fill || '',
              borderColor: this._radioGroup.fill || '',
              boxShadow: this._radioGroup.fill ? `-1px 0 0 0 ${this._radioGroup.fill}` : '',
              color: this._radioGroup.textColor || ''
            };
          },
          // elFormItem大小
          _elFormItemSize() {
            return (this.elFormItem || {}).elFormItemSize;
          },
          // 大小
          size() {
            return this._radioGroup.radioGroupSize || this._elFormItemSize || (this.$ELEMENT || {}).size;
          },
          // 是否禁用
          isDisabled() {
            return this.disabled || this._radioGroup.disabled || (this.elForm || {}).disabled;
          },
          tabIndex() {
            return (this.isDisabled || (this._radioGroup && this.value !== this.label)) ? -1 : 0;
          }
        },
    
        methods: {
          // 改变事件
          handleChange() {
            this.$nextTick(() => {
              // 通知ElRadioGroup组件触发handleChange事件,传值this.value
              this.dispatch('ElRadioGroup', 'handleChange', this.value);
            });
          }
        }
      };
    </script>
  • 相关阅读:
    ArrayList源码分析_JDK1.8.0_191
    LinkedList源码分析_JDK1.8.0_191
    HashMap源码分析_JDK1.8.0_191
    生产者消费者模型Java实现
    INT整型最小值取负还是本身的问题
    字节跳动面试题
    go sqlx操作数据库问题
    go gin框架调用cmd运行python脚本问题
    Android视频播放不能使用自研播放器
    mac python版本错误问题以及pip版本错误(anacanda)
  • 原文地址:https://www.cnblogs.com/wsk1576025821/p/10975946.html
Copyright © 2011-2022 走看看