当前位置: 首页 > Web前端 > HTML5

Vue自定义单选按钮和复选框组件

时间:2023-04-05 22:23:27 HTML5

“ 做好自己就好了呀 ”问题前段时间接到一个任务,需要做一个自定义的单选和多选按钮,但是之前都是用现成的UI框架,都不用自己写样式,直接一套就是干!但是进公司后,发现部门不适用外部UI框架,好吧,那我就自己写呗!构思我想到的办法是运用原生的radio和CheckBox,再通过样式覆盖的方式。兼容性由于在写组件时使用了flex布局,so 低版本浏览器不支持的哈,具体有关flex的知识可以学习一下阮大佬的博客:Flex 布局教程:语法篇废话不多说上代码<!-- 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实例:[{name:'选项一',isChecked:false}], name:可以是html, 需要显示和隐藏的加上isShow字段,true为隐藏,如下: [{name:'选项一',isChecked:false,isShow:false}] */ items: { type: Array, default: function() { return []; } }, // 已选框的颜色透明度 opacity: { type: Boolean, default: false }, // flex布局纵轴方向 isColumn: { type: Boolean, default: false }, // 最大选项数 limit: { type: Number, default: 2 }, // 已选项框的背景色 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; } // 将所选项的value值传出去,并勾选 /* 也可将这句代码放在父组件调用这个事件的地方,可以使得复选框智能在特定条件下被选中*/ 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; /* 前面三行代码是为了让checkbox按钮与文字对齐 */ width: 12px; height: 12px; appearance: none; /*清楚默认样式*/ -webkit-appearance: none; opacity: 0; outline: none; cursor: pointer; /* 注意不能设置为display:none*/}/* 选项框的样式修改 */.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: "杭州", value: 0, isChecked: true },{ name: "上海", value: 1, isChecked: false },{ name: "北京", 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; /*清楚默认样式*/ -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>以上两个均以组件形式调用哈,只要在父组件中传入相应数据就可以看到效果哦代码若有瑕疵,请指出,轻喷。