“ 做好自己就好了呀 ”
问题
前段时间接到一个任务,需要做一个自定义的单选和多选按钮,但是之前都是用现成的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>
以上两个均以组件形式调用哈,只要在父组件中传入相应数据就可以看到效果哦
代码若有瑕疵,请指出,轻喷。