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