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

“ 做好本身就好了呀 ”

题目

前段时间接到一个使命,须要做一个自定义的单选和多选按钮,然则之前都是用现成的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>

以上两个均以组件情势挪用哈,只要在父组件中传入响应数据就能够看到结果哦

代码如有瑕疵,请指出,轻喷。

    原文作者:Booleen
    原文地址: https://segmentfault.com/a/1190000018876094
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞