Kürzlich habe ich den Artikel „Neue Ideen für den Aufbau von Front-End-UI-Komponenten“ von Onkel Yu gelesen, der mich an einen Artikel erinnerte, den ich letztes Jahr geteilt hatte , „JS Design Pattern for Collaborative Development with Feelings“ , der ein wenig Anklang fand. .
Es heißt, dass ich letztes Jahr in der neuen Version des Kassiererprojekts von Alipay dieses Komponentencodierungsmodell eine Zeit lang ausprobiert habe. Hier ein paar Erfahrungen, die ich mit Ihnen teilen möchte:
Wenn Sie auf die zuvor erwähnte abstrakte Klasse zurückblicken, kommt es Schülern, die etwas über Designmuster wissen, vielleicht bekannt vor. Ja, auf den ersten Blick sieht es wie eine abstrakte Fabrik aus, aber in Kombination mit den folgenden Grundklassen werden Sie feststellen, dass ich es nicht überschrieben habe getVessel, show, hide und andere Methoden in jeder Basisklasse, erbten diese Methoden jedoch direkt in der abstrakten Klasse. Es wird definitiv Leute geben, die nicht verstehen, warum sie das tun, nur weil es JS ist, nicht JAVA. Ein gewisses Maß an Kopplung im Austausch für ausreichende Flexibilität ist meiner Meinung nach nicht übertrieben, ganz zu schweigen davon, dass diese abstrakte Klasse absolute Stabilität gewährleisten muss. Es ist notwendig, dass sie nach ihrer Bildung nicht nach Belieben geändert werden darf.
Über diese abstrakte Klasse verknüpfe ich ein Kontaktobjekt mit einem Containerobjekt und realisiere die einfachste Interaktion zwischen ihnen über die Aktionsmethode. „Das Einfachste“ bedeutet nichts anderes als Anzeige- oder Ausblendvorgänge, daher habe ich die Methoden zum Anzeigen und Ausblenden definiert. Offensichtlich kann das „einfachste“ Interaktionsverhalten nicht 100 % des Benutzerverhaltens erfüllen, daher muss ich eine setInterface-Methode festlegen und Effektklassen zu Klassen hinzufügen, die spezielle Interaktionseffekte erfordern. Vermeiden Sie schließlich die direkte Instanziierung dieser abstrakten Klasse, wenn Sie sie verwenden. Erinnern Sie alle in der Aktionsmethode daran, dass Sie, wenn Sie eine Operation instanziieren möchten, bitte zu einer bestimmten Vererbungsklasse wechseln, um die Aktionsmethode zu überschreiben.
Über diese abstrakte Klasse können wir die grundlegendsten aPop-, dropDown-, xbox- und xTab-Komponenten erben. Diese wurden bereits im vorherigen p-Artikel erwähnt. Ich werde mich hier nicht darauf konzentrieren, sie zu erklären Wenn die hier geschriebenen Grundklassen die besonderen Anforderungen nicht erfüllen können, wie können wir dann schnell personalisierte Komponenten entwickeln?
Nehmen wir xTab als Beispiel. Wir können diese Komponente verwenden, um den grundlegenden Umschalteffekt zwischen Multi-Touch-Punkten und mehreren Containern zu vervollständigen. Aber was ist, wenn wir darüber hinaus einige Animationseffekte hinzufügen müssen? Schauen wir uns zunächst den Implementierungscode der Registerkarte „Geerbte Klasse“ an:
Es kann festgestellt werden, dass ich die Methode setInterface nach der Methode show ausgeführt habe. Die gleichnamige Methode in der abstrakten Klasse wird standardmäßig aufgerufen, um zusätzliche interaktive Effektklassen für ähnliche interaktive Zeilen hinzuzufügen. Beispiel: Jetzt möchten wir uns mit dem SlideTab-Effekt befassen, dann müssen wir nur noch eine auf xTab basierende Anwendungsklasse erben, die setInterface-Methode überschreiben und eine Animationsklasse hinzufügen, um den Slide-Effekt zu erzielen, und fertig!
AP.widget.animTab = AP.widget.xTab.extend({
setInterface:function(target,vessel){
this.parent(target,vessel);
this.anim(vessel);
},
anim:function(vessel){
...
}
});
Um ehrlich zu sein, ist dies eine sehr grobe Designidee, aber sie ermöglicht es uns, den Codierungsmodus von Komponenten aus einem anderen Blickwinkel zu betrachten. Das Obige sind nur einige oberflächliche Anwendungsversuche, und die Spannung wird weitergehen ... und wartet auf Sie!
AP.widget.xTab = AP.widget.basic.extend({
bindEvents:function(target,vessel){
E.on(target,this.options.eventType,this.action,target,this);
E.on(window,'load',this.oXtab,target,this);
},
action:function(e,target){
this.switchTab(e,target);
},
switchTab:function(e,target){
...
for(i=0,len=tabs.length;i<len;i++){
var hash = tabs[i].href.split("#")[1];
var Vessel = D.get(hash + 'Extend');
if(Gefäß){
this.hide(vessel);
}
D.removeClass(tabs[i].parentNode,'current');
if(target.href == tabs[i].href){
D.addClass(target.parentNode,'current');
if(Gefäß){
this.show(vessel);
}
// Verschiedene Anwendungsschnittstellen festlegen
this.setInterface(target,vessel);
}
E.preventDefault(e);
}
},
showTab: function(index){
...
},
//Positionierungsregisterkarte initialisieren
oXtab:function(target,e){
...
}
});
AP.widget.basic = neue AP.Class({
setOptions:function(options){
//Schnittstelleneinstellungen
},
initialize:function(targets,options){
//Initialisierungsmethode. Der Zweck besteht darin, die Zuordnung zwischen Zielteilmengenelementen und einer Methode herzustellen
},
getVessel:function(target){
//Den Container abrufen, der die Zielzuordnungsbeziehung erfüllt
},
bindEvents:function(target,vessel){
//Hier die Triggeraktion des Ziels binden
},
action:function(){
//Die durch das an das Ziel gebundene Ereignis ausgelöste Ausführungsfunktion enthält die Logik, die Sie ausführen möchten.
},
show:function(){
//Container anzeigen
},
hide:function(){
//Container ausblenden
},
setInterface:function(){
//Legen Sie die von jeder Komponente gemeinsam genutzte Schnittstelle fest
}
})