preface

The component research input should have been finished over the weekend, but it was no accident. After unloading Hearthstone with roommates and refusing to waste life, don’t want to throw into the arms of gold shovel shovel, play a weekend yodeling people, curse sb will play this feet again…

This paper, as an additional part of the Input component research, will sort out the problem that the focus position of Input in focus jumps back and forth.

start

Whose kid is Focus

Previously, it was thought that the input focus was triggered by the click event.

It wasn’t until I touched the input component that I realized that things were not so simple. The programmer seemed to have discovered something new. First, he wrote an HTML binding to the input to listen for events and attached the printed results.

<body>
<div>
    <input type="text" value="11" id="ipt">
</div>
<script>
    ipt.onmouseup = function (e) {
        console.log('up');
    }

    ipt.onmousedown = function (e) {
        console.log('down');
    }

    ipt.onfocus = function () {
        console.log('focus');
    }

    ipt.onclick = function () {
        console.log('click');
    }
</script>
</body>
Copy the code

As you can see from the console, events are triggered in the order mousedown-focus-mouseup-click.

It’s enough to prove that the baby is not his. I made him like a father. From the results, the Focus event can only be triggered by mousedown.

Add a block default event to mousedown for paternity test. Click the button to see the result, and find that focus does not trigger, proving the previous inference is correct.

ipt.onmousedown = function (e) {
    e.preventDefault()
    console.log('down');
}
Copy the code

The input focus position is abnormal.

This is actually very difficult because I did a lot of research and didn’t understand the specific mechanism of it, so I can only give examples to illustrate it.

1. Initial call to INPUT with default valuesfocus

<body>
<div>
    <input type="text" value="11111" id="ipt">
</div>
<div>
    <button id="btn">test</button>
</div>
<script>

    btn.onclick = function() {
        ipt.focus();
    }
</script>
</body>
Copy the code

Click the Test button, and the cursor position will appear in the first grid.

Set value to null, focus, and put the value back (setAttribute does not work).

btn.onclick = function() {
    ipt.value = ' ';
    ipt.focus();
    ipt.value = '11';
}
Copy the code

If you use the autoFocus attribute, delayed assignment can be solved.

To change thetypeAfter manualfocusInput box

p.onclick = function (e) {
    const t = ipt.getAttribute('type');
    ipt.type = t === 'password' ? 'text' : 'password';
    ipt.focus();
    ipt.setAttribute('type', t === 'password' ? 'text' : 'password')}Copy the code

In the native version, simply switch focus() and setAttribute and the cursor will normally appear at the end.

In React, however, state is deferred and focus is usually run first, so one solution is to call focus in the setState callback function.

The other is to block the default event of p’s mouseup.

p.onmouseup = function (e) {
    console.log('up');
    e.preventDefault();
}
Copy the code

Input in the Focus state triggers a change in type by clicking on the event, or setAttribute(‘value’) changes (excluding ipt.value = ***’). The input cursor moves forward to the first place, and the solution is to block mouseup’s default event. What is the principle, I do not know = =, hope to understand the eldest brothers can tell me.

Fix focus issues in React

In this case, a new password component is added to the Input component, and the type change is controlled by clicking the little eye to show and hide the password. Since icon is not input, normal clicking will cause out-of-focus. There are two ways to solve this problem.

1. Refocus manually — usesetState, oruseEffect

changeType(e) {
    this.setState({
        type: (this.state.type === 'text' ? 'password' : 'text')},() = > {
        // Focus the cursor at the end
        this.inputRef.current.focus();
    });
    // focus the cursor first
    // this.inputRef.current.focus();
}
Copy the code

Here’s an example of how to write class. If you use hook to write useEffect, you need to add a marker to judge when the update will run, otherwise it will automatically focus when mounting, hook tutorial on the official website has written how to operate.

However, manual focus can be a problem, because the component can pass custom onBlur and onFocus. In this case, the two functions will be re-run, depending on the specific use of the reasonable.

usee.preventDefault()Blocking default events

This is also the approach used by various component libraries. Prevent out-of-focus and focus jumping problems with e.preventDefault() by binding mouseup and mousedown events to the icon. Keep the focus always at the input’s current position.

<Icon
  className="zent-input-icon"
  type={icon}
  onMouseUp={preventDefault}
  onMouseDown={preventDefault}
  onClick={onIconClick}
/>
Copy the code

end

The cause was a focus shift problem when adding the Password component. Then, after using useEffect, I looked at the code written by various component library leaders and found a way to solve the problem through Mouseup and MouseDown, so I did a little research to supplement the foundation.

The input component research will be done as soon as possible this week. It’s still a day to read the code and make progress