Vue custom radio button and check box components

Keywords: Javascript

"Just be yourself"

problem

Some time ago, I received a task. I need to make a custom radio and multi select button. But before, I used a ready-made UI framework, and I didn't need to write my own style. Just do it! But after entering the company, I found that the Department is not applicable to the external UI framework. OK, I'll write it myself!

Design

The way I think about it is to use the native radio and CheckBox, and then cover it with styles.

Compatibility

Because flex layout is used when writing components, so browsers in the lower version do not support ha. For specific knowledge about flex, you can learn from Nguyen's blog: Flex layout tutorial: Syntax

Don't talk much about code

<!-- Checkbox -->
<template>
  <div class="check-boxs"
       :class="{'column':isColumn}">
    <div v-for="(item,index) in items"
         :key=index
         class="check-box"
         :class="{'width100':isColumn}"
         @click="checkBox(index)"
         v-show="!item.isShow">
      <span :class="{'checkbox-icon':true,'checkbox-input':item.isChecked,'opacity':opacity&&item.isChecked}"
            :style="item.isChecked?propsStyle:''">
        <i :class="{'checkbox-on':item.isChecked}"></i>
      </span>
      <input type="checkbox"
             :value="item.value">
      <span v-html="item.name"></span>
    </div>
  </div>
</template>

<script>
export default {
  name: "checkbox",
  data() {
    return {
      propsStyle: {
        border: "1px solid " + this.color,
        background: this.color
      }
    };
  },
  props: {
    /**
      items Instance: [{name: 'option one', isChecked:false}],
      name: It can be html,
      If you need to show and hide the isShow field, true means hide, as follows:
      [{name:'Option 1 ', isChecked:false,isShow:false}]
     */
    items: {
      type: Array,
      default: function() {
        return [];
      }
    },
    // Color transparency of selected boxes
    opacity: {
      type: Boolean,
      default: false
    },
    // Vertical axis direction of flex layout
    isColumn: {
      type: Boolean,
      default: false
    },
    // Maximum number of options
    limit: {
      type: Number,
      default: 2
    },
    // Background color of the selected box
    color: {
      type: String,
      default: "#65aef7"
    }
  },
  watch: {
    color(newval, oldval) {
      if (newval != oldval) {
      }
    }
  },

  methods: {
    checkBox(index) {
      let count = 0;
      for (let i = 0; i < this.items.length; i++) {
        if (this.items[i].isChecked == true) {
          count++;
        }
      }
      if (count >= this.limit && !this.items[index].isChecked) {
        this.$emit("canNotAdd", false);
        return;
      }
      // Pass out the value of the selected item and check
      /* This code can also be placed where the parent component calls this event, enabling the check box intelligence to be selected under certain conditions*/
      this.$set(this.items[index], "isChecked", !this.items[index].isChecked);
      // this.items[index].isChecked = !this.items[index].isChecked;
      this.$emit("checkBox", index);
    }
  }
};
</script>

<style scoped>
.check-boxs {
  display: flex;
  display: -webkit-flex;
  justify-content: space-between;
  align-items: center;
  margin: 5px 0;
  color: #545454;
  font-size: 12px;
}
.column {
  flex-direction: column;
  justify-content: flex-start;
}
.width100 {
  width: 100%;
  display: flex;
  display: -webkit-flex;
  justify-content: space-between;
  height: 24px;
  align-items: flex-start;
  padding-right: 40px;
  box-sizing: border-box;
}
.check-box {
  position: relative;
  cursor: pointer;
}

.check-box input {
  vertical-align: middle;
  margin-top: -2px;
  margin-bottom: 1px;
  /* The first three lines of code are to align the checkbox button with the text */
  width: 12px;
  height: 12px;
  appearance: none; /*Clear default style*/
  -webkit-appearance: none;
  opacity: 0;
  outline: none;
  cursor: pointer;
  /* Note cannot be set to display:none*/
}
/* Style change of option box */
.checkbox-icon {
  width: 12px;
  height: 12px;
  position: absolute;
  top: 1px;
  z-index: 0;
  border-radius: 2px;
  background-color: #fff;
  border: 1px solid #c9c9c9;
  box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.15);
  cursor: pointer;
}
.checkbox-input {
  border: 1px solid #65aef7;
  background-color: #65aef7;
}
.opacity {
  opacity: 0.5;
}
.checkbox-on {
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 7px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg);
}
</style>
<template>
  <div class="radio-container">
    <div v-for="(item,index) in items"
         :key=index
         @click="radioOn(index)"
         class="single">
      <span class="outer"><i class="inner"
           v-if="item.isChecked"
           :style="item.isChecked?propsStyle:''"></i></span>
      <input type="radio"
             :name="item.name"
             :id="item.value"
             :value="item.value"
             v-model="radio">
      <span v-html="item.name"></span>
    </div>
  </div>
</template>

<script>
export default {
  name: "Radio",
  data() {
    return {
      radio: 0,
      propsStyle: {
        background: this.color
      }
    };
  },
  /*itemsRadio: [
{ name: "Hangzhou ", value: 0, isChecked: true},
{ name: "Shanghai ", value: 1, isChecked: false},
{ name: "Beijing ", value: 2, isChecked: false}
]*/
  props: {
    items: {
      type: Array,
      default: function() {
        return [];
      }
    },
    color: {
      type: String,
      default: "#65aef7"
    }
  },
  methods: {
    radioOn(index) {
      this.items.forEach(key => {
        key.isChecked = false;
      });
      this.items[index].isChecked = true;
      this.$emit("radioOn", index);
    }
  }
};
</script>

<style scoped>
.radio-container {
  display: flex;
  display: -webkit-flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  cursor: pointer;
}
.single {
  position: relative;
  display: flex;
  display: -webkit-flex;
  align-items: center;
  cursor: pointer;
}
input {
  width: 12px;
  height: 12px;
  appearance: none; /*Clear default style*/
  -webkit-appearance: none;
  opacity: 0;
  outline: none;
  cursor: pointer;
  vertical-align: middle;
  margin-top: -2px;
  margin-bottom: 1px;
}
.outer {
  height: 12px;
  width: 12px;
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  align-items: center;
  border: 1px solid #ccc;
  border-radius: 999px;
  position: absolute;
  top: 1px;
  z-index: 0;
}
.inner {
  background-color: green;
  width: 6px;
  height: 6px;
  border-radius: 999px;
}
</style>

Both of the above call HA in the form of component. You can see the effect as long as you pass in the corresponding data in the parent component

If the code is defective, please point out and spray lightly.

Posted by freakuency on Wed, 27 Nov 2019 12:44:48 -0800