网站首页 » 前端开发 » Vue » Vue2 Element 模仿秀-多选框篇(Checkbox)
上一篇:
下一篇:

Vue2 Element 模仿秀-多选框篇(Checkbox)

前言

这篇主要是介绍 Vue Element 中的多选框,没有太多的言语,放都放在了代码的字里行间中,下面我们就来看看 Element 官方组件库是怎么实现 checkbox 组件的。代码比较多,建议要有针对性地看。比如,你在看源码的时候没看懂,那么你看到这篇文章就再好不过了。

在开始之前我们先来简单的看看代码文件结构:

├── index.html
├── assets
│  ├── fonts
│  │  ├── yunkus-icons.ttf
│  │  └── yunksu-icons.woff
│  └── icon.css
├── main.js
├── router
│  └── index.js      # 路由配置文件
├── mixins
│  └── emitter.js 
└── components
   ├── Home.vue          # 大的框架结构组件
   ├── Checkbox.vue
   ├── CheckboxButton.vue
   └── CheckboxGroup.vue

效果演示:

Vue Element 模仿秀-多选框篇(Checkbox)

大致就是上面这样。下面我们就来逐一看下关键的几个文件里的代码。

Home.vue
<template>
 <div class="container">
  <div class="panel panel-default">
    <div class="panel-heading">基础用法</div>
    <div class="panel-body">
      <yk-checkbox checked v-model="checkbox">珠海</yk-checkbox>
      {{checkbox}}
    </div>
  </div>

  <div class="panel panel-default">
      <div class="panel-heading">禁止勾选</div>
      <div class="panel-body">
        <yk-checkbox disabled v-model="checkbox1">珠海</yk-checkbox>
        <yk-checkbox disabled v-model="checkbox2">广州</yk-checkbox>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">多选</div>
    <div class="panel-body">
      <yk-checkbox-group v-model="checkedCities">
            <yk-checkbox :checked="city === '珠海'" v-for="city in cities" :key="city" :label="city"></yk-checkbox>
        </yk-checkbox-group>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">indeterminate 状态</div>
    <div class="panel-body">
      <yk-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</yk-checkbox>
      <div style="margin: 15px 0;"></div>
      <yk-checkbox-group v-model="checkedCities2" @change="handleCheckedCitiesChange" >
        <yk-checkbox border v-for="city in cities" :key="city" :label="city"></yk-checkbox>
      </yk-checkbox-group>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">可选项目数量的限制({{checkedCities3.length}}/2)</div>
    <div class="panel-body">
      <yk-checkbox-group v-model="checkedCities3" :max="2" :min="1">
        <yk-checkbox border v-for="city in cities" :key="city" :label="city"></yk-checkbox>
      </yk-checkbox-group>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">按钮样式</div>
    <div class="panel-body">
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxButton">
        <yk-checkbox-button :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox-button>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxButton1" size="medium">
        <yk-checkbox-button :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox-button>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxButton2" size="small">
        <yk-checkbox-button :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox-button>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxButton3" size="mini">
        <yk-checkbox-button :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox-button>
      </yk-checkbox-group>
      </div>
    </div>
  </div>

  <div class="panel panel-default">
    <div class="panel-heading">带有边框</div>
    <div class="panel-body">
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxBorder" border>
        <yk-checkbox :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxBorder1" border size="medium">
        <yk-checkbox :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxBorder2" border size="small">
        <yk-checkbox :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox>
      </yk-checkbox-group>
      </div>
      <div style="margin-top: 20px;">
      <yk-checkbox-group v-model="checkboxBorder3" border size="mini">
        <yk-checkbox :disabled="city === '北京'" :checked="city === '北京'" v-for="city in cities" :label="city" :key="city">{{city}}</yk-checkbox>
      </yk-checkbox-group>
      </div>
    </div>
  </div> 
 </div>
</template>

<script>
import YkCheckbox from "@/components/Checkbox";
import YkCheckboxButton from "@/components/CheckboxButton";
import YkCheckboxGroup from "@/components/CheckboxGroup";
import "@/assets/icon.css";
const cityOptions = ["珠海", "广州", "深圳", "上海", "北京"];
export default {
  name: "Home",
  components: { YkCheckbox, YkCheckboxButton, YkCheckboxGroup },
  data() {
    return {
      // 基础用法
      checkbox: true,

      // 禁止勾选
      checkbox1: false,
      checkbox2: true,

      // 公用数据
      cities: cityOptions,

      // 多选
      checkedCities: [],

      // indeterminate 状态( 全选、返选)
      checkAll: false,
      checkedCities2: [],
      isIndeterminate: false,

      // 可选项目数量的限制
      checkedCities3: ["珠海"],

      // 按钮样式
      checkboxButton: [],
      checkboxButton1: [],
      checkboxButton2: [],
      checkboxButton3: [],

      // 带有边框
      checkboxBorder: [],
      checkboxBorder1: [],
      checkboxBorder2: [],
      checkboxBorder3: []
    };
  },
  methods: {
    // 全选反选方法
    handleCheckAllChange(val) {
      this.checkedCities2 = val ? cityOptions : [];
      this.isIndeterminate = false;
    },
    handleCheckedCitiesChange(value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.cities.length;
      this.isIndeterminate =
        checkedCount > 0 && checkedCount < this.cities.length;
    }
  }
};
</script>
Checkbox.vue
<template>
  <label class="yk-checkbox"
  :class="[
    isBorder && buttonSize ? 'yk-checkbox-' + buttonSize : '',
    { 
      'is-checked': isChecked,
      'is-disabled': isDisabled,
      'is-bordered': isBorder
    }
    ]"><span class="yk-checkbox-box" :class="[
        {
          'is-checked': isChecked,
          'is-disabled': isDisabled,
          'is-indeterminate': indeterminate,
          }
        ]">
        <i class="yk-checkbox-icon"></i>
        <input
          v-if="trueLabel || falseLabel"
          class="yk-checkbox-input"
          type="checkbox"
          :name="name"
          :disabled="isDisabled"
          :true-value="trueLabel"
          :false-value="falseLabel"
          v-model="model"
          @change="handleChange">

        <input 
          v-else
          v-model="model" 
          type="checkbox" 
          :value="label" 
          :disabled="isDisabled" 
          :name="name" 
          @change="handleChange"
          class="yk-checkbox-input">
        </span>
        <span class="yk-checkbox-text">
          <slot></slot>
          <template v-if="!$slots.default">{{label}}</template> 
        </span>
    </label>
</template>
<script>
import Emitter from "@/mixins/emitter";
export default {
  name: "YkCheckbox",
  componentName: "YkCheckbox",
  mixins: [Emitter],
  props: {
    name: String,
    value: {},
    label: {},
    size: String,
    disabled: Boolean,
    checked: Boolean,
    border: Boolean,
    indeterminate: Boolean,
    trueLabel: [String, Number],
    falseLabel: [String, Number]
  },
  data() {
    return {
      selfModel: false,
      isLimitExceeded: false
    };
  },
  computed: {
    model: {
      get() {
        return this.isGroup
          ? this.store
          : this.value !== undefined ? this.value : this.selfModel;
      },
      set(val) {
        if (this.isGroup) {
          this.isLimitExceeded = false; // 标记是否可以继续勾选(false 为可断续勾选 | true 则不可以断续勾选)。

          // 下面这个就是判断一下并且设置是否可继续勾选
          this._checkboxGroup.min !== undefined &&
            this._checkboxGroup.min > val.length &&
            (this.isLimitExceeded = true);

          // 同上
          this._checkboxGroup.max !== undefined &&
            this._checkboxGroup.max < val.length &&
            (this.isLimitExceeded = true);

          this.isLimitExceeded === false &&
            this.dispatch("YkCheckboxGroup", "input", [val]);
          // 这里 dispatch input 事件让人感觉跟后面 dispatch change 事件有点重复了,为什么要 dispatch 两个?
          // 因为 dispatch input 事件是用来通知指定的祖先组件的 input 事件,当你指定的父组件用 v-model 绑定后,就会自动绑定一个 input 事件
          // dispatch change 事件就可以让你执行自定义的函数,也就是你可以在这事件触发的方法中添加自己的逻辑代码
        } else {
          this.$emit("input", val);
          this.selfModel = val;
        }
      }
    },
    // isBorder 属性值为:
    // 如果有 YkCheckboxGroup 包裹,那就先取它上面的 size 属性,如果没有,则取当前组件自身的 size 属性。
    buttonSize() {
      return this.isGroup
        ? this._checkboxGroup.size ? this._checkboxGroup.size : this.size
        : this.size ? this.size : "";
    },
    // isBorder 属性值为:
    // 如果有 YkCheckboxGroup 包裹,那就先取它上面的 border 属性,如果没有,则取当前组件自身的 border 属性。
    isBorder() {
      return this.isGroup
        ? this._checkboxGroup.border ? this._checkboxGroup.border : this.border
        : this.border ? this.border : false;
    },
    isGroup() {
      // 找父组件元素 YkCheckboxGroup
      let parent = this.$parent;
      while (parent) {
        if (parent.$options.componentName !== "YkCheckboxGroup") {
          parent = parent.$parent;
        } else {
          this._checkboxGroup = parent;
          return true;
        }
      }
      return false;
    },
    isDisabled() {
      // YkCheckboxGroup 上有值则到其身上的值,否则每个组件取自己身上的值
      return this.isGroup
        ? this._checkboxGroup.disabled || this.disabled
        : this.disabled || false;
    },
    isChecked() {
      // 1、{}.toString.call(this.model) 如果 this.model 为布尔值,则直接返回
      // 2、如果 this.model 是一个数组,则判断当前组件实例中的 label 值是否已经存在于 this.model 中,并返回判断结果(true 或者 false)
      // 3、this.model 不为 null 并且也不为 undefined ,也就是有设置 trueLabel 值的时候,则返回 this.model === this.trueLabel 的比对结果(true 或者 false)
      if ({}.toString.call(this.model) === "[object Boolean]") {
        return this.model;
      } else if (Array.isArray(this.model)) {
        return this.model.indexOf(this.label) > -1;
      } else if (this.model !== null && this.model !== undefined) {
        return this.model === this.trueLabel;
      }
    },
    // 返回选项值,如果 this._checkboxGroup 存在则返回挂在它上面的值,否则返回组件自身的值(场景为如果已经用了 yk-checkbox-group 把 yk-checkbox 项包裹起来了,
    // 但是没有给 yk-checkbox-group 上绑定 v-model,而是绑定在了 yk-checkbox,那么就会返回 yk-checkbox 组件实例上的 value 值)。
    store() {
      return this._checkboxGroup ? this._checkboxGroup.value : this.value;
    }
  },
  methods: {
    // 下面这个方法主要是用于全靠处理,把 change 事件分发到 YkCheckboxGroup 父组件中,让父组件执行相应的函数
    handleChange(ev) {
      let value;
      if (ev.target.checked) {
        // 选中时,如果此组件实例设置了 trueLabel 则返回 trueLabel 的值,
        // 如果没设置 trueLabel,那么直接返回 true 。
        // 下 else 同 if
        value = this.trueLabel === undefined ? true : this.trueLabel;
      } else {
        value = this.falseLabel === undefined ? false : this.falseLabel;
      }
      // 通过父组件事件
      this.$emit("change", value, ev);
      this.$nextTick(() => {
        if (this.isGroup) {
          // 通过父组件的父组件事件(这个 dispatch() 方法其实可以设置为任意的一个祖先组件)
          this.dispatch("YkCheckboxGroup", "change", [
            this._checkboxGroup.value
          ]);
        }
      });
    },
    // 这个方法的作用就是当你直接给 yk-checkbox 添加 checked 的时候,它会把你把对应的 checkbox 的 this.label 值放到 this.model 数组中也就是选中的值。
    // 这个方法只会在组件被创建时才会执行一次,也就是用来初始化 checkbox 的状态而已。
    addToStore() {
      if (Array.isArray(this.model) && this.model.indexOf(this.label) === -1) {
        this.model.push(this.label);
      } else {
        this.model = this.trueLabel || true;
      }
    }
  },
  created() {
    // 如果有组件通过 checked 来设置选中状态,那么就调用 addToStore() 方法,把它的 label 值添加到选中的数组中
    this.checked && this.addToStore();
  }
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.yk-checkbox {
  color: #606266;
  font-weight: 500;
  font-size: 14px;
  position: relative;
  cursor: pointer;
  display: inline-block;
  white-space: nowrap;
  user-select: none;
}
.yk-checkbox-box {
  white-space: nowrap;
  cursor: pointer;
  outline: none;
  display: inline-block;
  line-height: 1;
  position: relative;
  vertical-align: middle;
}
.yk-checkbox-box.is-checked .yk-checkbox-icon {
  background-color: #409eff;
  border-color: #409eff;
}
.yk-checkbox-box.is-checked + .yk-checkbox-text {
  color: #409eff;
}
.yk-checkbox-icon {
  display: inline-block;
  position: relative;
  border: 1px solid #dcdfe6;
  border-radius: 2px;
  box-sizing: border-box;
  width: 14px;
  height: 14px;
  background-color: #fff;
  z-index: 1;
  transition: border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46),
    background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46);
}
.yk-checkbox-icon:after {
  box-sizing: content-box;
  content: "";
  border: 1px solid #fff;
  border-left: 0;
  border-top: 0;
  height: 7px;
  left: 4px;
  position: absolute;
  top: 1px;
  transform: rotate(45deg) scaleY(0);
  width: 3px;
  transition: transform 0.15s cubic-bezier(0.71, -0.46, 0.88, 0.6) 0.05s;
  transform-origin: center;
}
.yk-checkbox-box.is-checked .yk-checkbox-icon:after {
  transform: rotate(45deg) scaleY(1);
}
.yk-checkbox-input {
  opacity: 0;
  outline: none;
  position: absolute;
  margin: 0;
  width: 0;
  height: 0;
  z-index: -1;
}
.yk-checkbox-box.is-disabled .yk-checkbox-icon:after {
  cursor: not-allowed;
  border-color: #c0c4cc;
}
.yk-checkbox-box.is-disabled .yk-checkbox-icon {
  background-color: #edf2fc;
  border-color: #dcdfe6;
  cursor: not-allowed;
}
.yk-checkbox-box.is-disabled + span.yk-checkbox-text {
  color: #c0c4cc;
  cursor: not-allowed;
}
.yk-checkbox-box.is-indeterminate .yk-checkbox-icon {
  background-color: #409eff;
  border-color: #409eff;
}
.yk-checkbox-box.is-indeterminate .yk-checkbox-icon:before {
  content: "";
  position: absolute;
  display: block;
  background-color: #fff;
  height: 2px;
  transform: scale(0.5);
  left: 0;
  right: 0;
  top: 5px;
}

.yk-checkbox-box.is-indeterminate .yk-checkbox-icon:after {
  display: none;
}
.yk-checkbox + .yk-checkbox {
  margin-left: 30px;
}
.yk-checkbox-text {
  display: inline-block;
  padding-left: 10px;
  line-height: 19px;
  font-size: 14px;
}
.yk-checkbox.is-bordered.is-checked {
  border-color: #409eff;
}
.yk-checkbox.is-bordered {
  padding: 9px 20px 9px 10px;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  box-sizing: border-box;
  line-height: normal;
  height: 40px;
}
.yk-checkbox.is-bordered.yk-checkbox-mini {
  padding: 3px 15px 3px 10px;
  border-radius: 3px;
  height: 28px;
}
.yk-checkbox.is-bordered.yk-checkbox-small {
  padding: 5px 15px 5px 10px;
  border-radius: 3px;
  height: 32px;
}
.yk-checkbox.is-bordered.yk-checkbox-medium {
  padding: 7px 20px 7px 10px;
  border-radius: 4px;
  height: 36px;
}
.yk-checkbox.is-bordered.is-disabled {
  border-color: #ebeef5;
  cursor: not-allowed;
}
</style>
CheckboxButton.vue
<template>
  <label class="yk-checkbox-button"
  :class="[
    buttonSize ? 'yk-checkbox-button-' + buttonSize : '',
    { 
      'is-checked': isChecked,
      'is-disabled': isDisabled,
    }
    ]">
        <i class="yk-checkbox-button-icon"></i>
        <input
          v-if="trueLabel || falseLabel"
          class="yk-checkbox-button-input"
          type="checkbox"
          :name="name"
          :disabled="isDisabled"
          :true-value="trueLabel"
          :false-value="falseLabel"
          v-model="model"
          @change="handleChange">

        <input 
          v-else
          v-model="model" 
          type="checkbox" 
          :value="label" 
          :disabled="isDisabled" 
          :name="name" 
          @change="handleChange"
          class="yk-checkbox-button-input">
  
        <span class="yk-checkbox-button-text">
          <slot></slot>
          <template v-if="!$slots.default">{{label}}</template> 
        </span>
    </label>
</template>
<script>
import Emitter from "@/mixins/emitter";
export default {
  name: "YkCheckboxButton",
  componentName: "YkCheckboxButton",
  mixins: [Emitter],
  props: {
    name: String,
    value: {},
    label: {},
    size: String,
    disabled: Boolean,
    checked: Boolean,
    border: Boolean,
    indeterminate: Boolean,
    trueLabel: [String, Number],
    falseLabel: [String, Number]
  },
  data() {
    return {
      selfModel: false,
      isLimitExceeded: false
    };
  },
  computed: {
    model: {
      get() {
        return this.isGroup
          ? this.store
          : this.value !== undefined ? this.value : this.selfModel;
      },
      set(val) {
        if (this.isGroup) {
          this.isLimitExceeded = false; // 标记是否可以继续勾选(false 为可断续勾选 | true 则不可以断续勾选)。

          // 下面这个就是判断一下并且设置是否可继续勾选
          this._checkboxGroup.min !== undefined &&
            this._checkboxGroup.min > val.length &&
            (this.isLimitExceeded = true);

          // 同上
          this._checkboxGroup.max !== undefined &&
            this._checkboxGroup.max < val.length &&
            (this.isLimitExceeded = true);

          this.isLimitExceeded === false &&
            this.dispatch("YkCheckboxGroup", "input", [val]);
          // 这里 dispatch input 事件让人感觉跟后面 dispatch change 事件有点重复了,为什么要 dispatch 两个?
          // 因为 dispatch input 事件是用来通知指定的祖先组件的 input 事件,当你指定的父组件用 v-model 绑定后,就会自动绑定一个 input 事件
          // dispatch change 事件就可以让你执行自定义的函数,也就是你可以在这事件触发的方法中添加自己的逻辑代码
        } else {
          this.$emit("input", val);
          this.selfModel = val;
        }
      }
    },

    // 如果有 YkCheckboxGroup 包裹,那就先取它上面的 size 属性,如果没有,则取当前组件自身的 size 属性。
    buttonSize() {
      return this.isGroup
        ? this._checkboxGroup.size ? this._checkboxGroup.size : this.size
        : this.size ? this.size : "";
    },

    isGroup() {
      // 找父组件元素 YkCheckboxGroup
      let parent = this.$parent;
      while (parent) {
        if (parent.$options.componentName !== "YkCheckboxGroup") {
          parent = parent.$parent;
        } else {
          this._checkboxGroup = parent;
          return true;
        }
      }
      return false;
    },
    isDisabled() {
      // YkCheckboxGroup 上有值则到其身上的值,否则每个组件取自己身上的值
      return this.isGroup
        ? this._checkboxGroup.disabled || this.disabled
        : this.disabled || false;
    },
    isChecked() {
      // 1、{}.toString.call(this.model) 如果 this.model 为布尔值,则直接返回
      // 2、如果 this.model 是一个数组,则判断当前组件实例中的 label 值是否已经存在于 this.model 中,并返回判断结果(true 或者 false)
      // 3、this.model 不为 null 并且也不为 undefined ,也就是有设置 trueLabel 值的时候,则返回 this.model === this.trueLabel 的比对结果(true 或者 false)
      if ({}.toString.call(this.model) === "[object Boolean]") {
        return this.model;
      } else if (Array.isArray(this.model)) {
        return this.model.indexOf(this.label) > -1;
      } else if (this.model !== null && this.model !== undefined) {
        return this.model === this.trueLabel;
      }
    },
    // 返回选项值,如果 this._checkboxGroup 存在则返回挂在它上面的值,否则返回组件自身的值(场景为如果已经用了 yk-checkbox-group 把 yk-checkbox 项包裹起来了,
    // 但是没有给 yk-checkbox-group 上绑定 v-model,而是绑定在了 yk-checkbox,那么就会返回 yk-checkbox 组件实例上的 value 值)。
    store() {
      return this._checkboxGroup ? this._checkboxGroup.value : this.value;
    }
  },
  methods: {
    // 下面这个方法主要是用于全靠处理,把 change 事件分发到 YkCheckboxGroup 父组件中,让父组件执行相应的函数
    handleChange(ev) {
      let value;
      if (ev.target.checked) {
        // 选中时,如果此组件实例设置了 trueLabel 则返回 trueLabel 的值,
        // 如果没设置 trueLabel,那么直接返回 true 。
        // 下 else 同 if
        value = this.trueLabel === undefined ? true : this.trueLabel;
      } else {
        value = this.falseLabel === undefined ? false : this.falseLabel;
      }
      // 通过父组件事件
      this.$emit("change", value, ev);
      this.$nextTick(() => {
        if (this.isGroup) {
          // 通过父组件的父组件事件(这个 dispatch() 方法其实可以设置为任意的一个祖先组件)
          this.dispatch("YkCheckboxGroup", "change", [
            this._checkboxGroup.value
          ]);
        }
      });
    },
    // 这个方法的作用就是当你直接给 yk-checkbox 添加 checked 的时候,它会把你把对应的 checkbox 的 this.label 值放到 this.model 数组中也就是选中的值。
    // 这个方法只会在组件被创建时才会执行一次,也就是用来初始化 checkbox 的状态而已。
    addToStore() {
      if (Array.isArray(this.model) && this.model.indexOf(this.label) === -1) {
        this.model.push(this.label);
      } else {
        this.model = this.trueLabel || true;
      }
    }
  },
  created() {
    // 如果有组件通过 checked 来设置选中状态,那么就调用 addToStore() 方法,把它的 label 值添加到选中的数组中
    this.checked && this.addToStore();
  }
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.yk-checkbox-button,
.yk-checkbox-button-text {
  position: relative;
  display: inline-block;
}
.yk-checkbox-group {
  font-size: 0;
}
.yk-checkbox-button-input {
  opacity: 0;
  outline: none;
  position: absolute;
  margin: 0;
  z-index: -1;
}
.yk-checkbox-button:first-child .yk-checkbox-button-text {
  border-left: 1px solid #dcdfe6;
  border-radius: 4px 0 0 4px;
  box-shadow: none !important;
}
.yk-checkbox-button.is-checked .yk-checkbox-button-text {
  color: #fff;
  background-color: #409eff;
  border-color: #409eff;
  box-shadow: -1px 0 0 0 #8cc5ff;
}
.yk-checkbox-button-text {
  line-height: 1;
  font-weight: 500;
  white-space: nowrap;
  vertical-align: middle;
  cursor: pointer;
  background: #fff;
  border: 1px solid #dcdfe6;
  border-left: 0;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 0;
  transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 0;
}
.yk-checkbox-button:last-child .yk-checkbox-button-text {
  border-radius: 0 4px 4px 0;
}
.yk-checkbox-button.is-checked .yk-checkbox-button-text {
  color: #fff;
  background-color: #409eff;
  border-color: #409eff;
  box-shadow: -1px 0 0 0 #8cc5ff;
}
.yk-checkbox-button.is-disabled .yk-checkbox-button-text {
  color: #c0c4cc;
  cursor: not-allowed;
  background-image: none;
  background-color: #fff;
  border-color: #ebeef5;
  box-shadow: none;
}
.yk-checkbox-button-input:disabled:checked + .yk-checkbox-button-text {
  background-color: #f2f6fc;
}

.yk-checkbox-button-medium .yk-checkbox-button-te {
  padding: 10px 20px;
  font-size: 14px;
  border-radius: 0;
}

.yk-checkbox-button-small .yk-checkbox-button-text {
  padding: 9px 15px;
  font-size: 12px;
  border-radius: 0;
}
.yk-checkbox-button-mini .yk-checkbox-button-text {
  padding: 7px 15px;
  font-size: 12px;
  border-radius: 0;
}
</style>
CheckboxGroup.vue
<template>
  <div class="yk-checkbox-group">
    <slot></slot>
  </div>
</template>
<script>
import Emitter from "@/mixins/emitter";
export default {
  name: "YkCheckboxGroup",
  componentName: "YkCheckboxGroup",
  mixins: [Emitter],
  props: {
    value: {},
    size: String,
    border: Boolean,
    max: Number,
    min: Number
  }
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.yk-radio-group {
  display: inline-block;
  line-height: 1;
  vertical-align: middle;
  font-size: 0;
}
</style>

上面的代码有点多,但是不要紧。如果你觉得看不进去,那么你也可以不用从头到尾看一篇,你可以对照官方的源码,看到不明白的可以在对应的文件中找到相应的代码,看看里面的注释。相信这样,本文才能发挥最大的价值。毕竟这只是我自己个人走过的路,然后再记录下来的,可能你看了会一脸懵逼,还是那句话,用你自己觉得合适的方式去编程,这是学习编程的最好办法,但也不要总是局限于自己的世界里,还得多看看别人的代码,很多时候你会发现同一个实现,别人不一样的书写风格,不一样的解决思路。

关于上面的 emitter.js  文件可以看这里《Vue Element emitter.js 详解》,我单独把它分享一篇文章,因为后面估计还会有很多组件要用到它。同样的,代码里面也作了详细的注释。

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/vue-element-parody-checkbox/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END