As front-end development, it is inevitable to contact input in work and do some customized development based on input. However, due to the differences of Android ios system, webView selection of host APP (especially ios), and historical legacy of APP, there will be a lot of compatibility problems

Below, I will record the problems encountered in my development process and the solutions, hoping to help you

1. Ios WebView

In ios, different apps may have different built-in WebViews, resulting in inconsistent input behavior. Therefore, we first have a general understanding. Currently, there are two kinds of WebViews in ios system: WK and UI

Ios8 before, has been using UI, but from the beginning of ios8, the new WK type, compared to UI, WK load faster, consume less memory, and support more H5 features, so the major companies will basically upgrade this, but do not exclude some app because of various historical reasons are still using UI, such as us, At present, our H5 page runs in multiple apps, including UI and WK. Naturally, we will make some compatibility judgments during development

Determine the webView type

// There is no good way to determine the type of webView until ios developers tell you
// The following method is based on some new h5 features that are only supported by WK
function getIosWebviewType() {
    if (navigator.platform.substr(0.2) = = ='iP') {
        // iOS (iPhone, iPod or iPad)
        const lte9 = /constructor/i.test(window.HTMLElement);
        const nav = window.navigator; const ua = nav.userAgent;
        const idb = !!window.indexedDB;
        if (ua.indexOf('Safari')! = =- 1 && ua.indexOf('Version')! = =- 1 && !nav.standalone) {
            return 'Safari'
        } else if((! idb && lte9) || !window.statusbar.visible) {
            return 'UI'
        } else if ((window.webkit && window.webkit.messageHandlers) || ! lte9 || idb) {return 'WK'}}return 'unknown'
}
Copy the code

2. An autofocus failure

This property is supported by both the H5 specification and caniuse, but when you test it on a real machine, it is not always what you want

My test results are as follows:

  • ios
    • UIWebview, you can focus, you have a cursor, you can call up the keyboard
    • WKWebview, can focus, has a cursor, but can not call the keyboard
  • The android
    • No problem found at present (but not absolutely)

The reason is that Apple wants it to be triggered by the user, so it’s a user option, not a requirement, so it’s banned in the new version of the OS, but not in the old version of the UI

Fortunately, on both Android and ios, you can focus and call the keyboard by executing input.focus() synchronously in a touch or click event.

If the business scenario fits this scenario, it can be done this way

onClick = (a)= > {
  this.input.focus()
}
Copy the code

But if there is an asynchronous operation in the click event, the same as the autofocus attribute, can only focus, can not call up the keyboard

onClick = (a)= > {
  setTimeout((a)= > {
    this.input.focus()
  }, 1000)
  
  / / or
fetch('/api/get').then((a)= > {
    this.input.focus()
  })
}

Copy the code

down-cycled

If the business scenario does not fit the above situation, but you really want this feature, one solution is to enhance the focus effect after focusing (because the native cursor display is not obvious after all).

  • Set a focused style, either on the input or on other elements of the page, depending on the product characteristics and UE
  • Scroll the page appropriately to the center of the view

May refer to

3. Focus on the problem

3.1 Unable to focus by clicking or out of focus after focusing

Most cases are caused by 300ms problems on the mobile end

One is: the app uses UIWebview but the H5 page doesn’t introduce FastClick

The other is: fastclick has been introduced, but needs to be optimized for fastclick focus

FastClick.prototype.focus = function (targetElement) {
    targetElement.focus();
};
Copy the code

3.2 The cursor cannot focus to the click position

This high probability is also caused by FastClick, see: link

3.3 If you click another Input with a focus input, it will jump

This is most likely the result of FastClick, see the link above

Or so change fastClick source code, in onTouchEnd to add a judgment, whether the need to go native focus logic

FastClick.prototype.onTouchEnd = function (event) {
    // ...
    if (targetTagName === 'label') {
        // ...
    } else if (this.needsFocus(targetElement)) {
      	/ / new
        if (!this.needsFocusInput()) return false

      	// ...
    }

    // ...
};

/ / new
// Use the native input focus logic if there are already focus elements
FastClick.prototype.needsFocusInput = function () {
    const focusInput = document.querySelector('input:focus')
    return! focusInput }Copy the code

3.4 suggest

Most of the above problems are caused by FastClick, but the problem solved by FastClick (300ms) is already solved by most browsers, so confirm that if your app does not use UIWebview, you can remove FastClick directly

Fastclick Github

Note: As of late 2015 most mobile browsers – notably Chrome and Safari – no longer have a 300ms touch delay, so fastclick offers no benefit on newer browsers, and risks introducing bugs into your application. Consider carefully whether you really need to use it.

4. Out-of-focus problem

4.1 Want to stay focused

Sometimes you want the input to remain in focus when you click elsewhere on the page, but the browser default behavior is to defocus the input

Solution: Disable default behavior in click events

function onClick(e) {
	// Your event handler code. e.preventDefault();// On some iPhone models, refocus instead of blocking the default behavior
	input.focus();
}
Copy the code

4.2 Wish to actively lose focus

Some Android models have the following problems

  • In focus, click elsewhere on the page without actively out of focus
  • In some cases, after actively hiding the keyboard, the input will not be out of focus, but will call up the keyboard when the user touches the input elsewhere on the page because it is still in focus

There are two kinds of targeted solutions

The first: monitor user behavior, active out of focus

const autoBlur = (e) = > {
  const target = e.target
  const { tagName, className } = target
  // Click on the non-input field
  if(tagName.toUpperCase() ! = ='INPUT') {
    this.input.blur()
  }
}
document.body.addEventListener('touchstart', autoBlur)

Copy the code

Second: monitor keyboard height changes, active out of focus

const onKeyboardChange = (resize) = > {
  // Sometimes, for example, the number becomes text, or the system automatically decorates the keyboard. The keyboard is not hidden, but resize is triggered
  // On most models tested, all keyboards must be higher than 120 height, so add a limit
  if (Math.abs(resize) < 120) return

  const show = resize > 0
  if(! show) {this.input.blur()
  }
}

function getClientHeight() {
    return document.documentElement.clientHeight || document.body.clientHeight;
}

// Record the original height
let originHeight = getClientHeight()

// Listen for keyboard changes
window.addEventListener('resize', () = > {const resizeHeight = getClientHeight()

  const resize = originHeight - resizeHeight
  onKeyboardChange(resize);
  originHeight = resizeHeight;
}, false)
Copy the code

5. After focusing, scroll into view

In most cases, the system will scroll the input into the view for you, but in a few cases, you’ll need to do it yourself

  • One option is to call the scrollIntoViewIfNeeded API directly

  • The other option is to calculate the difference between the document height before and after focus, and then increase the body height accordingly and set scrollTop, which should appear under UIWebview

// Normal processing
input.addEventListener('focus', () => {
  setTimeout((a)= > {
    this.input.scrollIntoViewIfNeeded();
  }, 300)})Copy the code
// UIWebview
function getClientHeight() {
    return document.documentElement.clientHeight || document.body.clientHeight;
}
const bodyHeight = getClientHeight()
const bodyOverflow = getComputedStyle(document.body).overflow

input.addEventListener('focus', () = > {document.body.style.overflow = 'auto'
  setTimeout((a)= > {
    // alert(getClientHeight())
    let height = bodyHeight - getClientHeight()
    if (height < 0) height = height * 2 -
    document.body.style.height = `${bodyHeight + height}px`;
    document.body.scrollTop = height;
  }, 300)})// If the height is set, set it back in blur
input.addEventListener('blur', () = > {document.body.style.height = `${bodyHeight}px`;
  document.body.style.overflow = bodyOverflow
})


Copy the code

SetTimeout is added because there will be an animation when the keyboard is aroused. We need to scroll the page after the animation is over, otherwise the height calculated is not correct

In most cases, the keyboard animation time is less than 300

6. Force the cursor to the end

input.addEventListener('touchend', e => {
  const length = e.target.value.length
  e.target.setSelectionRange(length, length);
  e.preventDefault()
  e.target.focus()
})
Copy the code

7. Other questions

7.1 Cursor Hiding

In some scenarios, you need to customize the input box and cursor

Opacity: 0; Color: transparent Hide the native cursor

Ios can’t hide it, but moves the input box out of view by making it wide enough and moving it left:

input {
  width: 1000px;
  margin-left: -200px;
}
Copy the code

7.2 Copy and Paste

Both Android and ios support long press copy and paste, but ios requires that the cursor must be in the view. After you move the input to the left, as above, the paste button is not in the view and cannot be pasted

7.3 The SMS Verification Code (or other numbers) is displayed on the system keyboard

The new version of ios (12+, not sure) will display the message directly on the keyboard after receiving the message, the user can input the message into the input, but the old version does not support, users need to take the initiative to copy the message, and then paste the input, if the input is customized, you need to pay attention to the above problems

Some Android devices (such as the Mi 6+) can directly click on the notification bar to copy the message, which will also appear on the keyboard, while other models require users to hold down and paste

8. Conclusion

The above are basically the problems I encountered in the development process. With the iterative upgrade of the system, many problems will be officially solved, but we cannot decide whether the APP will be upgraded or not, and whether the users will upgrade

So, if you have any of these problems, I hope to enlighten you and help you