Element-ui checkbox
<template>
<!-- `checked` 为 true 或 false -->
<el-checkbox v-model="checked">备选项</el-checkbox>
</template>
<script>
export default {
data() {
return {
checked: true
};
}
};
</script>
剖析
- checkbox 有三种状态:选中,取消选中,半选
- checkbox 有三种使用情况:
- 单独使用, v-model绑定的值为布尔类型
- 单独使用,v-model绑定的值为数组类型,且需与label搭配
- 与checkbox-group搭配使用,且需与label搭配(checkbox-group见下回)
测试代码
<template>
<div>
<p>checkbox</p>
<!-- 第一种情况 -->
<y-checkbox v-model="checkboxValue" @change="handleChange">杭州</y-checkbox>
<!-- 第二种情况 -->
<y-checkbox v-model="checkboxArr" label="1" @change="handleChange">杭州</y-checkbox>
<!-- 半选中状态 -->
<y-checkbox
:indeterminate="checkboxIndeterminate"
v-model="checkboxIndeterminateValue"
@change="handleIndeterminate">半选中状态</y-checkbox>
</div>
</template>
<script>
export default {
data() {
return {
checkboxValue: true,
checkboxArr: [
'1',
'2',
'3',
],
checkboxIndeterminate: true,
checkboxIndeterminateValue: false,
}
},
watch: {
checkboxValue() {
console.log('父组件checkboxValue', this.checkboxValue)
}
},
methods: {
handleChange(data) {
console.log('父组件change事件', data);
},
handleIndeterminate(data) {
console.log('半选', data);
// 将半选控制标识更改为false, 便可以正常选中和取消选中了
this.checkboxIndeterminate = false;
}
}
}
</script>
- 注意:单独使用checkbox时,且设置了半选中
:indeterminate="checkboxIndeterminate"
,则需要绑定change事件以更改该checkboxIndeterminate为false,从而正常选中和取消选中
组件checkbox
template
<template>
<!-- checkbox选中状态: 选中, 不选中, 半选
单独使用checkbox,如何判断选中状态呢?
prop接收的value值类型需为布尔类型: true选中, false不选中
半选中状态如何处理?
半选中状态下,如果再次点击,将indeterminate置为false, 便可以选中和取消选中了
但是只能在父组件中控制indeterminate的值(因为子组件不能更改父组件prop传进来的值) -->
<label
class="y-checkbox"
role="checkbox">
<!-- checkbox分两部分, 一部分是多选框,一部分是标签 -->
<span
class="y-checkbox__input"
:class="{
'is-checked': isChecked,
'is-indeterminate': indeterminate,
}"
>
<!-- y-checkbox__inner 替换了原生多选框的样式,原生多选框只有两种状态,通过自定义的样式可定义第三种半选状态-->
<span class="y-checkbox__inner"></span>
<!-- 原生多选框, 如果value和labl都没有传, 则选中状态变化后, model值为true或false
定义ref以便获取该dom元素从而通知该原生多选框的选中状态
自定义属性 aria-hidden 可直观明白该html是否展示
-->
<input
ref="checkbox"
class="y-checkbox__original"
type="checkbox"
:value="label"
aria-hidden="false"
v-model="model"
@change="handleChange"/>
</span>
<!-- 标签, 如果子元素存在则展示子元素, 否则标签为label -->
<span
class="y-checkbox__label">
<slot></slot>
<templat v-if="!$slots.default">{{label}}</templat>
</span>
</label>
</template>
scripts
checkbox 选中状态判定
<script>
export default {
name: 'YCheckbox',
props: {
value: {},
// label选中状态的值, 只有在checkbox-group或者value为数组类型的时候方可有效
label: {},
// 半选中状态
indeterminate: Boolean,
},
computed: {
// 原生多选框值的选中状态
model: {
get() {
return this.value;
},
set(val) {
console.log('model发生了变化', val);
/**
* 通知父组件value值发生了变化
* v-model双向绑定, 手动通知父组件吗?这是因为并非是value值发生了变化,
* 而是另一个依赖变量model发生了变化, model发生变化后value也要变, 所以需要手动触发
*/
this.$emit('input', val);
}
},
/**
* 选中状态的判定
* 如何判定选中状态?
* 这里分三种情况,一种是单个使用(value为布尔类型, label为undefined)
* 一种情况是单个使用(value为数组类型, label为数组中的某一项)
* 一种情况是父组件为checkbox-group(value为undefined, label有值)
*/
isChecked() {
// this.model.toString(), {}.toString.call(this.model)有什么区别?
// 若this.model=true, 则 this.model.toString()->true, {}.toString.call(this.model)->[object Boolean]
console.log('第一种情况', {}.toString.call(this.model), {}.toString.call(this.model) === '[object Boolean]')
// 如果是第一种情况, 单独使用多选框且value值为布尔类型
if({}.toString.call(this.model) === '[object Boolean]') {
return this.model;
}
// 如果是第二种情况,单独使用且value为数组类型
// 数组的判定类型有几种?
// console.log('第二种情况', this.model, Array.isArray(this.model), this.model.indexOf(this.label), this.model.includes(this.label));
else if(Array.isArray(this.model)) {
console.log(this.model, this.label);
// 判断值是否存在于数组中
// indexOf和includes的区别
return this.model.indexOf(this.label) > -1;
}
// 第三种情况,父组件是checkbox-group
console.log('第三种情况,父组件是checkbox-group');
}
},
methods: {
/**
* 父组件可能有change事件,即选中状态变化后的回调
* 因为这是由原生多选框选中状态变化后的回调,需要等视图更新后方可获取到新值,并将新值传给回调函数
*/
handleChange() {
// console.log('原生checkbox发生了变化', this.model);
this.$nextTick(()=>{
this.$emit('change', this.model);
})
},
},
mounted() {
console.log('checkbox', this.value, this.label);
// console.log(this.model.toString(), {}.toString.call(this.model), {}.toString.call(this.model) === '[object Boolean]')
},
watch: {
isChecked() {
console.log('watchisChecked', this.isChecked)
}
}
}
</script>
this.model.toString()
与{}.toString.call(this.model)
的区别indexOf
与includes
的区别
style
.y-checkbox {
position: relative;
margin-right: 30px;
}
.y-checkbox:last-child {
margin-right: 0;
}
.y-checkbox__input {
position: relative;
}
.y-checkbox__inner {
display: inline-block;
position: relative;
width: 14px;
height: 14px;
border: 1px solid #dcdfe6;
border-radius: 2px;
box-sizing: border-box;
vertical-align: middle;
}
.y-checkbox__inner::after {
content: '';
display: content-box;
width: 3px;
height: 7px;
position: absolute;
top: 2px;
left: 4px;
box-sizing: border-box;
border: 1px solid #fff;
border-top: 0;
border-left: 0;
transform: rotate(0deg) scale(0);
}
/* 选中样式 */
.y-checkbox__input.is-checked .y-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
/* 选中后中间的对号,通过旋转45度得到 */
.y-checkbox__input.is-checked .y-checkbox__inner::after {
transform: rotate(45deg) scale(1);
}
/* 半选中状态 */
.y-checkbox__input.is-indeterminate .y-checkbox__inner {
background-color: #409eff;
border-color: #409eff;
}
/* 半选中状态 中间的横杠 */
.y-checkbox__input.is-indeterminate .y-checkbox__inner::after {
content: none;
}
.y-checkbox__input.is-indeterminate .y-checkbox__inner::before {
content: '';
display: inline-block;
height: 2px;
background-color: #fff;
position: absolute;
top: 5px;
right: 0;
left: 0;
transform: scale(.5);
}
/* 隐藏原生多选框 */
.y-checkbox__original {
opacity: 0;
outline: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
margin: 0;
}
.y-checkbox__label {
font-size: 14px;
display: inline-block;
padding-left: 10px;
}
总结
- 该 checkbox 测试,实现v-model、lable属性和change事件
- checkbox 逻辑跟 radio 有很多相似之处,相似的html结构、判定逻辑
- checkbox 三种选中状态(注意半选中状态切换到选中状态和取消选中状态)以及其两种使用形式
- indexOf 与 includes 的区别
- {}.toString.call(obj) 与 obj.toString() 的区别
- checkbox 选中状态下中间的对号的生成(伪元素创建,旋转)
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!