Criando componentes personalizados para o Bootstrap 4


A opinião pública traduziu o Bootstrap na categoria de estruturas lendárias do passado, mas ainda vale a pena assistir. O Bootstrap 4 é um excelente navegador para layout seguro e, mais importante, uma amostra de abordagem HTML sobre JS para criar aplicativos da Web, revela totalmente os recursos existentes do HTML para descrição declarativa da interface do usuário.


E como o código da estrutura JavaScript está desenvolvendo também é útil ter uma idéia. A arquitetura dos plug-ins do jQuery ainda está em uso, mas a partir da versão 4 é envolvida pelo Rollup nas classes do pacote ES6 transformadas usando o Babel6 . O jQuery provavelmente não será em breve - mais sobre isso mais tarde - mas, por enquanto, usando o exemplo da criação de seu próprio plug- in BsMultiSelect , na mesma pilha do Boostrap 4 , os recursos de desenvolvimento da estrutura serão revelados.


Por que " todo programador deve escrever o seu próprio ... "


" Melhorar o bem só estraga ." A necessidade de entender o que o novo Bootstrap obteve foi a transferência de seus componentes para a nova pilha e como é mais fácil agora criar componentes de alta ordem. Tudo parecia simples: combine .form-control , .badge e .dropdown-menu e você pode facilmente obter uma .dropdown-menu múltipla ...



Conflito de arquitetura da porta


O plug- in BsMultiSelect resultante não usa diretamente o código JS bootstrap.js , mas usa sua dependência, popper.js (estrutura pop-up vanilla). Isso ocorre porque o componente suspenso do bootstrap.js precisa encontrar o chamado elemento de alternância durante a inicialização no DOM (no caso específico, é um botão que abre o menu), se não o encontrar, ele trava com um erro (desde que eu criei diretamente a partir de js, tenho "botões" claro que não). Conclusão: os componentes afiados em "HTML sobre JS" não podem (ou desvantajosamente) ser criados diretamente a partir de JS. Conclusão número dois: você precisa programar componentes personalizados para que, no componente "HTML sobre JS", sempre haja um componente mais leve de "JS puro". Eu tenho esse MulitSelect.js completamente limpo não apenas do código, mas também dos estilos do Bootstrap. O MulitSelect.js desempenha o mesmo papel no BsMulitSelect.js, assim como o popper.js no dropdown.js.


Duas palavras sobre popper.js


Ótima biblioteca - uma função. O DropDown.js se repete, mas fornece uma interface completamente limitada a ele (novamente, porque em "HTML sobre JS" toda a API não é necessária). Popper tem uma questão mais aberta do que gostaríamos. Fiquei desapontado ao publicar no IE11 eventos que não são do Chrome .


Sobre a transição do IIFE para as classes


O padrão do plugin do jQuery é definir a função do construtor dentro do IIFE . Agora esta é uma classe dentro do IIFE. Abertura: antigas formas funcionais de executar métodos particulares entram em conflito com o ES6 lambda, portanto foram "abandonadas" no Bootstrap. Todos os métodos são públicos, enquanto os métodos pseudo-privados são prefixados com _ i.e. underscrore. Entendo que estou errado, mas sigo minhas convenções - "métodos públicos com letra maiúscula". Em todo o resto, o BsMultiSelect criou a adoção do contrato do DropDown.js "padrão", ou seja, Eu gostaria de representá-lo como uma espécie de clichê com carne.


no entanto, outra diferença, como há rollup, eu clico nos arquivos ..
 import $ from 'jquery' import AddToJQueryPrototype from './AddToJQueryPrototype' import MultiSelect from './MultiSelect' // ... ( (window, $) => { AddToJQueryPrototype('BsMultiSelect', (element, optionsObject, onDispose) => { // ... return new MultiSelect(element, optionsObject, onDispose, facade, window, $); }, $); } )(window, $) 

Novo acordo: o plugin deve publicar o Construtor - para não perder o construtor no IIFE. Sim, um IIFE deve permanecer - ninguém removeu a tarefa de definir a janela, as dependências $ e Popper (para aqueles que "não podem entrar nos módulos") de maneira padrão.


Configurações de Eslint e Stylelint Linter


Não me senti obrigado a seguir as regras draconianas para definir o código do Bootstrap. Certamente eles escrevem em um ambiente que os ajuda a definir espaços e a controlar o código-fonte é muito bom, mas é difícil para mim ouvir a cada segundo a tristeza do linter no VS Code. Ao escrever seu próprio plugin, as regras podem e devem ser bastante relaxadas.


Eslint, stylelint pode não sair com muita frequência, mas não há desejo de examinar as novas regras. Em todos os aspectos, essa conquista me irrita mais.


Código e pacote cumulativo de organização


O código redistribuível ES6 do Bootstrap é empacotado por pacote cumulativo em duas versões: bootstrap.js independente e pacote bootstrap.bundle.js - o último inclui popper.js.


O autor do rollup.config.js tem instintos estranhos para mim. Toda essa transformação de configuração por push e pop, dependendo da versão exigida de autônomo ou de pacote configurável , parece elaborada e intimidadora, felizmente, para escrever um plug-in, você só precisa de um tipo de pacote "autônomo" e não preciso provar que posso fazer melhor.


A versão autônoma do Bootstrap também é indicada no campo principal do pacote, ou seja, As dependências do npm são resolvidas para o mesmo arquivo que os usuários carregam via <script> . Esta não é uma solução inequívoca, mas meu plug - in BsMultiSelect seguiu o mesmo caminho. Nesse caso, os auxiliares da babel podem ser incluídos no plug - in , apesar de também estarem incluídos no bootsrap.js. Duplicação de alguma forma não está certa ...


O interessante é que o Bootstrap possui uma configuração paralela sob jspm - o carregador de módulo ES do navegador nativo e seu campo principal já são códigos remotos limpos, 12 componentes que não são incluídos no pacote, mas armazenados separadamente no diretório js / dist. Aqui, cada arquivo inclui auxiliares de babel. O Jspm agora está em uma encruzilhada, portanto, ao criar o BsMultiselect, ignore-o.


E, no entanto, é interessante perguntar aos conhecedores, o jspm levará todos os 12 vezes auxiliares duplicados para o navegador?

Uma grande vantagem do pacote foi descoberta - seus pacotes são legíveis, ao contrário dos webpack.


O Bootsrap 4 usa o Babel 6 e o ​​plug-in BsMultiSelect Babel 7


O BsMultiSelect migrou facilmente para o Babel 7 beta usando o plug-in rollup-babel atualizado (também em beta). Agora, vale a pena mudar para o Babel 7 por causa do novo @babel/preset-env (a configuração do transpiler "em que navegadores o código será executado"). Usando apenas a Internet, ficou bastante difícil entender como as predefinições do ES6 funcionam, elas passaram por uma longa evolução e muitas configurações desatualizadas foram acumuladas. Melhor apostar Babel 7 + @babel/preset-env imediatamente


No entanto, os erros beta de babel não precisaram esperar muito: [... nodeList] foi digitado em nodeList.concat (). Eu não entendi por um longo tempo, traduzir o código em chamadas jquery (isso ainda é necessário, mas mais sobre isso mais tarde) resolveu o problema. Pergunte: “Por que, então, Babel, se você não lida com ele?”, A resposta: “importações e lambda”.


Aspectos práticos


O Bootstrap 4 e seu plug-in (como qualquer código js) têm duas opções para fazer o download no navegador: através de script / estilo (crie uma "página") e através do nó de montagem / webpack (crie um "aplicativo", por isso continuarei com esses dois em princípio, situações muito diferentes e denotam: “página” e “aplicação”).
Para a página e o aplicativo, o mesmo "arquivo de distribuição" do Bootstrap será usado. Esta não é uma solução óbvia e não é a única (por exemplo, código diferente é usado para jspm e para testes mocha ), mas ao criar seu próprio plug-in, não há mais nada a fazer além de seguir esta convenção, esperando sua otimização.


Encontrar um equilíbrio entre satisfazer duas necessidades usando o mesmo código para duas opções de download diferentes: “páginas” e “aplicativos” é a principal tarefa de arquitetura que o desenvolvedor de plug-ins enfrenta.


Afinal, o plug-in Bootstrap também pode ser criado ad hoc , diretamente no seu aplicativo. Nesse caso, você pode escrever o código do plug-in com todos os prazeres: polyphiles e acesso às variáveis ​​SASS do esquema. No entanto, ao confiar na reutilização, será necessário transferir o plug-in para seu próprio pacote npm, os prazeres acima entram na categoria de problemas: você perde o acesso às variáveis ​​do SASS e precisa ter em mente os criadores das "páginas" que conectam o plug-in por meio de um script (onde estão meus polyfiles?).


Acesso às variáveis ​​de estilo SASS Bootstrap 4


Eu gostaria de escrever classes / seletores de CSS do Bootstrap para escrever o plugin. Nesse caso, ao personalizar o tema do Bootstrap, você pode esperar que o plug-in se adapte sem esforço adicional.


Para um plug-in auto-publicado, não há acesso às variáveis ​​do SASS.


Classes / seletores css existentes - não cobrem todos os estilos necessários para BsMutliSelect, por exemplo, você precisa de min-height para ul.form-control , quando no bootstrap.css existe apenas um seletor de css com altura para input.form-control - você não pode aplicá-lo para ul . Outras classes / seletores existentes trazem muitos estilos supérfluos: e se você quiser atribuir, por exemplo, cores de .form-control a um elemento sem atribuir uma classe .form-control ? Isso não funcionará porque não existe uma classe como .input-color na qual a variável $ input-color seria publicada "separadamente" de tudo.


Além disso, não é possível seguir as decisões da equipe do Bootstrap: eles não têm esse problema, se necessário - eles criam uma classe / seletor de CSS com a variável desejada e operam nela. Se você quiser debater, precisará explicar com Mark Otto , na equipe da BS, há um nível anormalmente alto de tomada de decisão, mesmo para mudanças cosméticas nos seletores de CSS, se as solicitações se enquadrarem na categoria "oferta".


Eu proponho a seguinte solução.


Para uma página (gerando um plug-in por meio de um script ), é necessário aturar a inacessibilidade das variáveis. Mas não é necessário oferecer-se para lidar com CSS - variáveis ​​inacessíveis podem ser oferecidas para serem personalizadas através de parâmetros js, pois não existem muitas (e nem todas são alteradas por qualquer esquema). Para o BsMultiSelect, os problemáticos eram: cor desativada, cor de entrada, sombra de controle focada (etc. apenas 10 estilos, a maioria deles raramente muda de esquema) ...


Por um lado, esta é uma declaração de todos os estilos dos quais o plugin depende ...
 $("select[multiple='multiple']").bsMultiSelect({ selectedPanelDefMinHeight: 'calc(2.25rem + 2px)', // default size selectedPanelLgMinHeight: 'calc(2.875rem + 2px)', // LG size selectedPanelSmMinHeight: 'calc(1.8125rem + 2px)', // SM size selectedPanelDisabledBackgroundColor: '#e9ecef', // disabled background selectedPanelFocusBorderColor: '#80bdff', // focus border selectedPanelFocusBoxShadow: '0 0 0 0.2rem rgba(0, 123, 255, 0.25)', // foxus shadow selectedPanelFocusValidBoxShadow: '0 0 0 0.2rem rgba(40, 167, 69, 0.25)', // valid foxus shadow selectedPanelFocusInvalidBoxShadow: '0 0 0 0.2rem rgba(220, 53, 69, 0.25)', // invalid foxus shadow inputColor: '#495057', // color of keyboard entered text selectedItemContentDisabledOpacity: '.65' // btn disabled opacity used }); 

Porém, para um aplicativo que usa o SASS e o coletor, você pode copiar BsMultiSelect.scss para si mesmo e corrigir o caminho para suas _variables.scss nele. Assim, o plugin "receberá" as variáveis ​​variáveis.


Tudo através de CSS ...
  $("select[multiple='multiple']").bsMultiSelect({ useCss: true }); 

Esses dois métodos são escritos explicitamente no meu código JS, através de dois "adaptadores". BsMultiSelect é realmente dois plugins em um. Um que trabalha com estilos através de variáveis ​​js, o outro delega esse trabalho css.


Ao mesmo tempo, devo dizer diretamente que trabalhar com CSS pode ser necessário, mesmo que a transferência de estilos personalizados por meio de parâmetros JS tenha sido usada, simplesmente porque os autores dos esquemas costumam fazer seu trabalho de maneira muito grosseira. Ou estranho. Por exemplo, o esquema de Skethy , por algum motivo, decidiu que o menu não precisa de um efeito de foco. Os recursos devem ser arquivados.


Mas, com o exemplo, espero que você possa ver como o plug-in se adaptou ao circuito pesado com relativa facilidade (foi necessário sobrecarregar os valores de apenas três estilos através dos parâmetros js).


adaptação ao esquema através de js
 $("select[multiple='multiple']").bsMultiSelect({ selectedPanelFocusBoxShadow:"0px 0px 0px 0.2rem rgba(51,51,51,0.25)", selectedPanelFocusBorderColor:"#333", selectedPanelDisabledBackgroundColor: "#f7f7f9" }); 


Esse é o máximo que pode ser alcançado usando as classes CSS "padrão" .bage , .form-control , .close , etc. Quase tudo se adaptou ao esquema, mas não tudo.


É uma pena, é claro, que você não consiga se livrar desses três parâmetros, nem todas as variáveis ​​de estilo de esquema são acessíveis por meio de seletores / classes css (estou mentindo, você pode sair se puder copiar BsMultiSelect.scss para si mesmo e trazer as variáveis ​​de circuito para ele, mas isso não satisfaz completamente , como todas as decisões que começam com as palavras "copiar para si mesmo").


Clique aqui: https://dashboardcode.imtqy.com/BsMultiSelect/indexsketchy.html


Polyfill's


No cenário “Estou escrevendo um plug-in ad hoc dentro do aplicativo” - você usará @babel/polyfill sem problemas e corrigirá o DOM do polyfill.io porque, dentro do aplicativo, ele já está lá.


Quando um plug-in é movido para um módulo npm externo, toda a alegria desaparece porque os usuários do Bootstrap não decidiram agradar as longas listas de polyfills necessários na documentação.


Solução: tudo o que o babel não transpõe, mas deixa para os polyphiles, impede que faça isso, rangendo os dentes, para converter em chamadas jQuery (por exemplo, Node.closest em $ .closest). Essa abordagem é adotada no próprio Bootstrap 4 e, obviamente, é uma luta contra o inchaço. Surpresa O jQuery é um polyfill.


Concordo que programar com Babel de olho no CanIUse.com e no MDN.com não é divertido. E o código é estranho (para mim).


Aqui é necessário destacar a situação de cima novamente. O Bootstrap usa duas bibliotecas jQuery e popper.js. O Popper.js é uma estrutura de baunilha dupla, não possui bf, jQuery ou polyfills externos, por si só. O JQuery é empacotado pelo grunhido que já usa o babel, mas de alguma forma magicamente sem seus polyfills e auxiliares. Um plug-in Bootstrap de terceiros (como o BsMultiSelct) usa o Babel 7. Seu produto ainda pode usar outra coisa. Não existe uma única plataforma polifílica, espera-se duplicação múltipla de código, existem quatro implementações das mesmas mais próximas carregadas no navegador. Mas nada pode ser feito sobre isso.


No entanto, se você usou polyfiles ao criar seu próprio plugin, lembre-se de que, se o aplicativo tiver scripts embutidos (por exemplo, <script>$( function() {/*..*/}) </script> ), você só precisará baixar os polyfiles de forma síncrona (caso contrário, o código embutido poderá iniciar a execução antes do momento em que o plug-in for carregado). I.e. por exemplo, webpack-polyfill-injector (o injetor de polifil mais rico que eu já conheci) preciso controlá-lo para que ele não decida carregar polifiles de forma assíncrona (comportamento padrão).


Sem jQuery


O jQuery parece um pouco tóxico, competindo e obscurecendo o Babel / ES6, mas não é para sempre. Existe o ramo v4-whithout-jquery , ele já está na solicitação de pool, planeja lançar o bootstrap-nojquery c versão 4.3 . Anteriormente, o espaço para nome dos eventos era chamado de maior problema de rejeição de jquery, embora seja óbvio que você pode escrever sem eles (BsMultiSelect sem). Aparentemente decidido.


Também foi anunciado que a partir da versão 4.3, será possível carregar os componentes originais no navegador separadamente (apenas para o cenário "aplicativo"). Os componentes originais se tornarão "como o BsMultiSelect "? Não. Se a equipe do BS precisar de algumas variáveis ​​do SASS, eles criarão classes / seletores de CSS para eles próprios e operarão com eles a partir do JS ("CSS funcional"). Os criadores de recursos personalizados não estão disponíveis.


A possível transição do sass para o pós-css https://github.com/twbs/bootstrap/projects/11 na 5ª versão fundamentalmente não muda nada. Ou muda tudo: "JS sobre HTML".


O Bootstrap 5 precisará configurar recomendações sobre como integrar os polifiles Babel e como corrigir o DOM. Aqui a previsão é mais ou menos clara: montagens completamente diferentes serão oferecidas aos criadores de páginas e criadores de aplicativos.


Sumário


Enquanto você escreve os componentes do Bootstrap 4 no Babel usando o método ad hoc sem pensar em reutilizar, o que significa polifiles e onde obter as variáveis ​​de estilo, você não conhece o luto.


Mas se você tornar o plug-in um pacote npm separado - e com o desejo de tomar uma decisão no espírito do próprio Bootstrap 4, o prazer será menor, você pensa com mais frequência e mais tempo. Você provavelmente precisa decidir imediatamente quem são seus usuários e oferecer compilações diferentes, uma para quem criará o aplicativo em pacotes e a outra para escrever páginas, ou seja, carregando o script do plugin.

Source: https://habr.com/ru/post/pt416235/


All Articles