Como você pode definir programaticamente um HTML SELECT para cair (por exemplo, devido ao mouseover)?

105

Como você pode definir programaticamente um HTML selectpara cair (por exemplo, devido ao mouseover)?

Corey Trager
fonte
6
Eu recomendo não mexer com o comportamento do padrão <select>, já que as pessoas esperam que ele se comporte de uma certa maneira e você estará impedindo que pessoas em outras plataformas (como celular) usem seu site.
Brian Donovan
1
@BrianDonovan Não é como se você não pudesse adicionar algum tratamento para isso.
Morg.
@shasikanth: seu violino não funciona nem no Firefox 37 nr no Chrome
rubo77
Ok, acho que o violino funcionou anteriormente. De qualquer forma, eu estaria excluindo meu comentário aqui.
shasi kanth
@BrianDonovan Na verdade, mobile é um bom caso de uso disso ... gerando programaticamente um select e então ter suas opções automaticamente abertas.
Michael,

Respostas:

15

Você não pode fazer isso com uma tag de seleção de HTML, mas pode fazer isso com JavaScript e HTML. Há uma variedade de controles existentes que fazem isso - por exemplo, a lista de "sugestões" anexada à entrada do SO "tag interessante / ignorada" ou a pesquisa do Gmail por endereços de e-mail.

Existem muitos controles JavaScript + HTML que fornecem esse recurso - procure por controles de preenchimento automático para ideias.

Veja este link para o controle de preenchimento automático ... http://ajaxcontroltoolkit.codeplex.com/

rp.
fonte
6
isso é uma pena - os navegadores móveis fornecem uma lista de rolagem específica do sistema operacional e eu preciso que ela apareça automaticamente.
Michael,
120

Isso costumava ser possível com HTML + Javascript, apesar de em todos os outros lugares as pessoas dizerem que não é, mas foi obsoleto mais tarde e não funciona agora.

No entanto, isso só funcionou no Chrome. Leia mais se você estiver interessado.


De acordo com o W3C Working Draft para HTML5, Seção 3.2.5.1.7. Conteúdo interativo :

Certos elementos em HTML têm um comportamento de ativação, o que significa que o usuário pode ativá-los. Isso dispara uma sequência de eventos dependentes do mecanismo de ativação, [...] por exemplo, usando teclado ou entrada de voz, ou através de cliques do mouse .

Quando o usuário dispara um elemento com um comportamento de ativação definido de uma maneira diferente de clicar nele, a ação padrão do evento de interação deve ser executar as etapas de ativação de clique sintético no elemento.

<select>sendo um Conteúdo Interativo, acreditei ser possível exibir programaticamente seus <option>s. Depois de algumas horas brincando, descobri que usar document.createEvent()e .dispatchEvent()funciona.

Dito isso, é hora da demonstração. Aqui está um Fiddle funcionando.


HTML:

<select id="dropdown">
    <option value="Red">Red</option>
    <option value="Green">Green</option>
    <option value="Blue">Blue</option>
</select>
<br>
<button id="fire" type="button" onclick="runThis()">Show dropdown items</button>​

Javascript:

// <select> element displays its options on mousedown, not click.
showDropdown = function (element) {
    var event;
    event = document.createEvent('MouseEvents');
    event.initMouseEvent('mousedown', true, true, window);
    element.dispatchEvent(event);
};

// This isn't magic.
window.runThis = function () { 
    var dropdown = document.getElementById('dropdown');
    showDropdown(dropdown);
};

Se alguém encontrar uma maneira de fazer o mesmo, mas não no Chrome, sinta-se à vontade para modificar este violino .

Xavier Ho
fonte
2
Obrigado por isso! Eu precisava emular o comportamento ALT + SETA PARA BAIXO do IE precisamente no Chrome.
J Bryan Price
3
Eu gostaria de poder adicionar à sua recompensa por isso. Muito obrigado.
Adam Tuttle
7
Não funciona em: IE10, FF 24. Funciona em: Chrome 30, Safari 6.0.5,Opera 16
hitautodestruct
2
@AdamTuttle Também não funciona no Android 4.4.2
Mirko
42
Agora ele está obsoleto no Chrome 53+
Washington Guedes
47

A resposta de Xavier Ho cobre como resolver o problema na maioria dos navegadores que existem atualmente. Mas, é uma boa prática 'não despachar / modificar' mais eventos por JavaScript . (Como, mousedownneste caso)

A partir da versão 53+, o Google Chrome não executará a ação padrão para eventos não confiáveis . Como eventos criados ou modificados por script ou despachados por meio de dispatchEventmétodo. Essa mudança é para alinhar com Firefox e IE que eu acho que já não estão realizando a ação.

Para fins de teste, Fiddle forneceu a resposta de Xavier que não funcionará no Chrome 53+. (Eu não testo FF e IE).

Links para referência:

https://www.chromestatus.com/features/5718803933560832 https://www.chromestatus.com/features/6461137440735232

E initMouseEvent também está obsoleto

Asim KT
fonte
Isso pode ser feito usando MouseEvents? developer.mozilla.org/en-US/docs/Web/API/MouseEvent
Shamal Perera
Acho que não. você tentou alguma coisa?
Asim KT
28

Este é o mais próximo que consegui obter, alterar o tamanho do elemento no mouseover e restaurar o tamanho no mouseout:

       <select onMouseOut="this.size=1;" onMouseOver="this.size=this.length;">
        <option>1</option>
        <option>2</option>
        <option>3</option>
        <option>4</option>
        <option>5</option>
      </select>

CMS
fonte
13
ou <SELECT onMouseOut = "this.size = 1;" onMouseOver = "this.size = this.length;"> ... </SELECT>
RealHowTo
1
Também é necessário adicionar onchange = "this.size = 1" para que o menu seja recolhido assim que a seleção for feita. As regras CSS do elemento também precisam ser configuradas.
gm2008
Parece que funciona. A largura da seleção diminui e isso causa um evento de retirada do mouse, redefinindo a seleção para sua largura original. Isso causa um efeito de convulsão. Definir uma largura fixa parece resolver isso. Com mais do que alguns itens, a lista se expande além da exibição.
1,21 gigawatts
16

Eu tenho esse mesmo problema e a maneira mais fácil que encontrei de resolver isso foi com html e css.

select{
  opacity: 0;
  position: absolute;
}
<select>
  <option>option 1</option>
  <option>option 2</option>
  <option>option 3</option>
</select>
<button>click</button>

Rafael Umbelino
fonte
2
Faz muito tempo que não vejo essa abordagem e é a referência que esperava encontrar. Melhor com CSS extra para coincidir com o tamanho do select escondido para acionar (botão, img, div, etc) ... 1) Garante região clicável preenche acionador 2) O menu abre diretamente abaixo do acionador. Observação: também pode ser necessário adicionar um Z-index para garantir que a região clicável seja o elemento mais importante em alguns layouts.
Mavelo
entretanto, se o usuário rolar a página para baixo, o botão se move de acordo, mas a seleção permanece na mesma posição; não exatamente como o esperado. alguma solução para isso?
David Portabella
Solução perfeita. Mas melhor, talvez, <div style='position:relative'><select> <option>option 1</option> <option>option 2</option> <option>option 3</option> </select> <button>click</button></div>empurre o botão e selecione um div como este @DavidPortabella
Muhammet Can TONBUL
8

Acho que isso não é mais possível no Chrome.

Parece que a versão 53 do Chrome desativa essa funcionalidade, conforme afirmado por Asim K T.

De acordo com a especificação http://www.w3.org/TR/DOM-Level-3-Events/#trusted-events

Os eventos confiáveis ​​não devem disparar a ação padrão (exceto o evento de clique).

No entanto, eles habilitaram no webview, mas eu não testei isso.

Descobrimos que alguns webviews estão usando fastclick dentro deles e, devido ao risco de quebra, permitiremos o mouse sobre seleções, mesmo que não sejam confiáveis.

E nesta discussão, a ideia de permitir que os desenvolvedores abram um menu suspenso programaticamente foi abandonada.

Understatic
fonte
7

Se alguém ainda estiver procurando por isso:

<select id="dropdown">
    <option value="Red">Red</option>
    <option value="Green">Green</option>
    <option value="Blue">Blue</option>
</select>
<br>
<button id="fire" type="button" >Show dropdown items</button>

Javascript:

var is_visible=false; 

$(document).ready(function(){

    $('#fire').click(function (e) { 
    var element = document.getElementById('dropdown');


    if(is_visible){is_visible=false; return;}
    is_visible = true;

    var event;
    event = document.createEvent('MouseEvents');
    event.initMouseEvent('mousedown', true, true, window);
    element.dispatchEvent(event);

    /* can be added for i.e. compatiblity.
      optionsSelect.focus();
       var WshShell = new ActiveXObject("WScript.Shell");
       WshShell.SendKeys("%{DOWN}");
    */
    e.stopPropagation();
    return false;
});


$(document).click(function(){is_visible=false; });
});

Atualizar:

Um até que não haja uma solução perfeita para esse problema, mas você pode tentar evitar esse cenário. Por que você quer fazer isso. Eu estava pensando em uma solução alguns meses atrás para fazer um plugin selecionado para dispositivos móveis

https://github.com/HemantNegi/jquery.sumoselect

Finalmente acabamos mascarando o div customizado (ou qualquer outro elemento) com um elemento select transparente, para que ele possa interagir diretamente com o usuário.

Hemant_Negi
fonte
1
Plug-ins como github.com/HemantNegi/jquery.sumoselect são a única solução para vários navegadores que realmente parece melhor do que o controle padrão.
Justin
iniMouseEventparece funcionar, mas por $(select).trigger('mousedown')que não funciona?
coding_idiot
3

Aqui está a melhor maneira que encontrei. NOTA Ele só funciona com o IE no Windows e sua web provavelmente precisaria estar em uma zona segura - porque acessamos o shell. O truque é que ALT-Seta para baixo é uma tecla de atalho para abrir uma lista suspensa de seleção.

<button id="optionsButton" style="position:absolute;top:10px;left:10px;height:22px;width:100px;z-index:10" onclick="doClick()">OPTIONS</button>
<select id="optionsSelect" style="position:absolute;top:10px;left:10px;height:20px;width:100px;z-index:9">
    <option>ABC</option>
    <option>DEF</option>
    <option>GHI</option>
    <option>JKL</option>
</select>
<script type="text/javascript">
   function doClick() {
       optionsSelect.focus();
       var WshShell = new ActiveXObject("WScript.Shell");
       WshShell.SendKeys("%{DOWN}");
   }
</script>
sproketboy
fonte
3
Não funcionará a menos que você faça isso .
Knu
1
@Knu Internet Explorer adiciona automaticamente os IDs dos elementos como referências ao elemento no escopo global.
user2428118
@KlasMellbourn provavelmente. Eles estão tentando tornar seus navegadores mais compatíveis agora. Use a solução de "tamanho" mencionada.
sproketboy
2

Pare de pensar que uma coisa é impossível, nada é impossível de fazer, quando você quer fazer.

Use esta função expandir JS criada por um cara.

http://code.google.com/p/expandselect/

Inclua este JS e apenas chame-o, passando o parâmetro como seu id de seleção, assim:

ExpandSelect(MySelect)
Paulo roberto rosa
fonte
2
Para ficar claro, esse JS não faz com que um <SELECT>caia. Como afirma explicitamente "Os navegadores não permitem a expansão de <select> em javascript puro, esse controle pode ser expandido apenas clicando nele diretamente com o mouse". Portanto, é "impossível"! Em vez disso, o JS afirma "Nós imitamos o controle <select> expandido criando outro select com várias opções exibidas ao mesmo tempo ..." O que é bem diferente e pode ou não ser aceitável para o seu caso de uso ...
JonBrave
1

Posso estar errado, mas não acredito que seja possível com a caixa de seleção padrão. Você poderia fazer algo com JS e CSS que alcançasse o resultado desejado, mas não (que eu saiba) o SELECT básico.

Mandril
fonte
0

Abrir uma "seleção de HTML" é possível por meio de algumas soluções alternativas mencionadas nesta pergunta e outras semelhantes. No entanto, uma maneira mais limpa de fazer isso é adicionar uma biblioteca de seleção ao seu projeto, como "select2" ou "escolhido". Por exemplo, abrir um select2 programaticamente seria tão fácil quanto:

$('#target-select').select2('open');
Kasra Ebrahimi
fonte
-2

Não é exatamente o que você pediu, mas gosto desta solução pela sua simplicidade. Na maioria dos casos em que desejo iniciar um menu suspenso, é porque estou validando que o usuário realmente fez uma seleção. Eu mudo o tamanho da lista suspensa e focalizo, o que destaca bem o que eles pularam:

$('#cboSomething')[0].size = 3;
$('#cboSomething')[0].focus();
Rob3C
fonte
Não sei por que você foi rejeitado, pois não é a "pior" maneira de fazer isso. Eu evitaria isso simplesmente porque muda o layout dos elementos ao redor. Embora eu ache que a solução do @CMS é mais facilmente compreendida com os eventos de foco / desfoque no controle.
Mavelo