Yeniden kullanılabilir UI bileşenleri oluşturmak için ipuçları ve püf noktaları

Fotoğraf Farzard Nazifi

Bu makalede Ember.js kullanarak temel ön uç kütüphanemizi oluştururken kullandığım bazı ipuçlarını ve püf noktalarını paylaşmak istiyorum. Onunla daha önce hiç bağlantı kurmamak harika bir öğrenme fırsatı oldu. Umarım beğenirsiniz! Lütfen dikkat, yazıdaki fikirleri örneklemek için kullanılan kodun dikkatini çekmek için yeterli bilgi içerdiğini unutmayın. Ayrıca bazı Ember.js terminolojisini kullanır, ancak kavramların çerçeve-agnostik olması amaçlanmıştır.

Görevler

Basitçe söylemek gerekirse, kütüphaneyi oluşturmak için gerekenler şunlardır:

  1. Verimli olmalı.
  2. Bakım yapılabilir olmalı.
  3. Tutarlı olmalı.

Yaklaşımlar

İş mantığını en aza indirin

Projelerde karşılaştığım en sık karşılaşılan sorunlardan biri, içlerinde çok fazla mantık içeren bileşenlerdir. Böylece teorik olarak kapsam dışında kalan görevleri yapmak.

Herhangi bir işlevselliği uygulamadan önce, bileşenin sorumlu olduğu görevlerin bazılarını ana hatlarıyla belirtmek iyidir.

Bir düğme bileşeni oluşturduğumuzu hayal edin.

Yapabilmek istiyorum:

  • Hangi tür düğmenin olduğunu belirtin - Birincil veya normal
  • Düğmenin içinde görüntülenen içeriği bilgilendirin (Simge ve metin)
  • Düğmeyi devre dışı bırak veya etkinleştir
  • Tıklama üzerine biraz işlem yapın

Bu küçük anahattı olan bu bileşenin inşa sürecinde yer alan farklı parçaları ayırın. Eşyaların nereye yerleştirilebileceğini belirlemeye çalışın.

1 - Tür ve içerik bileşene özgüdür, bu nedenle bileşen dosyasına yerleştirilebilirler.

Tür - bir dereceye kadar - gerekli olduğundan, herhangi bir değer verilmemesi durumunda bir doğrulama ekleyelim.

const type = get (bu, 'type');
const türleri = {
  birincil: 'btn - birincil',
  düzenli: 'btn - düzenli',
}
dönüş (tür)? types [type]: types.regular;

Özellikleri bir nesneye eşleştirmeyi seviyorum, çünkü nesnelerin çok çaba harcamadan ölçeklenmesini sağlıyor; tehlike düğmesine veya buna benzer bir şeye ihtiyacımız olursa.

2 - Engelli durumu bir giriş gibi farklı bileşenlerde bulunabilir. Tekrarı önlemek için, bu davranış bir modüle veya paylaşılan herhangi bir yapıya taşınabilir - millet buna karışım olarak adlandırılır.

3 - Tıklama işlemi farklı bileşenlerde bulunabilir. Bu yüzden başka bir dosyaya da taşınabilir ve içinde hiç mantık içermemelidir - sadece geliştirici tarafından sağlanan geri çağırmayı çağırmak gerekir.

Bu şekilde, genişletmeyi destekleyen bir temel mimarinin ana hatlarını çizmeye yardımcı olurken, bileşenimizin hangi durumlarda ele alması gerektiği konusunda bir fikrimiz olabilir.

Ayrı yeniden kullanılabilir UI durumu

Bazı kullanıcı arabirimi etkileşimleri, aşağıdaki gibi farklı bileşenler arasında yaygındır:

  • Etkinleştir / devre dışı bırak - örn. düğmeler, girişler
  • Genişlet / Küçült - örn. daralt, açılır listeler
  • Göster / gizle - Hemen hemen her şey

Bu özellikler genellikle görsel durumu kontrol etmek için kullanılır - umarım.

Farklı bileşenlerde tutarlı bir isimlendirme yapın. Görsel bir durumla ilgili tüm eylemler bir karışıma taşınabilir.

/ * UIStateMixin * /
devre dışı bırak () {
  set (bu, ‘devre dışı’, doğru);
  bunu geri ver;
},
etkinleştirme() {
  set (bu, 'devre dışı', yanlış ');
  bunu geri ver;
},

Her yöntem yalnızca belirli bir değişkeni değiştirmekle sorumludur ve şu gibi zincirleme için geçerli bağlamı döndürür:

buton
  .disable ()
  .showLoadingIndicator ();

Bu yaklaşım genişletilebilir. Farklı içerikleri kabul edebilir ve dahili olanları kullanmak yerine harici değişkenleri kontrol edebilir. Örneğin:

_getCurrentDisabledAttr () {
  dönüş (isPresent (bu ('devre dışı bırakılmış')))
    ? 'devre dışı' / * Dış parametre * /
    : 'isDisabled'; / * Dahili değişken * /
},
enable (bağlam) {
  set (bağlam || this, this._getCurrentDisabledAttr (), yanlış);
  bunu geri ver;
}

Temel işlevlerin soyutlanması

Her bileşen belirli rutinler içerir. Bu rutinler, bileşenin amacından bağımsız olarak gerçekleştirilmelidir. Örneğin, tetiklemeden önce geri aramayı doğrulama.

Bu varsayılan yöntemler şu şekilde kendi karışımlarına da taşınabilir:

/ * BaseComponentMixin * /
_isCallbackValid (callbackName) {
  const callback = get (bu, callbackName);
  
  return !! (isPresent (callback) && typeof callback === 'işlevi');
},
_handleCallback (geri arama, params) {
  if (! this._isCallbackValid (callback)) {
    yeni hata atmak (/ * message * /);
  }
  this.sendAction (geri çağırma, params);
},

Ve sonra bileşenlere dahil edilir.

/* Bileşen */
onClick (params) {
  this._handleCallback ('onClick', params);
}

Bu, temel mimarinizi tutarlı tutar. Ayrıca, üçüncü taraf yazılımlarla genişletmeye ve hatta entegrasyona izin verir. Fakat lütfen, felsefi bir özet olma.

Bileşenleri oluşturma

İşlevselliği mümkün olduğu kadar yeniden yazmaktan kaçının. Uzmanlık sağlanabilir. Kompozisyon ve gruplama yoluyla yapılabilir. Yeni bileşenler oluşturmak için daha küçük bileşenleri bir araya getirmenin yanı sıra.

Örneğin:

Temel bileşenler: Düğme, aşağı açılır, giriş.
Aşağı açılan düğme => düğmesi + aşağı açılır
Otomatik tamamlama => giriş + açılır menü
=> Giriş (salt okunur) + açılır menüyü seçin

Bu şekilde, her bir bileşenin kendi görevleri vardır. Her biri kendi durumunu ve parametrelerini ele alırken, sarmalayıcı bileşeni kendi mantığını ele alır.

Endişeyle endişelerin ayrılması.

Endişeleri bölmek

Daha karmaşık bileşenleri oluştururken endişeleri bölme olasılığı vardır. Bir bileşenin farklı bölümleri arasındaki endişeleri bölebilirsiniz

Diyelim ki seçkin bir bileşen oluşturuyoruz.

{{form-select binding = productId items = items}}
items = [
  {tanım: 'Ürün # 1', değer: 1},
  {tanım: 'Ürün # 2', değer: 2}
]

Dahili olarak, basit bir giriş bileşenine ve bir açılır menüye sahibiz.

{{form-input binding = _description}}
{{ui-dropdown items = öğeler onSelect = (eylem 'selectItem')}}

Asıl görevimiz, tanımı kullanıcıya sunmaktır, ancak uygulamamız için bir anlamı yoktur - değer.

Bir seçenek seçerken, değeri denetleyiciye doğru iterek, değişken değişkenini güncelleyerek açıklamayı girişimize iç değişken aracılığıyla aşağı göndererek nesneyi böldünüz.

Bu kavram, bir değer, otomatik tamamlama veya seçme alanı gibi, sınır değerinin dönüştürülmesi gereken bileşenlere uygulanabilir. Datepickers da bu davranışı uygulayabilir. Maskeli değeri kullanıcıya sunarken, bağlı değişkeni güncellemeden önce tarihin maskesini kaldırabilirler.

Dönüşümler karmaşıklık arttıkça riskler de artar. Aşırı mantık veya olayları destekleme zorunluluğu ile - bu yaklaşımı uygulamadan önce düşünün.

Önayarlar - Yeni Bileşenler

Bazen gelişimi kolaylaştırmak için bileşenleri ve hizmetleri optimize etmek gerekir. Bunlar ön ayar veya yeni bileşenler şeklinde teslim edilir.

Ön ayarlar parametredir. Bilgilendirildiğinde, bildirimi basitleştirerek bileşen üzerinde önceden tanımlanmış değerler belirlerler. Ancak, yeni bileşenler genellikle temel bileşenlerin daha özel sürümleridir.

Zor kısım, ön ayarların ne zaman uygulanacağını veya yeni bileşenlerin ne zaman oluşturulacağını bilmektir. Bu kararı verirken aşağıdaki yönergeleri kullanıyorum:

Hazır ayarlar ne zaman oluşturulur

1 - Tekrarlayan kullanım şekilleri

Belirli bir bileşenin aynı parametrelere sahip çeşitli yerlerde tekrar kullanıldığı zamanlar vardır. Bu durumlarda, özellikle temel bileşende aşırı sayıda parametre olduğunda, yeni bileşenlerin ön ayarlarını tercih etmeyi severim.

/ * Düzenli uygulama * /
{{Form tamamlama
    bağlama = productId'den
    url = "ürünler" / * Alınacak URL * /
    labelAttr = "açıklama" / * Etiket olarak kullanılan özellik * /
    valueAttr = "id" / * Değer olarak kullanılan özellik * /
    apiAttr = "ürün" / * Param istek üzerine gönderildi * /
}}
/ * Ön ayarlar * /
{{Form tamamlama
    Önceden ayarlanmış = "ürün"
    bağlama = productId'den
}}

Ön ayardan gelen değerler, sadece parametreye bilgi verilmemişse, esnekliğini koruyarak ayarlanır.

/ * Ön ayar modülünün saf uygulaması * /
const presets = {
  ürün: {
    url: ‘ürünler’
    labelAttr: "açıklama"
    valueAttr: ‘id’,
    apiAttr: ‘ürün’
  },
}
const attrs = hazır ayarlar [get (this, ‘hazır ayar’)];
Object.keys (attrs) .forEach ((prop) => {
  if (! olsun (bu, pervane)) {
    set (bu, prop, attrs [prop]);
  }
});

Bu yaklaşım, bileşeninizi kişiselleştirmek için gereken bilgileri azaltır. Aynı zamanda, varsayılan değerleri tek bir yerde güncellemenizi sağlayarak bakımı kolaylaştırır.

2 - Temel bileşen çok karmaşık

Daha spesifik bir bileşen oluşturmak için kullanacağınız temel bileşen çok fazla parametre kabul ettiğinde. Böylece, onu oluşturmak bazı problemlere yol açacaktır. Örneğin:

  • Yeni bileşenden temel bileşene parametrelerin çoğunu (tümü değilse de) enjekte etmeniz gerekir. Gittikçe daha fazla bileşen bundan kaynaklandığı için, temel bileşen üzerinde yapılan güncellemeler büyük miktarda değişiklik yapacaktır. Böylece, daha yüksek hata oranına yol açar.
  • Daha fazla bileşen oluşturuldukça, farklı nüansları belgelemek ve ezberlemek zorlaşır. Bu özellikle yeni geliştiriciler için geçerlidir.

Yeni bileşenler ne zaman oluşturulur

1 - İşlevsellik genişletiliyor

İşlevselliği daha basit bir bileşenden genişletirken yeni bir bileşen oluşturmak daha uygun olur. Bileşene özgü bir mantığın başka bir bileşene sızdırmasını önlemenize yardımcı olur. Bu özellikle ekstra davranış uygularken kullanışlıdır.

/ * Beyan * /
{{ui-button-dropdown items = öğeler}}
/ * Başlığın altında * /
{{# ui-düğmesi onClick = (eylem 'toggleDropdown')}}
  {{label}}  
{{/ Ui düğmeli}}
{{#if, genişletilmiş}}
  {{ui-dropdown items = öğeler}}
{{/Eğer}}

Yukarıdaki örnekte, düğme bileşeni kullanılmıştır. Bu, açılır bir bileşen ve görünürlük durumunu dahil ederken sabit bir simgeyi destekleme düzenini genişletir.

2 - Dekorasyon parametreleri

Yeni bileşenler oluşturmak için başka bir olası neden var. Bu, parametre kullanılabilirliğini kontrol etmek veya varsayılan değerleri dekore etmek gerektiğindedir.

/ * Beyan * /
{{form-datepicker onFocus = (eylem 'doSomething')}}
/ * Başlığın altında * /
{{form-input onFocus = (eylem '_onFocus')}}
_odaklan() {
  $ (This.element)
    .find ( 'giriş')
    .Select (); / * Odaktaki alan değerini seç * /
  this._handleCallback ( 'onFocus'); / * Param callback işlevini tetikler * /
}

Bu örnekte, bileşene alan odaklandığında çağrılması gereken bir işlev sağlanmıştır.

Dahili olarak, geri çağrıyı doğrudan temel bileşene iletmek yerine, bir iç işlevden geçer. Bu, belirli bir görevi gerçekleştirir (alan değerini seçerek) ve sonra sağlanan geri aramaları çağırır.

Temel giriş bileşeni tarafından kabul edilen tüm parametreleri yönlendirmez. Bu, belirli işlevlerin kapsamını kontrol etmeye yardımcı olur. Ayrıca gereksiz doğrulamalardan kaçınır.

Benim durumumda, onBlur olayı başka bir olayla değiştirildi - onChange. Bu, kullanıcı alanı doldurduğunda veya takvimde bir tarih seçtiğinde tetiklenir.

Sonuç

Bileşenlerinizi oluştururken, bu bileşeni günlük yaşamında kullanan kişiyi ve onun tarafını düşünün. Bu şekilde herkes kazanır.

En iyi sonuç gruptaki herkesin kendisi ve grup için en iyisini yapmasıdır - John Nash

Ayrıca, geribildirim almaktan utanmayın. Her zaman üzerinde çalışılabilecek bir şey bulacaksınız.

Yazılım mühendisliği becerilerinizi daha da geliştirmek için, Eric Elliott’in “Composing Software” serisini takip etmenizi öneririm. Bu harika!

Umarım makaleyi beğenmişsinizdir. Lütfen bu kavramları al, kendi düşüncelerine dönüştür ve bizimle paylaş!

Ayrıca, twitter @gcolombo_ adresinden bana ulaşmaktan çekinmeyin! Fikrini duymayı ve birlikte çalışmayı çok isterim.

Teşekkürler!