Padomi un ieteikumi atkārtoti lietojamu UI komponentu izveidošanai

Farzarta Nazifi foto

Šajā rakstā es vēlos dalīties ar dažiem padomiem un viltībām, kuras izmantoju, veidojot mūsu galveno frontend bibliotēku, izmantojot Ember.js. Iepriekš ar to nav bijis kontakta, tā ir bijusi lieliska mācību iespēja. Es ceru, ka jūs, puiši, izbaudat to! Lūdzu, ņemiet vērā, ka rakstā izmantoto ideju ilustrēšanai izmantotais kods satur tikai pietiekami daudz informācijas, lai varētu to saprast. Tajā tiek izmantota arī kāda Ember.js terminoloģija, taču jēdzieni ir domāti kā karkasagnostiski.

Mērķi

Vienkārši sakot, bibliotēkas celtniecības prasības ir šādas:

  1. Tam jābūt produktīvam.
  2. Tam jābūt uzturējamam.
  3. Tam jābūt konsekventam.

Pieejas

Samaziniet biznesa loģiku

Viena no biežākajām problēmām, ar ko es saskāros projektos, ir komponenti, kas tajos satur pārāk daudz loģikas. Tādējādi tādu uzdevumu veikšana, kuri teorētiski ir ārpus to darbības jomas.

Pirms jebkuras funkcionalitātes ieviešanas ir labi izklāstīt dažus pienākumus, par kuriem komponents ir atbildīgs.

Iedomājieties, ka mēs veidojam pogu komponentu.

Es vēlētos, lai varētu:

  • Informējiet, kāda veida poga tā ir - galvenā vai parastā
  • Informējiet saturu, kas tiek parādīts pogas iekšpusē (ikona un teksts)
  • Atspējot vai iespējot pogu
  • Pēc klikšķa veikšanas veiciet dažas darbības

Ņemot šo mazo kontūru, atdaliet dažādas detaļas, kas iesaistītas šī komponenta veidošanas procesā. Mēģiniet noteikt, kur varētu ievietot lietas.

1 - tips un saturs ir specifiski komponentam, tāpēc tos var ievietot komponenta failā.

Tā kā tips zināmā mērā ir nepieciešams, pievienosim verifikāciju, ja vērtība netiks norādīta.

const type = get (tas, 'tips');
const tips = {
  primārais: “btn - primārais”,
  parasts: “btn - parasts”,
}
atgriešanās (tips)? tips [tips]: tips.regulārs;

Man patīk rekvizītus kartēt objektā, jo tas ļauj mērogot lietas bez lielām pūlēm - gadījumā, ja mums ir nepieciešama bīstamības poga vai kaut kas tamlīdzīgs.

2 - invalīdu stāvokli var atrast dažādos komponentos, piemēram, ieejā. Lai izvairītos no atkārtošanās, šo uzvedību var pārvietot uz moduli vai jebkuru dalītu struktūru - ļaudis to sauc par mixin.

3 - klikšķa darbību var atrast dažādos komponentos. Tātad to var arī pārvietot uz citu failu, un tajā nedrīkst būt nekādas loģikas - vienkārši jāzvana uz atzvanīšanu, ko nodrošina izstrādātājs.

Tādējādi mums var rasties priekšstats par gadījumiem, kad mūsu komponentam ir jārisina, vienlaikus palīdzot ieskicēt bāzes arhitektūru, kas atbalsta paplašināšanu.

Atsevišķs atkārtoti lietojams lietotāja interfeisa statuss

Noteiktas lietotāja saskarnes mijiedarbības ir raksturīgas dažādiem komponentiem, piemēram:

  • Iespējot / atspējot - piem. pogas, ieejas
  • Izvērst / samazināt - piem. sabrukums, nolaižamie saraksti
  • Rādīt / slēpt - diezgan daudz viss

Šīs īpašības bieži tiek izmantotas tikai vizuālā stāvokļa kontrolei - cerams.

Uzturiet konsekventu nomenklatūru dažādiem komponentiem. Visas darbības, kas saistītas ar vizuālo stāvokli, var pārvietot uz maisījumu.

/ * UIStateMixin * /
atspējot () {
  komplekts (šis, 'invalīds', taisnība);
  atdot šo;
},
iespējot () {
  komplekts (tas, 'invalīds', viltus ');
  atdot šo;
},

Katra metode ir atbildīga tikai par konkrēta mainīgā pārslēgšanu un atgriež pašreizējo ķēdes kontekstu, piemēram:

pogu
  .disable ()
  .showLoadingIndicator ();

Šo pieeju var paplašināt. Tā var pieņemt dažādus kontekstus un kontrolēt ārējos mainīgos, nevis izmantot iekšējos. Piemēram:

_getCurrentDisabledAttr () {
  atgriešanās (isPresent (saņemt (šī, “atspējota”))))
    ? 'atspējots' / * ārējais parametrs * /
    : 'isDisabled'; / * Iekšējais mainīgais * /
},
iespējot (konteksts) {
  set (konteksts || this, this._getCurrentDisabledAttr (), false);
  atdot šo;
}

Pamatfunkciju abstrahēšana

Katrā komponentā ir noteikta kārtība. Šīs rutīnas jāveic neatkarīgi no komponenta mērķa. Piemēram, pārbaudiet atzvanīšanu pirms tā aktivizēšanas.

Šīs noklusējuma metodes var arī pārvietot uz saviem maisījumiem, piemēram:

/ * BaseComponentMixin * /
_isCallbackValid (callbackName) {
  const atzvanīšana = get (this, callbackName);
  
  atgriezties !! (isPresent (atzvanīšana) && typeof callback === 'function');
},
_handleCallback (atzvanīšana, params) {
  if (! this._isCallbackValid (atzvanīšana)) {
    mest jaunu kļūdu (/ * ziņojums * /);
  }
  this.sendAction (atzvanīšana, params);
},

Un pēc tam iekļauts komponentos.

/* Komponents */
onClick (params) {
  this._handleCallback ('onClick', params);
}

Tas nodrošina jūsu bāzes arhitektūras konsekvenci. Tas arī ļauj paplašināt un pat integrēt ar trešo personu programmatūru. Bet, lūdzu, neesi filozofējošs abstraktors.

Komponējošie komponenti

Cik vien iespējams, izvairieties no funkcionalitātes pārrakstīšanas. Var panākt specializāciju. To var izdarīt, izmantojot kompozīciju un grupēšanu. Kā arī mazāku sastāvdaļu apvienošana, lai izveidotu jaunus komponentus.

Piemēram:

Pamatkomponenti: Poga, nolaižamā izvēlne, ievade.
Nolaižamā poga => poga + nolaižamā izvēlne
Automātiskā aizpildīšana => ievade + nolaižamā izvēlne
Atlasiet => ievade (tikai lasāma) + nolaižamā izvēlne

Tādā veidā katram komponentam ir savi pienākumi. Katrs apstrādā savu stāvokli un parametrus, bet aptinuma komponents apstrādā savu īpašo loģiku.

Visnozīmīgākās ir bažu nodalīšana.

Bažas sadalīšana

Sastādot sarežģītākus komponentus, pastāv iespēja sadalīt bažas. Bažas varat sadalīt starp dažādām komponenta daļām

Pieņemsim, ka mēs veidojam atlasītu komponentu.

{{forma-atlasiet iesiešana = preceId preces = preces}}
vienumi = [
  {apraksts: “1. produkts”, vērtība: 1},
  {apraksts: “2. produkts”, vērtība: 2}
]

Iekšēji mums ir vienkārša ievades sastāvdaļa un nolaižamā izvēlne.

{{form-input binding = _description}}
{{ui-nolaižamie vienumi = vienumi onSelect = (darbība 'selectItem')}}

Mūsu galvenais uzdevums ir iepazīstināt lietotāju ar aprakstu, taču tam nav nozīmes mūsu lietojumprogrammā - vērtība to dara.

Izvēloties opciju, jūs sadalījāt objektu, nosūtot aprakstu uz mūsu ievadi caur iekšēju mainīgo, vienlaikus palielinot vērtību līdz kontrollerim, atjauninot saistīto mainīgo.

Šo jēdzienu var izmantot komponentiem, kuros saistītā vērtība ir jāpārveido, piemēram, kā skaitlis, automātiskā aizpildīšana vai atlases lauks. Datumu atlasītāji var arī ieviest šo rīcību. Viņi var atmaskot datumu pirms saistītā mainīgā atjaunināšanas, vienlaikus parādot lietotājam maskēto vērtību.

Riski palielinās, jo pārveidojumi kļūst sarežģītāki. Pārmērīga loģika vai nepieciešamība atbalstīt notikumus - pirms šīs pieejas ieviešanas padomājiet par to.

Sākotnējie iestatījumi un jaunie komponenti

Dažreiz ir jāoptimizē komponenti un pakalpojumi, lai atvieglotu attīstību. Tie tiek piegādāti sākotnējo iestatījumu vai jaunu komponentu veidā.

Sākotnējie iestatījumi ir parametri. Kad viņi ir informēti, viņi komponentam nosaka iepriekš noteiktas vērtības, vienkāršojot tā deklarēšanu. Tomēr jaunie komponenti parasti ir vairāk specializētas bāzes komponentu versijas.

Grūtākais ir zināt, kad ieviest iestatījumus vai izveidot jaunus komponentus. Pieņemot šo lēmumu, es izmantoju šādas vadlīnijas:

Kad izveidot iestatījumus

1 - atkārtotas lietošanas shēmas

Ir reizes, kad noteikts komponents tiek atkārtoti izmantots dažādās vietās ar vienādiem parametriem. Šajos gadījumos es vēlētos dot priekšroku iestatījumiem, nevis jauniem komponentiem, it īpaši, ja bāzes komponentam ir pārmērīgs parametru skaits.

/ * Regulāra ieviešana * /
{{veidlapas automātiskā aizpildīšana
    iesiešana = produktsId
    url = "produkti" / * ielādējamais URL * /
    labelAttr = "description" / * Atribūts izmantots kā etiķete * /
    valueAttr = "id" / * atribūts, ko izmanto kā vērtību * /
    apiAttr = "produkts" / * Param nosūtīts pēc pieprasījuma * /
}}
/ * Sākotnējie iestatījumi * /
{{veidlapas automātiskā aizpildīšana
    preset = "produkts"
    iesiešana = produktsId
}}

Iepriekš iestatītās vērtības tiek iestatītas tikai tad, ja parametrs nav informēts, saglabājot tā elastību.

/ * Preses moduļa naiva ieviešana * /
iepriekšējie iestatījumi = {
  produkts: {
    URL: “produkti”,
    labelAttr: “apraksts”,
    valueAttr: “id”,
    apiAttr: “produkts”,
  },
}
const attrs = presets [saņemt (tas, 'iepriekš iestatīts')];
Object.keys (attrs) .forEach ((prop) => {
  if (! get (this, prop)) {
    komplekts (tas, prop, attrs [prop]);
  }
});

Šī pieeja samazina zināšanas, kas vajadzīgas jūsu komponenta pielāgošanai. Vienlaicīgi tas atvieglo apkopi, ļaujot vienuviet atjaunināt noklusējuma vērtības.

2 - pamatkomponents ir pārāk sarežģīts

Kad pamata komponents, kuru izmantojāt specifiskāka komponenta izveidošanai, pieņem pārāk daudz parametru. Tādējādi tā izveidošana radītu dažas problēmas. Piemēram:

  • Jums būs jāinjicē visvairāk (ja ne visi) parametri no jaunā komponenta uz pamata sastāvdaļu. Tā kā no tā izriet arvien vairāk komponentu, visi bāzes komponenta atjauninājumi atspoguļotu milzīgas izmaiņas. Tādējādi palielinās kļūdu biežums.
  • Jo vairāk komponentu tiek izveidots, jo grūtāk dokumentēt un iegaumēt dažādās nianses. Īpaši tas attiecas uz jaunajiem izstrādātājiem.

Kad izveidot jaunus komponentus

1 - funkcionalitātes paplašināšana

Paplašinot funkcionalitāti no vienkāršāka komponenta, ir lietderīgi izveidot jaunu komponentu. Tas palīdz novērst komponentu loģikas noplūdi citam komponentam. Tas ir īpaši noderīgi, īstenojot papildu uzvedību.

/ * Deklarācija * /
{{ui-pogas nolaižamie vienumi = priekšmeti}}
/* Zem kapuces */
{{# ui-poga onClick = (darbība 'toggleDropdown')}}
  {{label}}  
{{/ ui-button}}
{{#if isExpanded}}
  {{ui-nolaižamie vienumi = priekšmeti}}
{{/ ja}}

Iepriekš minētajā piemērā tiek izmantota pogas sastāvdaļa. Tas paplašina tā izkārtojumu, lai atbalstītu fiksētu ikonu, tajā pašā laikā iekļaujot nolaižamo komponentu un tā redzamības stāvokli.

2 - dekorēšanas parametri

Ir vēl viens iespējams iemesls jaunu komponentu izveidošanai. Tas ir tad, kad nepieciešams kontrolēt parametru pieejamību vai izrotāt noklusējuma vērtības.

/ * Deklarācija * /
{{form-datepicker onFocus = (darbība 'doSomething')}}
/* Zem kapuces */
{{form-input onFocus = (darbība '_onFocus')}}
_onFocus () {
  USD (šis elements)
    .find ('ievade')
    .izvēlēties (); / * Atlasiet fokusa lauka vērtību * /
  this._handleCallback ('onFocus'); / * Aktivizē param atzvanīšanu * /
}

Šajā piemērā komponentam tika nodrošināta funkcija, kas paredzēta izsaukšanai, kad lauks ir fokusēts.

Iekšēji tā vietā, lai atzvanīšanu nosūtītu tieši pamatkomponentam, tā veic iekšēju funkciju. Tas veic noteiktu uzdevumu (izvēloties lauka vērtību) un pēc tam izsauc sniegto atzvanīšanu.

Tas nenovirza visus parametrus, kurus pieņem pamata ievades komponents. Tas palīdz kontrolēt noteiktu funkcionalitāti. Tas arī ļauj izvairīties no nevajadzīgām validācijām.

Manā gadījumā onBlur notikums tika aizstāts ar citu notikumu - onChange. Tas tiek aktivizēts, kad lietotājs aizpilda lauku vai kalendārā izvēlas datumu.

Secinājums

Veidojot savus komponentus, ņemiet vērā savu pusi, kā arī to, kurš šo sastāvdaļu izmanto ikdienas dzīvē. Tādā veidā visi uzvar.

Labāko rezultātu dod visi grupas dalībnieki, darot to, kas ir vislabākais gan pašam, gan grupai - Džons Nešs

Nekautrējieties lūgt atsauksmes. Jūs vienmēr atradīsit kaut ko tādu, pie kā var strādāt.

Lai vēl vairāk padziļinātu savas programmatūras inženierijas prasmes, es iesaku sekot Ērika Elliota sērijai “Programmatūras sastādīšana”. Tas ir vienreizēji!

Nu, es ceru, ka jums patika raksts. Lūdzu, ņemiet vērā šos jēdzienus, pārvērtiet savas idejas un dalieties tajā ar mums!

Arī nekautrējieties sazināties ar mani twitter @gcolombo_! Es labprāt uzklausītu jūsu viedokli un pat strādātu kopā.

Paldies!