checkbox
-
Label
<label class="el-checkbox"> <!-- 复选框 --> <span class="el-checkbox__input"></span> <!-- 文字部分 --> <span class="el-checkbox__label"></span> </label>
-
选中样式
.el-checkbox__inner {//🔲 复选框样式 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 .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46); } .el-checkbox__inner: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 .15s ease-in .05s; transform-origin: center; } .el-checkbox__input.is-checked .el-checkbox__inner:after {//✅显示 transform: rotate(45deg) scaleY(1); }
这是
el-checkbox__inner
类的after伪元素,里面是一个只有右下border的长方形经过旋转45度后的图形,也就是一个勾的形状,所以这个勾只是纯粹的css实现而已,好处是简化了html结构,并且还用了transition
来添加点击后勾变大的动画效果,这里是通过过渡transform
的scaleY
的值来实现,未选中时scaleY
为0,选中时为1,就实现了勾放大的效果
因此要善用伪元素,会简化很多不必要的代码 -
slot
<!-- 文字部分 --> <span v-if="$slots.default || label" class="el-checkbox__label"> <slot></slot> <template v-if="!$slots.default">{{ label }}</template> </span>
我感觉radio的这里比这个要简洁,完全可以替换成后背插槽
//radio <span class="el-checkbox__label"> <slot> {{ label }} </slot> </span>
-
el-checkbox__original 隐藏input样式
-
focus
.el-checkbox__input.is-foucs .el-checkbox__inner { border-color: #409eff; }
这里跟radio不一样,这里是有
is-focus
添加focus样式。 -
初始化
setStoreValue(props, { model }) const setStoreValue = (props: ICheckboxProps, { model }: PartialReturnType<typeof useModel>) => { function addToStore() { //如果是array,且当前model中未选中当前值时,将其选中 if ( Array.isArray(model.value) && !model.value.includes(props.label) ) { model.value.push(props.label) } else { model.value = props.trueLabel || true } } //props.checked 为true时,修改model的值 使props.checked与model值 一致 props.checked && addToStore() }
-
isChecked
<span :class="{ 'is-checked': isChecked,}"></span> <input :checked="isChecked"/> //是否被选中 const isChecked = computed(() => { const value = model.value //toTypeString 源于vue //const objectToString = Object.prototype.toString; //const toTypeString = (value) => objectToString.call(value); //1.boolean 2.array 3.trueLabel 三种情况的判断 if (toTypeString(value) === '[object Boolean]') { return value } else if (Array.isArray(value)) { return value.includes(props.label) } else if (value !== null && value !== undefined) { return value === props.trueLabel } })
-
model
const model = computed({ get() { return isGroup.value ? store.value : props.modelValue ?? selfModel // 「双问号」?? 如果给定变量值为 null 或者 undefined,则使用双问号后的默认值,否则使用该变量值。 }, set(val: unknown) { if (isGroup.value && Array.isArray(val)) { // checkbox-group //是否突破限制 判断 isLimitExceeded.value = false // min定义了 且 当前选中长度 < min if (checkboxGroup.min !== undefined && val.length < checkboxGroup.min.value) { isLimitExceeded.value = true } // max定义了 且 当前选中长度 > max if (checkboxGroup.max !== undefined && val.length > checkboxGroup.max.value) { isLimitExceeded.value = true } //未突破限制 修改checkboxGroup的value值 // ?.链式调用。 isLimitExceeded.value === false && checkboxGroup?.changeEvent?.(val) } else { emit(UPDATE_MODEL_EVENT, val)//update:modelValue 修改checkbox的value值 selfModel = val as boolean } }, }) function handleChange(e: InputEvent) { if (isLimitExceeded.value) return //如果突破限制 就不能修改值 const target = e.target as HTMLInputElement const value = target.checked ? props.trueLabel ?? true : props.falseLabel ?? false emit('change', value, e) }
不过这块有问题
就是 当有min>1时,初始化数组为[],不能选中值。#1742
所以在学习的时候,也是能发现源码中存在的一些问题的😂
-
watch
// 监听value变化,与表单验证有关 watch(() => props.modelValue, val => { elFormItem.formItemMitt?.emit('el.form.change', [val]) })