オプションボックスコンポーネント
<template>
<div
:class="[
'optionBox',
OptionChecked ? 'optionBoxChecked' : '',
!text ? 'optionDefaultText' : '',
type === 'radio' ? 'optionBoxRadio' : '',
]"
@click="onChangeChecked"
>
{
{
text || '*' }}
</div>
</template>
<script>
export default {
name: 'OptionBox',
props: {
/** 按钮框里的文字,如果不传就是√ */
text: {
type: String,
default: '',
},
/** 是否选中状态,从外界传入 */
checked: {
type: [Boolean, undefined],
default: undefined,
},
/** 一共两种类型 checkbox 和 radio */
type: {
type: String,
default: 'checkbox',
},
},
data() {
return {
OptionChecked: this.checked || false,
};
},
watch: {
checked(value) {
this.OptionChecked = value;
},
},
methods: {
onChangeChecked() {
if (this.checked === undefined) {
this.OptionChecked = !this.OptionChecked;
this.$emit('change', this.OptionChecked);
} else {
this.$emit('change', !this.checked);
}
},
},
};
</script>
<style lang="less">
.optionBox {
color: #666;
width: 30px;
height: 30px;
border: 1px solid #d9d9d9;
text-align: center;
line-height: 28px;
display: inline-block;
font-size: 14px;
background: #fff;
border-radius: 2px;
cursor: pointer;
}
.optionBoxRadio {
border-radius: 50%;
}
.optionBoxChecked {
color: #fff;
background: #025299;
border: 1px solid #025299;
}
.optionDefaultText {
position: relative;
color: transparent;
&::before {
content: '';
width: 6px;
height: 12px;
top: 5px;
left: 10px;
transform: rotate(45deg);
border-right: 3px solid #fff;
border-bottom: 3px solid #fff;
position: absolute;
}
}
</style>
オプションコンポーネントは、optionBoxコンポーネントに基づいてカプセル化された高レベルのコンポーネントです。
<template>
<div :class="$style['scf-option-warpper']">
<scf-option-box
ref="optionBoxRef"
:text="text"
:type="type"
:checked="checked"
@change="onChangeValue"
/>
<span
:class="[$style['scf-option-name'], nameChecked ? $style['scf-option-name-checked'] : '']"
@click="onClickOption"
>{
{
name }}</span
>
</div>
</template>
<script>
import OptionBox from '@/components/option-box/option-box';
export default {
name: 'Option',
components: {
'scf-option-box': OptionBox,
},
props: {
/** 选项对应的文字 */
name: {
type: String,
default: '',
require: true,
},
/** 选项对应的值 */
value: {
type: String,
default: '',
require: true,
},
/** 选项按钮上的文字 */
text: {
type: String,
default: '',
},
/** 按钮的类型,checkbox和radio */
type: {
type: String,
default: 'checkbox',
},
/** 是否选中 */
checked: {
type: [Boolean, undefined],
default: undefined,
},
},
data() {
return {
/** 用于控制name的颜色,根据返回的按钮当前的状态 */
nameChecked: this.checked || false,
};
},
watch: {
checked: {
handler(newValue) {
this.nameChecked = newValue;
},
immediate: true,
},
},
methods: {
onChangeValue(checkedValue) {
this.$emit('change', checkedValue, this.value);
if (this.checked === undefined) {
this.nameChecked = checkedValue;
}
},
onClickOption() {
this.$refs.optionBoxRef.onChangeChecked();
},
},
};
</script>
<style module lang="less">
.scf-option-warpper {
cursor: pointer;
display: inline-block;
}
.scf-option-name {
padding-left: 10px;
color: #333;
}
.scf-option-name-checked {
color: #025299;
}
</style>
オプショングループコンポーネントは、オプションコンポーネントに基づいてカプセル化された高レベルのコンポーネントです。
<template>
<div>
<div v-for="item in options" :key="item.value" class="option-div">
<paper-option
:name="item.name"
:text="type === 'sort' ? optionText[item.value] : item.text"
:value="item.value"
:type="optionType"
:checked="checkedValues.indexOf(item.value) >= 0"
@change="OptionChangeValue"
/>
</div>
</div>
</template>
<script>
import Option from '../option/option';
export default {
name: 'OptionGroup',
components: {
'paper-option': Option,
},
props: {
/**
* @option 渲染的每一个小的选项 {name:string, text:string, value:string}
* name 每一个小选项对应的提示
* text 每一个小选项按钮的文字
* value 每一个小选项对应的值
* */
options: {
type: Array,
require: true,
},
/**
* @type string 复选框 checkbox | 单选框 radio | 排序 sort
* */
type: {
type: String,
default: 'checkbox',
},
values: {
type: Array,
},
},
data() {
return {
checkedValues: this.values || [],
isCompelete: false,
};
},
computed: {
optionType: {
get() {
let result = this.type;
if (this.type === 'sort') {
result = 'radio';
}
return result;
},
},
optionText: {
get() {
let result = {
};
if (this.type === 'sort') {
this.checkedValues.forEach((item, i) => {
result[item] = String(i + 1);
});
}
return result;
},
},
},
watch: {
checkedValues: {
handler(newValue) {
const length = newValue?.length || 0;
let result = false;
if (this.type !== 'sort') {
if (length) {
result = true;
}
} else {
if (length === this.option?.length) {
result = true;
}
}
this.isCompelete = result;
this.$emit('change', newValue, result);
},
},
},
methods: {
OptionChangeValue(isChecked, checkedValue) {
if (isChecked) {
if (this.type === 'radio') {
this.checkedValues = [];
}
this.checkedValues.push(checkedValue);
} else {
const order = this.checkedValues.findIndex((item) => {
return item === checkedValue;
});
if (order >= 0) {
this.checkedValues.splice(order, 1);
}
}
},
},
};
</script>
<style lang="less">
.option-div {
margin-top: 16px;
}
</style>
使い方
<template>
<div>
<div>多选项组</div>
<scf-option-group :options="options" @change="onOptionGroupChange" />
<div>单选项组</div>
<scf-option-group :options="options" type="radio" @change="onOptionGroupChange" />
<div>排序选项组</div>
<scf-option-group
:options="options"
type="sort"
:values="optionValues"
@change="onOptionGroupChange"
/>
</div>
</template>
<script>
import OptionGroup from '@/components/option-group/option-group';
export default {
name: 'PaperUi',
components: {
'scf-option-group': OptionGroup,
},
data() {
return {
options: [
{
value: '1',
name: '这是选项1',
text: '',
},
{
value: '2',
name: '这是选项2',
text: '',
},
{
value: '3',
name: '这是选项3',
text: '',
},
{
value: '4',
name: '这是选项4',
text: '',
},
],
};
},
methods: {
onOptionGroupChange(value, isCompelete) {
console.log(value, isCompelete);
},
},
};
</script>