Foreword
Welcome to follow the public account of the same name “
Panda's Cat
“. Articles will be updated simultaneously, and you can also quickly join the front-end communication group!
Recently, my friends have encountered another need, which is to add a border style to the check box when it is selected, which is roughly as follows:
Original effect:
What you need now:
The hiding time of this outer border is:
- Checkbox unchecked
- Click outside the checkbox content
The friends quickly completed the requirements, but the test students reported the following BUG:
-
Normal speed click
-
Quickly click back and forth
It is obvious that the outer border does not show/hide as expected when clicked quickly. In order to better reproduce the problem, we will re-implement the function and then solve the problem. .
Implement checkbox component
Since this checkbox uses internal business components and is implemented through JSX syntax, the template template syntax is not used here.
Core analysis
The content is relatively simple. To implement a checkbox yourself, the core is nothing more than the following points.
Use
to associate
- In order to achieve the effect of clicking text part directly and clicking
checkbox
, you can usetags, and the association methods are divided into two types
- The
id
ofis consistent with the
for
attribute of< pre>
Directly wrap
<label> Click me <input type="text" /> </label>
- The
Customize checkbox
style
In order to unify the display style, the span element
will be used to replace the original checkbox
, and the Original checkbox
is hidden, such as the checkbox in Ant Design, Element UI.
Supports v-model
two-way binding
In order to facilitate external use, self-encapsulated components need to support the form of v-model two-way data binding, and within the component only the corresponding props and emis need to be Just define the event, as follows:
export default defineComponent({<!-- --> props: {<!-- --> modelValue: {<!-- --> type: Boolean, default: false } }, emits: ["update:modelValue"], ... })
Effect display
The mouse click position is not displayed in the following effect. The actual click position includes:
- checkbox itself displays the selected style, including outer border and fill style
- checkbox text part, hide outer border
- Area outside checkbox, hide outer border
The code is roughly as follows:
// ChcekBox.tsx import {<!-- --> defineComponent, ref } from 'vue' export default defineComponent({<!-- --> name: 'ChcekBox', props: {<!-- --> modelValue: {<!-- --> type: Boolean, default: false } }, emits: ["update:modelValue"], setup(props, {<!-- --> slots, emit }) {<!-- --> const blur = ref(false); const onChange = (e) => {<!-- --> emit('update:modelValue', e.target.checked) } const onFocus = () => {<!-- --> blur.value = false; } const onBlur = () => {<!-- --> blur.value = true; } return () => ( <label class="checkbox-wrapper"> <span class={<!-- -->["checkbox", props.modelValue & amp; & amp; !blur.value & amp; & amp; "checkbox-checked"]}> <input class="checkbox-input" type="checkbox" name="checkbox" checked={<!-- -->props.modelValue} onBlur={<!-- -->onBlur} onFocus={<!-- -->onFocus} onChange={<!-- -->onChange} /> <span class={<!-- -->["checkbox-inner", props.modelValue & amp; & amp; "checkbox-inner-checked"]}></span> </span> <span class="checkbox-label">{<!-- -->slots.default ? slots.default() : ''}</span> </label> ) } }); // ChcekBox.less .checkbox-wrapper {<!-- --> display: flex; align-items: center; cursor: pointer; .abs {<!-- --> position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); height: 16px; width: 16px; } .checkbox {<!-- --> position: relative; margin-right: 5px; height: 16px; width: 16px; padding: 10px; border-radius: 4px; border: 1.5px solid transparent; & amp;-checked{<!-- --> border-color: #1677ff; } & amp;-inner {<!-- --> .abs(); border: 1px solid #1677ff; border-radius: 4px; & amp;-checked {<!-- --> background-color: #1677ff; border-color: #1677ff; } & amp;::after {<!-- --> box-sizing: border-box; position: absolute; top: 50%; inset-inline-start: 21.5%; display: table; width: 6px; height: 9px; border: 2px solid #fff; border-top: 0; border-inline-start: 0; content: " "; transform: rotate(45deg) scale(1) translate(-50%, -50%); transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s; } } & amp;-input {<!-- --> .abs(); opacity: 0; } } }
Analyze/solve outer border display BUG
Let’s review the display effect when quickly click back and forth:
Then looking back at the code implemented above, it is not difficult to find that the onFocus
and onBlur
events on checkbox are wanted to be Control the show/hide of the outer border when triggered.
So now there is a problem with show/hide, which is obviously related to the onFocus
and onBlur
events.
focus and blur events
The focus
event is triggered when the element gets focus. This event cannot be canceled and will not bubble .
The blur
event is triggered when an element loses focus. This event cannot be canceled and will not Bubbling.
Another point that is most easily overlooked is that they must be triggered from another state to current state, for example:
- When it is in the focused state and continues to perform the focus action, the
focus
event will not be triggered. - When it is in the out-of-focus state and continues to perform the out-of-focus action, the
blur
event will not be triggered.
Analyze the problem
First of all, in terms of layout, element and element
both use absolute positioning, and the latter will cover the former.
Event bubbling
So our current click operation actually directly operates on the element, so why can it still be triggered on the element
What about the bound
focus
and blur
events?
This is not difficult, because there is event bubbling, so the click operation can be passed to the underlying element, naturally The corresponding event can be triggered.
focus and blur are not triggered
When performing a quick click, you will find that neither the focus nor the blur events are triggered, as follows:
It is obvious that there is a problem with the display because these two events are not executed.
So the question is why these two events were not executed?
If the last time the blur event is triggered in terms of state changes, then it is understandable that subsequent blur events will not be triggered. After all, the state has not been changed, but focusEvent is not executed, which is not what it should be.
There is no relevant information on this issue yet. Anyone who knows about it can share their insights in the comment area.
Solving problems
Once you know the reason, it is easy to make adjustments. Although focus and blur cannot be triggered all the time, the change event is not affected. as follows:
Therefore, you only need to migrate the logic related to showing/hiding the outer border to onChange, as follows:
- In order to ensure that the
onBlur
event can be executed normally, whenonChange
is triggered we should passe.target.focus()
triggers the outer border display logic in order to change thecheckbox
Focus/Out of Focus status, as mentioned before, only the difference between Current Status and Next Status can trigger the corresponding event.
Since the
onChange
event is not affected, why do we needonBlur
andonFocus
?
This is also a question raised by friends in the comment area. In order to avoid everyone having this question, I will explain it here.
Let’s look back briefly at the requirements:
- Click on the checkbox itself to display the selected styles, including outer border and fill style
- Click outside the checkbox to hide the outer border
Then we know that when the checkbox itself is clicked, the onChange event will always be triggered. From this perspective, there is really no need for onBlur and onFocus.
But it is worth noting that when you need to click the area outside the checkbox to hide the outer border, the onChange event cannot be executed because at this time checkbox > The selected state has not changed, and this operation is very suitable for the triggering time of the onBlur event, so we need the onBlur event.
Because the onBlur event is needed, but because of the problem mentioned earlier that the onFocus and onBlur events are not triggered when quickly clicked, we need to use onChange< /strong> Manually trigger the onFocus event of checkbox. Only in this way can it be triggered when we click on the area outside the checkbox >onBlur event.
import {<!-- --> defineComponent, ref } from 'vue' export default defineComponent({<!-- --> name: 'ChcekBox', props: {<!-- --> modelValue: {<!-- --> type: Boolean, default: false } }, emits: ["update:modelValue"], setup(props, {<!-- --> slots, emit }) {<!-- --> const blur = ref(props.modelValue); const onChange = (e) => {<!-- --> e.target.focus(); emit('update:modelValue', e.target.checked) } const onFocus = () => {<!-- --> blur.value = false; } const onBlur = () => {<!-- --> blur.value = true; } return () => ( <label class="checkbox-wrapper"> <span class={<!-- -->["checkbox", props.modelValue & amp; & amp; !blur.value & amp; & amp; "checkbox-checked"]}> <input class="checkbox-input" type="checkbox" name="checkbox" checked={<!-- -->props.modelValue} onBlur={<!-- -->onBlur} onFocus={<!-- -->onFocus} onChange={<!-- -->onChange} /> <span class={<!-- -->["checkbox-inner", props.modelValue & amp; & amp; "checkbox-inner-checked"]} onClick={<!-- -->()= >console.log('click in checkbox-inner')}></span> </span> <span class="checkbox-label">{<!-- -->slots.default ? slots.default() : ''}</span> </label> ) } })
The final effect is as follows:
Finally
Welcome to follow the public account of the same name “
Panda's Cat
“. Articles will be updated simultaneously, and you can also quickly join the front-end communication group!
To sum up, when you need to use the focus and blur events in your project to achieve related requirements, you should pay special attention, especially in the safari browser or IOS devices etc. There may be cases where the focus and blur events do not take effect.
Hope this article is helpful! ! !