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>
  • 相关阅读:
    稳扎稳打Silverlight(47) 4.0UI之操作剪切板, 隐式样式, CompositeTransform, 拖放外部文件到程序中
    返璞归真 asp.net mvc (9) asp.net mvc 3.0 新特性之 View(Razor)
    返璞归真 asp.net mvc (6) asp.net mvc 2.0 新特性
    稳扎稳打Silverlight(48) 4.0其它之打印, 动态绑定, 增强的导航系统, 杂七杂八
    精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First
    稳扎稳打Silverlight(42) 4.0控件之Viewbox, RichTextBox
    稳扎稳打Silverlight(53) 4.0通信之对WCF NetTcpBinding的支持, 在Socket通信中通过HTTP检索策略文件, HTTP请求中的ClientHttp和BrowserHttp
    稳扎稳打 Silverlight 4.0 系列文章索引
    稳扎稳打Silverlight(54) 4.0通信之对UDP协议的支持: 通过 UdpAnySourceMulticastClient 实现 ASM(Any Source Multicast),即“任意源多播”
    返璞归真 asp.net mvc (8) asp.net mvc 3.0 新特性之 Model
  • 原文地址:https://www.cnblogs.com/wsk1576025821/p/10975946.html
Copyright © 2011-2022 走看看