0918 vue model, checkbox, radio button
自定 checkbox, radio 樣式,並簡單用 v-model 完成雙向綁定
usage:
<check-button-v2
value="複選選項值-1"
v-model="multipleSelectdList"
:disabled="true"
>複選選項文字-1</check-button-v2>
<template>
<label :class="['check-button-wrapper', customClass, {disabled: isDisabled}]">
<input type="checkbox"
:value="value"
:disabled="isDisabled"
v-model="proxyChecked" />
<span class="box"></span>
<slot></slot>
</label>
</template>
<script>
export default {
name: 'CheckButton',
props: {
customClass: { type: String },
checked: { type: [Array, Boolean], default: false },
disabled: { type: Boolean, default: false },
value: { type: String, default: null },
},
model: {
prop: 'checked',
event: 'change',
},
computed: {
isDisabled() {
return !!this.disabled
},
proxyChecked: {
get() {
return this.checked;
},
set(val) {
this.$emit('change', val);
}
},
},
};
</script>
<style lang="scss">
$base-border-width: 2;
$base-box-size: 25;
.disabled {
color: $gray;
cursor: not-allowed !important;
}
.check-button-wrapper {
cursor: pointer;
display: inline-flex;
align-items: center;
position: relative;
height: $base-box-size + px;
margin-right: 5px;
padding: 2px 10px 2px 30px;
user-select: none;
&:hover input ~ .box{
border-width: ($base-border-width + 1) + px;
border-color: $blue;
}
& input:disabled ~ .box{
border-color: $gray;
cursor: not-allowed;
&:before {
filter: grayscale(100%);
}
}
input {
position: absolute;
opacity: 0;
height: 0;
width: 0;
&:checked ~ .box {
&:before {
opacity: 1;
}
}
}
.box {
cursor: pointer;
display: inline-block;
@include size($base-box-size + px);
position: absolute;
top: 0;
left: 0;
border: $base-border-width + px solid $orange;
border-radius: 3px;
overflow: hidden;
&:before {
@include size($base-box-size - 9 + px);
content: '';
position: absolute;
top: 10%;
left: 10%;
background: url(check.svg) no-repeat 0 0 / 100% 100%;
opacity: 0;
transition: 0.4s ease;
}
}
}
</style>
radiobox
usage:
<radio-button-v2
btnValue="單選值-1"
v-model="selectdList"
:disabled="true"
>單選選項文字-1</radio-button-v2>
<template>
<label :class="['radio-button-wrapper', customClass, {disabled: isDisabled}]">
<input type="radio"
:value="btnValue"
:checked="(btnValue == value) ? 'checked' : ''"
:disabled="isDisabled"
@change="$emit('input', $event.target.value)" />
<span class="box"></span>
<slot></slot>
</label>
</template>
<script>
export default {
name: 'RadioButton',
props: {
customClass: { type: String },
btnValue: { default: true },
disabled: { type: Boolean, default: false },
value: { default: null }, // from v-model
},
computed: {
isDisabled() {
return !!this.disabled
}
},
};
</script>
<style lang="scss">
$base-border-width: 2;
$base-box-size: 25;
.disabled {
color: $gray;
cursor: not-allowed !important;
}
.radio-button-wrapper {
cursor: pointer;
display: inline-flex;
align-items: center;
position: relative;
height: $base-box-size + px;
margin-right:5px;
padding: 2px 10px 2px ($base-box-size + 5) + px;
user-select: none;
&:hover input ~ .box{
border-width: ($base-border-width + 1) + px;
border-color: $blue;
}
& input:disabled ~ .box{
border-color: $gray;
cursor: not-allowed;
&:before {
background: $gray;
}
}
input {
position: absolute;
opacity: 0;
height: 0;
width: 0;
&:checked ~ .box {
&:before {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
}
}
.box {
cursor: pointer;
display: inline-block;
@include size($base-box-size + px);
position: absolute;
top: 0;
left: 0;
border: $base-border-width + px solid $orange;
border-radius: 50%;
overflow: hidden;
&:before {
@include size($base-box-size - 8 + px);
border-radius: 100%;
background: $blue;
position: absolute;
top: 50%;
left: 50%;
content: '';
transform: translate(-50%, -50%) scale(0);
opacity: 1;
transition: 0.4s ease;
}
}
}
</style>