Mobile Safari: Phương thức Javascript focus () trên trường nhập liệu chỉ hoạt động với nhấp chuột?


75

Tôi có một trường đầu vào đơn giản như thế này.

<div class="search">
   <input type="text" value="y u no work"/>
</div>​

Và tôi đang cố gắng thực hiện focus()nó bên trong một hàm. Vì vậy, bên trong một hàm ngẫu nhiên (không quan trọng nó là hàm gì), tôi có dòng này…

$('.search').find('input').focus();

Điều này hoạt động tốt trên mọi Máy tính để bàn.

Tuy nhiên, nó không hoạt động trên iPhone của tôi. Trường không được lấy nét và bàn phím không hiển thị trên iPhone của tôi.

Với mục đích thử nghiệm và để cho các bạn thấy vấn đề, tôi đã làm một mẫu nhanh:

$('#some-test-element').click(function() {
  $('.search').find('input').focus(); // works well on my iPhone - Keyboard slides in
});

setTimeout(function() {
  //alert('test'); //works
  $('.search').find('input').focus(); // doesn't work on my iPhone - works on Desktop
}, 5000);​

Bất kỳ ý tưởng nào tại sao focus()nó không hoạt động với chức năng thời gian chờ trên iPhone của tôi.

Để xem ví dụ trực tiếp, hãy kiểm tra trò chơi này trên iPhone của bạn. http://jsfiddle.net/Hc4sT/

Cập nhật:

Tôi đã tạo ra trường hợp giống hệt như tôi đang gặp phải trong dự án hiện tại của mình.

Tôi có một hộp chọn - khi được "thay đổi" - đặt tiêu điểm vào trường nhập và trượt trong kexboard trên iphone hoặc các thiết bị di động khác. Tôi phát hiện ra rằng tiêu điểm () được đặt chính xác nhưng bàn phím không hiển thị. Tôi cần bàn phím để hiển thị.


có thể nó được lấy nét , nhưng bàn phím không hiển thị (đó là trường hợp trên Nokia X6 của tôi).
11684

1
làm việc cho tôi. jsfiddle bạn đã dán chỉ cần tập trung vào hộp và mở bàn phím trên iPhone của tôi. bạn đang sử dụng iOS nào? Tôi đã kiểm tra với 5.1.
Krizz,

Ok, bạn đúng như vẻ ngoài của nó. Tôi đang sử dụng iOS 5.1.1. Tiêu điểm () dường như hoạt động như tôi biết được đặt input:focus { background:green; }thông qua css trên đầu vào. Tuy nhiên, bàn phím không trượt đối với tôi. Xem trường hợp công việc này tôi hiện đang làm việc. cl.ly/1d210x1W3Y3W Kiểm tra điều này trên iPhone của bạn. Bạn có cơ hội trượt trên bàn phím khi chọn "Tìm kiếm" trong hộp chọn không?
matt,

1
Tôi đang thử rất nhiều thứ. Tôi đã thử triggerHandler (), focusin (), trigger ("tiêu điểm"). Tôi thậm chí đã cố gắng làm mờ nó trước và sau đó thêm lại tiêu điểm. Tôi nghĩ rằng nó có thể là một lỗi trong webkit. Bạn có thể gặp may với cái này ... Nhưng tôi sẽ cố gắng một vài điều nữa ...
Alex

1
Tôi đang bỏ cuộc. Tôi đã thử mọi thứ. Đó không chỉ là điều bạn có thể làm trong trình duyệt Web Safari của iOS. Hy vọng rằng Apple thực hiện một thay đổi để cho phép điều này vì tôi chắc chắn không coi đây là một "tính năng"! haha Tôi không biết tại sao bạn có thể dễ dàng làm mờ () trường nhưng không thể lấy nét cho nó. Không có ý nghĩa đối với tôi.
Alex,

Câu trả lời:


77

Thực ra, các bạn, có một cách. Tôi đã rất vất vả để tìm ra điều này cho [LIÊN KẾT BỊ XÓA] (hãy thử nó trên iPhone hoặc iPad).

Về cơ bản, Safari trên các thiết bị màn hình cảm ứng khá phức tạp khi nói đến focus()hộp văn bản. Ngay cả một số trình duyệt máy tính để bàn cũng hoạt động tốt hơn nếu bạn làm vậy click().focus(). Tuy nhiên, các nhà thiết kế của Safari trên các thiết bị màn hình cảm ứng nhận ra rằng điều này gây khó chịu cho người dùng khi bàn phím liên tục xuất hiện, vì vậy họ chỉ xuất hiện tiêu điểm trong các điều kiện sau:

1) Người dùng đã nhấp vào một nơi nào đó và focus()được gọi trong khi thực hiện sự kiện nhấp chuột. Nếu bạn đang thực hiện lệnh gọi AJAX, thì bạn phải thực hiện đồng bộ, chẳng hạn như với $.ajax({async:false})tùy chọn không dùng nữa (nhưng vẫn khả dụng) trong jQuery.

2) Hơn nữa - và cái này khiến tôi bận rộn trong một thời gian - focus()dường như vẫn không hoạt động nếu một số hộp văn bản khác được tập trung vào thời điểm đó. Tôi đã có nút "Bắt đầu" làm AJAX, vì vậy tôi đã thử làm mờ hộp văn bản khi có touchstartnút Bắt đầu, nhưng điều đó chỉ khiến bàn phím biến mất và di chuyển chế độ xem trước khi tôi có cơ hội hoàn thành việc nhấp vào nút Bắt đầu . Cuối cùng, tôi đã thử làm mờ hộp văn bản khi có touchendnút Bắt đầu và điều này hoạt động như một sự quyến rũ!

Khi bạn đặt số 1 và số 2 với nhau, bạn sẽ có được một kết quả kỳ diệu giúp đặt biểu mẫu đăng nhập của bạn khác biệt với tất cả các biểu mẫu đăng nhập web tồi tàn, bằng cách đặt trọng tâm vào các trường mật khẩu của bạn và làm cho chúng cảm thấy tự nhiên hơn. Thưởng thức! :)


2
Điều này nghe có vẻ rất thông minh, nhưng tôi đang gặp khó khăn khi "đặt # 1 và # 2 lại với nhau". Trong ứng dụng của tôi, sử dụng jQueryMobile, khi người dùng nhấp vào một mục danh sách trong trang A, một trang B mới sẽ mở ra, chỉ có một đầu vào hiển thị. Tôi muốn bàn phím tự động mở cho đầu vào đó. Có phải bạn muốn nói rằng tôi phải đặt lệnh gọi .focus () ở đâu đó trong trình xử lý nhấp chuột trên trang A?
Wytze

1
Cảm ơn bạn đã tiết kiệm thời gian của tôi. Đó là rất rõ ràng để tìm thấy.
vogdb

4
Tôi đã có thể lấy nó! Thay vì làm mờ và tập trung phần tử, tôi chỉ cần thêm event.preventDefault()vào touchstart. Lưu ý rằng ngăn chặn này ng-nhấp chuột từ thực hiện, vì vậy tôi đã phải thêm logic văn bản rõ ràng của tôi bên trong xử lý sự kiện và$scope.$apply()
ErikAGriffin

2
Tôi thấy rằng chỉ chạy input.focus()từ trình xử lý nhấp chuột của một nút, đã hoạt động. Safari trên iPhone 5 và iPad. Nếu tôi có focus()trong một setTimeout, điều đó không hoạt động. Vì vậy, có lẽ đó là những gì "đồng bộ" có nghĩa là, @Michael.
Dan Dascalescu,

1
Cảm ơn bạn đã đăng một giải pháp thực tế. Làm mờ phần tử trước đó trên chạm + đặt tiêu điểm vào sự kiện nhấp chuột vẫn hoạt động trong iOS10.
Kirill E.

18

Một triển khai javascript gốc của câu trả lời của WunderBart.

function onClick() {

  // create invisible dummy input to receive the focus first
  const fakeInput = document.createElement('input')
  fakeInput.setAttribute('type', 'text')
  fakeInput.style.position = 'absolute'
  fakeInput.style.opacity = 0
  fakeInput.style.height = 0
  fakeInput.style.fontSize = '16px' // disable auto zoom

  // you may need to append to another element depending on the browser's auto 
  // zoom/scroll behavior
  document.body.prepend(fakeInput)

  // focus so that subsequent async focus will work
  fakeInput.focus()

  setTimeout(() => {

    // now we can focus on the target input
    targetInput.focus()

    // cleanup
    fakeInput.remove()
    
  }, 1000)

}

Các tài liệu tham khảo khác: Tắt Tự động phóng to thẻ "Văn bản" Nhập - Safari trên iPhone


1
Điều này đã làm việc cho tôi. Nếu bạn muốn ngăn việc hiển thị bàn phím trên tiêu điểm fakeInput, hãy thêm readonly = "true" vào đó.
Branislav Kuliha

Chỉ có giải pháp hoạt động. requestAnimationFrame là đủ cho tôi và loại bỏ sự chậm trễ.
Thomas

Câu trả lời này sẽ được chia sẻ trên các vấn đề tương tự khác liên quan đến việc tập trung setTimeout + trên trình duyệt Safari. Đó là một thứ thực sự hoạt động!
gojun

Cảm ơn bạn! Đây là giải pháp duy nhất làm việc cho tôi.
Offek

5

Tôi phải đối mặt với vấn đề tương tự gần đây. Tôi đã tìm thấy một giải pháp dường như hoạt động cho tất cả các thiết bị. Bạn không thể làm tiêu điểm không đồng bộ theo lập trình nhưng bạn có thể chuyển tiêu điểm sang đầu vào mục tiêu của mình khi một số đầu vào khác đã được lấy nét. Vì vậy, những gì bạn cần làm là tạo, ẩn, thêm vào DOM & tập trung đầu vào giả vào sự kiện kích hoạt và khi hành động không đồng bộ hoàn tất, chỉ cần gọi lại tiêu điểm trên đầu vào đích. Đây là một đoạn mã ví dụ - chạy đoạn mã đó trên điện thoại di động của bạn.

biên tập:

Đây là một trò chơi với cùng một mã . Rõ ràng là bạn không thể chạy các đoạn mã đính kèm trên điện thoại di động (hoặc tôi đang làm sai điều gì đó).

var $triggerCheckbox = $("#trigger-checkbox");
var $targetInput = $("#target-input");

// Create fake & invisible input
var $fakeInput = $("<input type='text' />")
  .css({
    position: "absolute",
    width: $targetInput.outerWidth(), // zoom properly (iOS)
    height: 0, // hide cursor (font-size: 0 will zoom to quarks level) (iOS)
    opacity: 0, // make input transparent :]
  });

var delay = 2000; // That's crazy long, but good as an example

$triggerCheckbox.on("change", function(event) {
  // Disable input when unchecking trigger checkbox (presentational purpose)
  if (!event.target.checked) {
    return $targetInput
      .attr("disabled", true)
      .attr("placeholder", "I'm disabled");
  }

  // Prepend to target input container and focus fake input
  $fakeInput.prependTo("#container").focus();

  // Update placeholder (presentational purpose)
  $targetInput.attr("placeholder", "Wait for it...");

  // setTimeout, fetch or any async action will work
  setTimeout(function() {

    // Shift focus to target input
    $targetInput
      .attr("disabled", false)
      .attr("placeholder", "I'm alive!")
      .focus();

    // Remove fake input - no need to keep it in DOM
    $fakeInput.remove();
  }, delay);
});
label {
  display: block;
  margin-top: 20px;
}

input {
  box-sizing: border-box;
  font-size: inherit;
}

#container {
  position: relative;
}

#target-input {
  width: 250px;
  padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
  <input type="text" id="target-input" placeholder="I'm disabled" />

  <label>
    <input type="checkbox" id="trigger-checkbox" />
    focus with setTimetout
   </label>
</div>


Đây là giải pháp tốt nhất mà tôi tìm thấy cho đến nay.
anwerso,

Bạn có thể đặt fontSize: '16px'để tắt tự động thu phóng. Ngoài ra, hãy xem câu trả lời của tôi bên dưới để triển khai js gốc.
Raine Revere

3

Tôi có một biểu mẫu tìm kiếm có biểu tượng xóa văn bản khi nhấp vào. Tuy nhiên, vấn đề (trên thiết bị di động và máy tính bảng) là bàn phím sẽ thu gọn / ẩn, vì clicksự kiện bị xóa focusđã bị xóa khỏi input.

đầu vào tìm kiếm văn bản với biểu tượng đóng

Mục tiêu : sau khi xóa biểu mẫu tìm kiếm (nhấp / nhấn vào biểu tượng x), giữ cho bàn phím hiển thị !

Để thực hiện điều này, hãy đăng ký stopPropagation()vào sự kiện như sau:

function clear ($event) {
    $event.preventDefault();
    $event.stopPropagation();
    self.query = '';
    $timeout(function () {
        document.getElementById('sidebar-search').focus();
    }, 1);
}

Và biểu mẫu HTML:

<form ng-controller="SearchController as search"
    ng-submit="search.submit($event)">
        <input type="search" id="sidebar-search" 
            ng-model="search.query">
                <span class="glyphicon glyphicon-remove-circle"
                    ng-click="search.clear($event)">
                </span>
</form>

3

Giải pháp này hoạt động tốt, tôi đã thử nghiệm trên điện thoại của mình:

document.body.ontouchend = function() { document.querySelector('[name="name"]').focus(); };

thưởng thức


ALMOST này hoạt động. Nhưng quy mô doesnt hai datefields, và loại làm cho trang một chút trục trặc
Shayne

Cảm ơn bạn! Đã thử tất cả các loại công cụ và điều này cuối cùng đã làm nó cho tôi biết nơi vì một lý do document.getElementById không
daamsie

2

Tôi đã quản lý để làm cho nó hoạt động với mã sau:

event.preventDefault();
timeout(function () {
    $inputToFocus.focus();
}, 500);

Tôi đang sử dụng AngularJS vì vậy tôi đã tạo một chỉ thị để giải quyết vấn đề của tôi:

Chỉ thị:

angular.module('directivesModule').directive('focusOnClear', [
    '$timeout',
    function (timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var id = attrs.focusOnClear;
                var $inputSearchElement = $(element).parent().find('#' + id);
                element.on('click', function (event) {
                    event.preventDefault();
                    timeout(function () {
                        $inputSearchElement.focus();
                    }, 500);
                });
            }
        };
    }
]);

Cách sử dụng chỉ thị:

<div>
    <input type="search" id="search">
    <i class="icon-clear" ng-click="clearSearchTerm()" focus-on-clear="search"></i>
</div>

Có vẻ như bạn đang sử dụng jQuery, vì vậy tôi không biết liệu chỉ thị có giúp được gì không.


2
Điều này được biết là không hoạt động trên ios safari. Safari đặc biệt phân biệt giữa các sự kiện được tạo bởi sự tương tác của người dùng và được tạo hoàn toàn từ chính js và sẽ không cung cấp các sự kiện tập trung / chọn lọc theo cách này.
Ben Wheeler

Điều đó không đúng và tôi đang sử dụng nó trên các ứng dụng của mình với Cordova / Phonegap ... Và tại sao lại bỏ phiếu? Câu trả lời của tôi khác với những câu khác như thế nào? Ngoại trừ việc tôi đã tạo một Chỉ thị Angular mà bạn có thể sử dụng.
martinmose

thường thì trên Angular chỉ cần thời gian chờ là đủ, bạn không cần phải đặt giá trị thời gian chờ. Nó làm cho nó đợi chu kỳ thông báo và do đó chạy vào thời điểm khi các sự kiện khác đang cản trở tiêu điểm được thực hiện.
Maarten

Xin chào @Maarten, cảm ơn bạn đã bình luận, ý bạn là 500 tôi đã đặt vào thời gian chờ? :)
martinmose

Được rồi tôi sẽ kiểm tra điều đó. Cảm ơn :).
martinmose

1

CẬP NHẬT

Tôi cũng đã thử điều này, nhưng vô ích:

$(document).ready(function() {
$('body :not(.wr-dropdown)').bind("click", function(e) {
    $('.test').focus();
})
$('.wr-dropdown').on('change', function(e) {
    if ($(".wr-dropdow option[value='/search']")) {
        setTimeout(function(e) {
            $('body :not(.wr-dropdown)').trigger("click");
        },3000)         
    } 
}); 

});

Tôi bối rối không hiểu tại sao bạn nói điều này không hoạt động vì JSFiddle của bạn đang hoạt động tốt, nhưng dù sao đây cũng là gợi ý của tôi ...

Hãy thử dòng mã này trong hàm SetTimeOut trên sự kiện nhấp chuột của bạn:

document.myInput.focus();

myInput tương quan với thuộc tính tên của thẻ đầu vào.

<input name="myInput">

Và sử dụng mã này để làm mờ trường:

document.activeElement.blur();

Cảm ơn bạn, hãy xem cập nhật của tôi trong câu hỏi của tôi. Tôi dường như cũng không thể làm cho nó hoạt động với đề xuất của bạn.
matt,


-3

Vui lòng thử sử dụng sự kiện on-tap thay vì ng-click. Tôi đã có vấn đề này. Tôi đã giải quyết vấn đề này bằng cách đặt nút hộp tìm kiếm rõ ràng bên trong nhãn biểu mẫu tìm kiếm và thay thế việc nhấp vào nút xóa bằng cách nhấn vào. Nó hoạt động tốt bây giờ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.