Vueパッケージのチェックボックスとラジオ

オプションボックスコンポーネント

<template>
  <div
    :class="[
      'optionBox',
      OptionChecked ? 'optionBoxChecked' : '',
      !text ? 'optionDefaultText' : '',
      type === 'radio' ? 'optionBoxRadio' : '',
    ]"
    @click="onChangeChecked"
  >
    {
    
    {
    
     text || '*' }}
  </div>
</template>

<script>
export default {
    
    
  name: 'OptionBox',
  props: {
    
    
    /** 按钮框里的文字,如果不传就是√ */
    text: {
    
    
      type: String,
      default: '',
    },
    /** 是否选中状态,从外界传入 */
    checked: {
    
    
      type: [Boolean, undefined],
      default: undefined,
    },
    /** 一共两种类型 checkbox 和 radio */
    type: {
    
    
      type: String,
      default: 'checkbox',
    },
  },
  data() {
    
    
    return {
    
    
      OptionChecked: this.checked || false,
    };
  },
  watch: {
    
    
    checked(value) {
    
    
      this.OptionChecked = value;
    },
  },
  methods: {
    
    
    onChangeChecked() {
    
    
      if (this.checked === undefined) {
    
    
        this.OptionChecked = !this.OptionChecked;
        this.$emit('change', this.OptionChecked);
      } else {
    
    
        this.$emit('change', !this.checked);
      }
    },
  },
};
</script>

<style lang="less">
.optionBox {
    
    
  color: #666;
  width: 30px;
  height: 30px;
  border: 1px solid #d9d9d9;
  text-align: center;
  line-height: 28px;
  display: inline-block;
  font-size: 14px;
  background: #fff;
  border-radius: 2px;
  cursor: pointer;
}

.optionBoxRadio {
    
    
  border-radius: 50%;
}

.optionBoxChecked {
    
    
  color: #fff;
  background: #025299;
  border: 1px solid #025299;
}

.optionDefaultText {
    
    
  position: relative;
  color: transparent;
  &::before {
    
    
    content: '';
    width: 6px;
    height: 12px;
    top: 5px;
    left: 10px;
    transform: rotate(45deg);
    border-right: 3px solid #fff;
    border-bottom: 3px solid #fff;
    position: absolute;
  }
}
</style>

オプションコンポーネントは、optionBoxコンポーネントに基づいてカプセル化された高レベルのコンポーネントです。

<template>
  <div :class="$style['scf-option-warpper']">
    <scf-option-box
      ref="optionBoxRef"
      :text="text"
      :type="type"
      :checked="checked"
      @change="onChangeValue"
    />
    <span
      :class="[$style['scf-option-name'], nameChecked ? $style['scf-option-name-checked'] : '']"
      @click="onClickOption"
      >{
    
    {
    
     name }}</span
    >
  </div>
</template>

<script>
import OptionBox from '@/components/option-box/option-box';

export default {
    
    
  name: 'Option',
  components: {
    
    
    'scf-option-box': OptionBox,
  },
  props: {
    
    
    /** 选项对应的文字 */
    name: {
    
    
      type: String,
      default: '',
      require: true,
    },
    /** 选项对应的值 */
    value: {
    
    
      type: String,
      default: '',
      require: true,
    },
    /** 选项按钮上的文字 */
    text: {
    
    
      type: String,
      default: '',
    },
    /** 按钮的类型,checkbox和radio */
    type: {
    
    
      type: String,
      default: 'checkbox',
    },
    /** 是否选中 */
    checked: {
    
    
      type: [Boolean, undefined],
      default: undefined,
    },
  },
  data() {
    
    
    return {
    
    
      /** 用于控制name的颜色,根据返回的按钮当前的状态 */
      nameChecked: this.checked || false,
    };
  },
  watch: {
    
    
    checked: {
    
    
      handler(newValue) {
    
    
        this.nameChecked = newValue;
      },
      immediate: true,
    },
  },
  methods: {
    
    
    onChangeValue(checkedValue) {
    
    
      this.$emit('change', checkedValue, this.value);
      if (this.checked === undefined) {
    
    
        this.nameChecked = checkedValue;
      }
    },
    onClickOption() {
    
    
      this.$refs.optionBoxRef.onChangeChecked();
    },
  },
};
</script>
<style module lang="less">
.scf-option-warpper {
    
    
  cursor: pointer;
  display: inline-block;
}

.scf-option-name {
    
    
  padding-left: 10px;
  color: #333;
}

.scf-option-name-checked {
    
    
  color: #025299;
}
</style>

ここに画像の説明を挿入します
オプショングループコンポーネントは、オプションコンポーネントに基づいてカプセル化された高レベルのコンポーネントです。

<template>
  <div>
    <div v-for="item in options" :key="item.value" class="option-div">
      <paper-option
        :name="item.name"
        :text="type === 'sort' ? optionText[item.value] : item.text"
        :value="item.value"
        :type="optionType"
        :checked="checkedValues.indexOf(item.value) >= 0"
        @change="OptionChangeValue"
      />
    </div>
  </div>
</template>

<script>
import Option from '../option/option';
export default {
    
    
  name: 'OptionGroup',
  components: {
    
    
    'paper-option': Option,
  },
  props: {
    
    
    /**
     * @option 渲染的每一个小的选项 {name:string, text:string, value:string}
     * name 每一个小选项对应的提示
     * text 每一个小选项按钮的文字
     * value 每一个小选项对应的值
     * */
    options: {
    
    
      type: Array,
      require: true,
    },
    /**
     * @type string 复选框 checkbox | 单选框 radio | 排序 sort
     * */
    type: {
    
    
      type: String,
      default: 'checkbox',
    },
    values: {
    
    
      type: Array,
    },
  },
  data() {
    
    
    return {
    
    
      checkedValues: this.values || [],
      isCompelete: false,
    };
  },
  computed: {
    
    
    optionType: {
    
    
      get() {
    
    
        let result = this.type;
        if (this.type === 'sort') {
    
    
          result = 'radio';
        }
        return result;
      },
    },
    optionText: {
    
    
      get() {
    
    
        let result = {
    
    };
        if (this.type === 'sort') {
    
    
          this.checkedValues.forEach((item, i) => {
    
    
            result[item] = String(i + 1);
          });
        }
        return result;
      },
    },
  },
  watch: {
    
    
    checkedValues: {
    
    
      handler(newValue) {
    
    
        const length = newValue?.length || 0;
        let result = false;
        if (this.type !== 'sort') {
    
    
          if (length) {
    
    
            result = true;
          }
        } else {
    
    
          if (length === this.option?.length) {
    
    
            result = true;
          }
        }
        this.isCompelete = result;
        this.$emit('change', newValue, result);
      },
    },
  },
  methods: {
    
    
    OptionChangeValue(isChecked, checkedValue) {
    
    
      if (isChecked) {
    
    
        if (this.type === 'radio') {
    
    
          this.checkedValues = [];
        }
        this.checkedValues.push(checkedValue);
      } else {
    
    
        const order = this.checkedValues.findIndex((item) => {
    
    
          return item === checkedValue;
        });
        if (order >= 0) {
    
    
          this.checkedValues.splice(order, 1);
        }
      }
    },
  },
};
</script>

<style lang="less">
.option-div {
    
    
  margin-top: 16px;
}
</style>

使い方

<template>
   <div>
	<div>多选项组</div>
    <scf-option-group :options="options" @change="onOptionGroupChange" />
    <div>单选项组</div>
    <scf-option-group :options="options" type="radio" @change="onOptionGroupChange" />
    <div>排序选项组</div>
    <scf-option-group
      :options="options"
      type="sort"
      :values="optionValues"
      @change="onOptionGroupChange"
    />
   </div>
</template>
<script>
import OptionGroup from '@/components/option-group/option-group';
export default {
    
    
  name: 'PaperUi',
  components: {
    
    
     'scf-option-group': OptionGroup,
  },
  data() {
    
    
    return {
    
    
      options: [
        {
    
    
          value: '1',
          name: '这是选项1',
          text: '',
        },
        {
    
    
          value: '2',
          name: '这是选项2',
          text: '',
        },
        {
    
    
          value: '3',
          name: '这是选项3',
          text: '',
        },
        {
    
    
          value: '4',
          name: '这是选项4',
          text: '',
        },
      ],
    };
  },
  methods: {
    
    
   onOptionGroupChange(value, isCompelete) {
    
    
      console.log(value, isCompelete);
    },
  },
};
</script>

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/glorydx/article/details/115056043