Soru Bir tartışmalı div hala dışarı tıklayarak tıklayarak odaklanmak?


Bazı nedenlerden dolayı, metin girişi için normal metin girişi yerine contenteditable div kullanmam gerekiyor. (bazı javascript kütüphanesi için) kullanarak contenteditable div'i ayarladığım zamana kadar iyi çalışıyor. display: inline-blockdiv'un dışını tıklasam bile div'a odaklanır!

Kullanıcıya sadece ekranın sağ tarafına değil ama etrafına tıklama yaptığında div'a odaklanmaya ihtiyacım var. Şu anda, kullanıcı başka bir yere tıkladığında ve ardından div ile aynı satırdaki konuma tıkladığında, ona odaklanıldığını buldum.

Sorunu göstermek için basit bir örnek:

HTML:

<div class="outside">
    <div class="text-input" contenteditable="true">
        Input 1
    </div>
    <div class="text-input" contenteditable="true">
        Input 2
    </div>
    <div class="unrelated">This is some unrelated content<br>
      This is some more unrelated content
      This is just some space to shows that clicking here doesn't mess with the contenteditable div
      but clicking the side mess with it.
    </div>
</div>

CSS:

div.outside {
  margin: 30px;
}
div.text-input {
  display:inline-block;
  background-color: black;
  color: white;
  width: 300px;
}

Sorunu görüntülemek için JSFiddle

Tarayıcının yalnızca aynı satıra tıklama yapmak yerine tıklatıldığında div'a odaklanmasını sağlamak için bir yol var mı (CSS veya javascript her ikisi de kabul edilebilir)?

Not; Benzer bir problem olduğunu fark ettim (ilgili diğer gönderiye bağlantı), ama durum biraz farklı ve sağlanan çözüm benim için çalışmıyor.


28
2017-12-18 10:59


Menşei


Sorunun ne olduğundan emin değil, ama bu işe yaradı ...jsfiddle.net/AXM4Y/8 - yjs
um ... işe yarıyor ama neden bilmiyorum. - cytsunny
@yjs bunu cevaplamak ister misin - Quill
Eğer bir cevap vermek istiyorsanız, lütfen neden işe yaradığını da anlayın. - cytsunny
Bence tıklanan divun odaklanması ... jsfiddle.net/omerblink/AXM4Y/9 - Omer


Cevaplar:


açıklama (eğer umursamıyorsanız Geçici Çözümler altında)

Bir tıkladığınızda düzenlenebilir eleman, tarayıcı bir imleci yerleştirir (a.k.a. Ekleme noktası) en yakın metin düğümü Tıklanan öğe içinde, tıklama ile aynı satırda. Metin düğümü, doğrudan, tıklanan elemanın içinde veya çocuk elemanlarından birinde olabilir. Bunu aşağıdaki kod snippet'ini çalıştırarak ve büyük mavi kutuda tıklayarak doğrulayabilirsiniz.

.container {width: auto; padding: 20px; background: cornflowerblue;}
.container * {margin: 4px; padding: 4px;}
div {width: 50%; background: gold;}
span {background: orange;}
span > span {background: gold;}
span > span > span {background: yellow;}
<div class="container" contenteditable>
  text in an editable element
  <div>
    text in a nested div
  </div>
  <span><span><span>text in a deeply nested span</span></span></span></div>
Notice that you can get an insertion point by clicking above the first line or below the last. This is because the "hitbox" of these lines extends to the top and bottom of the container, respectively. Some of the other answers don't account for this!

Mavi kutu bir <div> ile contenteditable öznitelik ve iç turuncu / sarı kutular yuvalanmış alt öğelerdir. Çocuk öğelerinden birinin yakınında (ancak içeride değil) tıklarsanız, dışarıdan tıklatmanıza rağmen imleç içinde biter. Bu bir hata değil. Tıkladığınız öğe (mavi kutu) düzenlenebilir olduğundan ve alt öğe içeriğinin bir parçası olduğundan, en yakın metin düğümünün olması durumunda imleci alt öğeye yerleştirmek mantıklıdır.

Sorun, Webkit tarayıcılarının (Chrome, Safari, Opera) bu davranışı sergilemesidir. contenteditable Ebeveyn yerine çocuğun üzerinde ayarlanır. Tarayıcı, gerçekte tıkladığınız öğe düzenlenebilir olmadığından, bu durumda en yakın metin düğümünü aramayı bile rahatsız etmemelidir. Ancak Webkit yapar ve bu metin düğümü düzenlenebilir bir çocukta olursa, yanıp sönen bir imleç alırsınız. Bunu bir hata olarak düşünürdüm; Webkit tarayıcıları bunu yapıyor:

on click:
  find nearest text node within clicked element;
  if text node is editable:
    add insertion point;

... bunu yapmaları gerektiğinde:

on click:
  if clicked element is editable:
    find nearest text node within clicked element;
    add insertion point;

Blok elemanları (div gibi) hatadan etkilenmez, bu da beni düşünmeme neden olur @GOTO 0'un cevabı metin seçimini yapmakta doğrudur - en azından ekleme noktası yerleşimini kontrol eden aynı mantık tarafından yönetiliyormuş gibi görünüyor. Satır içi bir öğenin dışındaki çoklu tıklatma, içindeki metni vurgular, ancak blok öğeleri için böyle değildir. Bir bloğun dışına tıkladığınızda, ekleme noktasını almamanız muhtemelen bir tesadüf değildir. Aşağıdaki ilk geçici çözüm bu istisnayı kullanır.


Geçici çözüm 1 (iç içe div)

Bloklar hatadan etkilenmediğinden, en iyi çözümün bir satır içi satırın içine yerleştirilmesi ve bunun yerine düzenlenebilir olmasını sağlamak olduğunu düşünüyorum. Satır içi bloklar zaten dahili olarak bloklar gibi davranır, dolayısıyla divun davranışları üzerinde hiçbir etkisi olmamalıdır.

div.outside {
  margin: 30px;
}
div.text-input {
  display:inline-block;
  background-color: black;
  color: white;
  width: 300px;
}
<div class="outside">
    <div class="text-input">
      <div contenteditable>
        Input 1
      </div>
    </div>
    <div class="text-input">
      <div contenteditable>
        Input 2
      </div>
    </div>
    <div class="unrelated">This is some unrelated content<br>
      This is some more unrelated content
      This is just some space to shows that clicking here doesn't mess with the contenteditable div
      but clicking the side mess with it.
    </div>
</div>


Geçici çözüm 2 (görünmez karakterler)

Eğer koymanız gerekiyorsa contenteditable satır içi bloklar üzerindeki öznitelik, bu çözüm buna izin verecektir. Görünmez karakterlerle satır içi blokları çevreleyerek çalışır (özellikle, sıfır genişlikli alanlar) onları harici tıklamalardan korur. (GOTO 0'ın cevabı aynı prensibi kullanır, ancak hala kontrol ettiğim bazı problemler vardı).

div.outside {
  margin: 30px;
}
div.text-input {
  display:inline-block;
  background-color: black;
  color: white;
  width: 300px;
  white-space: normal;
}
.input-container {white-space: nowrap;}
<div class="outside">
  <span class="input-container">&#8203;<div class="text-input" contenteditable>
    Input 1
  </div>&#8203;</span>
  <span class="input-container">&#8203;<div class="text-input" contenteditable>
    Input 2
  </div>&#8203;</span>
  <div class="unrelated">This is some unrelated content<br>
      This is some more unrelated content
      This is just some space to shows that clicking here doesn't mess with the contenteditable div
      but clicking the side mess with it.
  </div>
</div>


Geçici çözüm 3 (javascript)

İşaretlemenizi kesinlikle değiştiremezseniz, bu JavaScript tabanlı çözüm son çare olarak çalışabilir. bu cevap). Setleri contentEditable satır içi bloklar tıklandığında ve odağı kaybettiğinde yanlış olduğunda true.

(function() {
  var inputs = document.querySelectorAll('.text-input');
  for(var i = inputs.length; i--;) {
    inputs[i].addEventListener('click', function(e) {
      e.target.contentEditable = true;
      e.target.focus();
    });
    inputs[i].addEventListener('blur', function(e) {
      e.target.contentEditable = false;
    });
  }
})();
div.outside {
  margin: 30px;
}
div.text-input {
  display:inline-block;
  background-color: black;
  color: white;
  width: 300px;
}
<div class="outside">
    <div class="text-input">
      Input 1
    </div>
    <div class="text-input">
      Input 2
    </div>
    <div class="unrelated">This is some unrelated content<br>
      This is some more unrelated content
      This is just some space to shows that clicking here doesn't mess with the contenteditable div
      but clicking the side mess with it.
    </div>
</div>


19
2017-12-23 23:19



Mükemmel cevap. Bu problemi çözer. Sadece açıklama hakkında merak ediyorum: "ekleme noktası konumu" nedir? - cytsunny
@ user1273587 "ekleme noktası konumu", tarayıcının ekleyeceği doğru konum olarak belirlediği bir web sayfasındaki belirli yerdir Ekleme noktası (örn. metin girmenizi sağlayan yanıp sönen imleç). Bu konum, doğrudan tıkladığınız öğenin içinde veya alt öğelerinden biri içinde olacaktır. Tarayıcılar, tıklattığınız öğe düzenlenebilir olmadıkça, maalesef Webkit her zaman bu kuralı takip etmediği sürece bu konuma bir ekleme noktası yerleştirmemeli (ve muhtemelen hesaplamamalıdır). - DoctorDestructo
Sıfır genişlikte boşluklar hile yaptı! Bağlanmak için fazladan bir JS yok ve hatta Draft.js'yi satır içi olarak geçersiz kılmaya çalıştıklarında bile çalışırlar (ki bunu ayarlayarak yapabilirsiniz) *:first-child {display:inline;}). Ne can sıkıcı bir böcek! - btown


Bu davranışı yalnızca Chrome ve Safari’de yeniden yapılandırarak bunun bir Web Seti ile ilgili sorun olabileceğini ileri sürdüm.

Kodu incelemeksizin neler olduğunu söylemek zor ama en azından sorunun, tarayıcıda metin seçimini tetikleyen bazı hatalı mekanizmalarda bulunduğundan şüphelenebiliriz. Analoji için, eğer divSon karakter, satırın sonunda başlayan bir metin seçimini tetikledikten sonra, aynı metin satırını tıklatarak, tartışmasız değildi.

Çözüm, tartışılabilir içeriği paketlemek divbir konteyner elemanına dönüşür ve kabı -webkit-user-select: none onu affedilemez hale getirmek için.

Alex Char bir yorumda belirttiği gibi, bu, içeriğin içindeki metnin başlangıcında bir seçimi tetiklemek için bir fare tıklatmasını engellemez, çünkü ilk içerik arasında statik bir metin yoktur. div ve etrafındaki (seçilebilir) ata kabı. Muhtemelen daha zarif çözümler vardır, ancak bu problemin üstesinden gelmenin bir yolu, ilk tartışılmadan hemen önce sıfır genişlikte bir metnin görünmez, kesintili bir kapsamı eklemektir. div istenmeyen metin seçimini yakalamak için.

  • Neden boş değil?: Çünkü metin seçiminde boş öğeler göz ardı edilir.
  • Neden sıfır genişliği?: Çünkü onu görmek istemiyoruz ...
  • Neden görünmez?: Çünkü içeriğin panoya kopyalanmasını istemiyoruz Ctrl + A, Ctrl + C.

div.outside {
  margin: 30px;
}
div.text-input {
  display:inline-block;
  background-color: black;
  color: white;
  width: 300px;
}
div.text-input-container {
  -webkit-user-select: none;
}
.invisible {
  visibility: hidden;
}
<div class="outside">
    <div class="text-input-container">
        <span class="invisible">&#8203;</span><div class="text-input" contenteditable="true">
            Input 1
        </div>
        <div class="text-input" contenteditable="true">
            Input 2
        </div>
    </div>
    <div class="unrelated">This is some unrelated content<br>
      This is some more unrelated content
      This is just some space to shows that clicking here doesn't mess with the contenteditable div
      but clicking the side mess with it.
    </div>
</div>

Normal şartlarda bile, bitişik satır içi blok elemanlarının, bir blok elemanın yanında değil, ayrı bir kapta tutulması genellikle iyi bir fikirdir. divKardeş elemanların sırasının değişmesi durumunda beklenmedik yerleşim etkilerini önlemek için).


9
2017-12-22 10:02



Chrome'da hala çalışmıyor. Bu div'in üzerine tıkladığınızda (kenar boşluğunda) kontrol edin. - Alex Char
@AlexChar Bunu gördüğünüz için teşekkürler. Cevabımı güncelledi. - GOTO 0
Hala Alex'in işaret ettiği aynı sorun var. Gerçekten garip olan şey, merkezin soluna tıklarsanız, ilk div seçilecektir, ancak her iki durumda da ilk divın üzerini tıklatıyor olsanız bile ikinci div seçilecektir. - DoctorDestructo
Bunun Windows için Safari'de çalışmasının nedeni, satır içi blokları yanlış bir şekilde -webkit-user-select: none özellik mevcut. Tahmin et, aksi halde işe yaramazdı. Anyhoo, sadece bir düşünce vardı: :before eklemek için sözde öğe &zwnj; belki anonim açıklıktan kurtulabilirsin. - DoctorDestructo
Tüm kodunuzu tek bir satıra koymadığınız sürece sözde öğe istenmeyen bir alan ekler: /. Yani sanırım mükemmel değil. Her halükarda, sadece bir düşüncem var ve sonra seni yalnız bırakacağım: sıfır genişlik alanı (&#8203; veya \200B), sıfır genişlikli olmayan marangozdan daha iyi bir seçim olabilir çünkü ikincisi kontrol için kullanılmalıdır Ligatürleri. Sadece bir teknik, ama acımadı. - DoctorDestructo


Kullanılması gerekmiyorsa display: inline-blockFloat kullanmanızı tavsiye ederim. İşte örnek.

Örneğinize göre yeni CSS şöyle olurdu:

div.text-input {
  display: block;
  background-color: black;
  color: white;
  width: 300px;
  float: left;
  margin-right: 10px;
}
div.unrelated {
  clear: both;
}

1
2017-12-22 06:12



Neden float içermesi gerekiyor: sol? Ekranı satır içi bloğundan engellemek için çalıştığında çalıştı. jsfiddle.net/dr6ocnfu/1 - jjbskir
Dahil ettim float: left İstediği CSS stilini yeniden üretmek display: inline-block. Sorunun bütün noktası budur. - Inacio Schweller


Kapsayıcıdaki metin seçimini devre dışı bırak ... düzeltmeniz gerekir.

Örneğin:

* {
   -ms-user-select: none; /* IE 10+ */
   -moz-user-select: -moz-none;
   -khtml-user-select: none;
   -webkit-user-select: none;
   user-select: none;
}

0
2017-12-23 16:00



Çok pul pul desteği ile standart olmayan bir özellik. Dikkatle ilerle. Referans: developer.mozilla.org/en-US/docs/Web/CSS/user-select - Shakespeare
yine de yardımcı değil - vsync


Biraz jQuery'ye ne dersin?

$(".outside").click(function(e){
    $(e.target).siblings(".text-input").blur();
    window.getSelection().removeAllRanges();
});

Ve eğer IRL'yi tıklarsanız contenteditable=true kardeşlerin çocukları:

$(".outside").click(function(e){
    if ($(e.target).siblings(".text-input").length != 0){
        $(e.target).siblings(".text-input").blur();
        window.getSelection().removeAllRanges();
    } 
    else {
        $(e.target).parentsUntil(".outside").last().siblings(".text-input").blur();
        window.getSelection().removeAllRanges();
    }
});

window.getSelection().removeAllRanges();"Bulanıklık, aramadan sonra tüm aralıkları kaldırmaktır"


0
2018-05-14 08:55