Advanced Plugin Concepts
2015-11-13 17:10
351 查看
ProvidePublicAccesstoDefaultPluginSettingsAnimprovementwecan,andshould,maketothecodeaboveistoexposethedefaultpluginsettings.Thisisimportantbecauseitmakesitveryeasyforpluginuserstooverride/customizethepluginwithminimalcode.Andthisiswherewebegintotakeadvantageofthefunctionobject.
[/code]
Nowuserscanincludealinelikethisintheirscripts:
[/code]
Andnowwecancallthepluginmethodlikethisanditwilluseablueforegroundcolor:
1
[/code]
Asyoucansee,we'veallowedtheusertowriteasinglelineofcodetoalterthedefaultforegroundcoloroftheplugin.Anduserscanstillselectivelyoverridethisnewdefaultvaluewhentheywant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[/code]
linkProvidePublicAccesstoSecondaryFunctionsasApplicable
Thisitemgoeshand-in-handwiththepreviousitemandisaninterestingwaytoextendyourplugin(andtoletothersextendyourplugin).Forexample,theimplementationofourpluginmaydefineafunctioncalled"format"whichformatsthehilighttext.Ourpluginmaynowlooklikethis,withthedefaultimplementationoftheformatmethoddefinedbelowthehilightfunction:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[/code]
Wecouldhavejustaseasilysupportedanotherpropertyontheoptionsobjectthatallowedacallbackfunctiontobeprovidedtooverridethedefaultformatting.That'sanotherexcellentwaytosupportcustomizationofyourplugin.Thetechniqueshownheretakesthisastepfurtherbyactuallyexposingtheformatfunctionsothatitcanberedefined.Withthistechniqueitwouldbepossibleforotherstoshiptheirowncustomoverridesofyourplugin–inotherwords,itmeansotherscanwritepluginsforyourplugin.
Consideringthetrivialexamplepluginwe'rebuildinginthisarticle,youmaybewonderingwhenthiswouldeverbeuseful.Onereal-worldexampleistheCyclePlugin.TheCyclePluginisaslideshowpluginwhichsupportsanumberofbuilt-intransitioneffects–scroll,slide,fade,etc.Butrealistically,thereisnowaytodefineeverysingletypeofeffectthatonemightwishtoapplytoaslidetransition.Andthat'swherethistypeofextensibilityisuseful.TheCyclePluginexposesa"transitions"objecttowhichuserscanaddtheirowncustomtransitiondefinitions.It'sdefinedinthepluginlikethis:
1
2
3
4
5
[/code]
Thistechniquemakesitpossibleforotherstodefineandshiptransitiondefinitionsthatplug-intotheCyclePlugin.
linkKeepPrivateFunctionsPrivate
Thetechniqueofexposingpartofyourplugintobeoverriddencanbeverypowerful.Butyouneedtothinkcarefullyaboutwhatpartsofyourimplementationtoexpose.Onceit'sexposed,youneedtokeepinmindthatanychangestothecallingargumentsorsemanticsmaybreakbackwardcompatibility.Asageneralrule,ifyou'renotsurewhethertoexposeaparticularfunction,thenyouprobablyshouldn't.
Sohowthendowedefinemorefunctionswithoutclutteringthenamespaceandwithoutexposingtheimplementation?Thisisajobforclosures.Todemonstrate,we'lladdanotherfunctiontoourplugincalled"debug".Thedebugfunctionwilllogthenumberofselectedelementstotheconsole.Tocreateaclosure,wewraptheentireplugindefinitioninafunction(asdetailedinthejQueryAuthoringGuidelines).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[/code]
Our"debug"methodcannotbeaccessedfromoutsideoftheclosureandthusisprivatetoourimplementation.
linkBobandSue
Let'ssayBobhascreatedawickednewgalleryplugin(called"superGallery")whichtakesalistofimagesandmakesthemnavigable.Bob'sthrowninsomeanimationtomakeitmoreinteresting.He'striedtomakethepluginascustomizableaspossible,andhasendedupwithsomethinglikethis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[/code]
Thefirstthingthatprobablycomestoyourmind(OK,maybenotthefirst)istheprospectofhowhugethispluginmustbetoaccommodatesuchalevelofcustomization.Theplugin,ifitweren'tfictional,wouldprobablybealotlargerthannecessary.Thereareonlysomanykilobytespeoplewillbewillingtospend!
Now,ourfriendBobthinksthisisallfine;infact,he'squiteimpressedwiththepluginanditslevelofcustomization.Hebelievesthatalltheoptionsmakeforamoreversatilesolution,onewhichcanbeusedinmanydifferentsituations.
Sue,anotherfriendofours,hasdecidedtousethisnewplugin.Shehassetupalloftheoptionsrequiredandnowhasaworkingsolutionsittinginfrontofher.It'sonlyfiveminuteslater,afterplayingwiththeplugin,thatsherealizesthegallerywouldlookmuchnicerifeachimage'swidthwereanimatedataslowerspeed.ShehastilysearchesthroughBob'sdocumentationbutfindsnoanimateWidthDurationoption!
linkDoYouSeeTheProblem?
It'snotreallyabouthowmanyoptionsyourpluginhas;butwhatoptionsithas!
Bobhasgonealittleoverthetop.Thelevelofcustomizationhe'soffering,whileitmayseemhigh,isactuallyquitelow,especiallyconsideringallthepossiblethingsonemightwanttocontrolwhenusingthisplugin.Bobhasmadethemistakeofofferingalotofridiculouslyspecificoptions,renderinghispluginmuchmoredifficulttocustomize!
linkABetterModel
Soit'sprettyobvious:Bobneedsanewcustomizationmodel,onewhichdoesnotrelinquishcontrolorabstractawaythenecessarydetails.
ThereasonBobissodrawntothishigh-levelsimplicityisthatthejQueryframeworkverymuchlendsitselftothismindset.OfferingapreviousButtonTextColoroptionisniceandsimple,butlet'sfaceit,thevastmajorityofpluginusersaregoingtowantwaymorecontrol!
Hereareafewtipswhichshouldhelpyoucreateabettersetofcustomizableoptionsforyourplugins:
linkDon'tCreatePlugin-specificSyntax
Developerswhouseyourpluginshouldn'thavetolearnanewlanguageorterminologyjusttogetthejobdone.
Bobthoughthewasofferingmaximumcustomizationwithhisdelayoption(lookabove).Hemadeitsothatwithhispluginyoucanspecifyfourdifferentdelays,"quiteshort,""veryshort,""quitelong,"or"verylong":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[/code]
Notonlydoesthislimitthelevelofcontrolpeoplehave,butittakesupquiteabitofspace.Twelvelinesofcodejusttodefinethedelaytimeisabitmuch,don'tyouthink?Abetterwaytoconstructthisoptionwouldbetoletpluginusersspecifytheamountoftime(inmilliseconds)asanumber,sothatnoprocessingoftheoptionneedstotakeplace.
Thekeyhereisnottodiminishthelevelofcontrolthroughyourabstraction.Yourabstraction,whateveritis,canbeassimplisticasyouwant,butmakesurethatpeoplewhouseyourpluginwillstillhavethatmuch-sought-afterlow-levelcontrol!(Bylow-levelImeannon-abstracted.)
linkGiveFullControlofElements
IfyourplugincreateselementstobeusedwithintheDOM,thenit'sagoodideatoofferpluginuserssomewaytoaccessthoseelements.SometimesthismeansgivingcertainelementsIDsorclasses.Butnotethatyourpluginshouldn'trelyonthesehooksinternally:
Abadimplementation:
1
2
3
4
[/code]
Toallowuserstoaccessandevenmanipulatethatinformation,youcanstoreitinavariablecontainingthesettingsofyourplugin.Abetterimplementationofthepreviouscodeisshownbelow:
1
2
3
4
5
6
7
[/code]
Noticethatwe'vecreatedareferencetotheinjectedwrapperandwe'realsocallingthe
1
2
3
4
5
6
7
8
9
10
[/code]
The$.extend()methodwillnowrecursethroughallnestedobjectstogiveusamergedversionofboththedefaultsandthepassedoptions,givingthepassedoptionsprecedence.
ThepluginusernowhasthepowertospecifyanyattributeofthatwrapperelementsoiftheyrequirethattherebeahookforanyCSSstylesthentheycanquiteeasilyaddaclassorchangethenameoftheIDwithouthavingtogodiggingaroundinpluginsource.
ThesamemodelcanbeusedtolettheuserdefineCSSstyles:
1
2
3
4
5
6
7
8
9
10
[/code]
YourpluginmayhaveanassociatedstylesheetwheredeveloperscanaddCSSstyles.Eveninthissituationit'sagoodideatooffersomeconvenientwayofsettingstylesinJavaScript,withouthavingtouseaselectortogetattheelements.
linkProvideCallbackCapabilities
Whatisacallback?–Acallbackisessentiallyafunctiontobecalledlater,normallytriggeredbyanevent.It'spassedasanargument,usuallytotheinitiatingcallofacomponent,inthiscase,ajQueryplugin.
Ifyourpluginisdrivenbyeventsthenitmightbeagoodideatoprovideacallbackcapabilityforeachevent.Plus,youcancreateyourowncustomeventsandthenprovidecallbacksforthose.Inthisgallerypluginitmightmakesensetoaddan"onImageShow"callback.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[/code]
Insteadofinitiatingthecallbackviatraditionalmeans(addingparenthesis)we'recallingitinthecontextof
1
2
3
4
5
6
7
[/code]
Similarlyyoucouldaddan"onImageHide"callbackandnumerousotherones.Thepointofcallbacksistogivepluginusersaneasywaytoaddadditionalfunctionalitywithoutdiggingaroundinthesource.
linkRemember,It'saCompromise
Yourpluginisnotgoingtobeabletoworkineverysituation.Andequally,it'snotgoingtobeveryusefulifyouoffernoorveryfewmethodsofcontrol.So,remember,it'salwaysgoingtobeacompromise.Threethingsyoumustalwaystakeintoaccountare:
Flexibility:Howmanysituationswillyourpluginbeabletodealwith?
Size:Doesthesizeofyourplugincorrespondtoitsleveloffunctionality?I.e.Wouldyouuseaverybasictooltippluginifitwas20kinsize?–Probablynot!
Performance:Doesyourpluginheavilyprocesstheoptionsinanyway?Doesthisaffectspeed?Istheoverheadcausedworthitfortheenduser?
//Plugindefinition.
$.fn.hilight=function(options){
//Extendourdefaultoptionswiththoseprovided.
//Notethatthefirstargumenttoextendisanempty
//object–thisistokeepfromoverridingour"defaults"object.
varopts=$.extend({},$.fn.hilight.defaults,options);
//Ourpluginimplementationcodegoeshere.
};
//Plugindefaults–addedasapropertyonourpluginfunction.
$.fn.hilight.defaults={
foreground:"red",
background:"yellow"
};
[/code]
Nowuserscanincludealinelikethisintheirscripts:
//Thisneedsonlybecalledonceanddoesnot
//havetobecalledfromwithina"ready"block
$.fn.hilight.defaults.foreground="blue";
[/code]
Andnowwecancallthepluginmethodlikethisanditwilluseablueforegroundcolor:
1
$("#myDiv").hilight();
[/code]
Asyoucansee,we'veallowedtheusertowriteasinglelineofcodetoalterthedefaultforegroundcoloroftheplugin.Anduserscanstillselectivelyoverridethisnewdefaultvaluewhentheywant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Overrideplugindefaultforegroundcolor.
$.fn.hilight.defaults.foreground="blue";
//...
//Invokepluginusingnewdefaults.
$(".hilightDiv").hilight();
//...
//Overridedefaultbypassingoptionstopluginmethod.
$("#green").hilight({
foreground:"green"
});
[/code]
Thisitemgoeshand-in-handwiththepreviousitemandisaninterestingwaytoextendyourplugin(andtoletothersextendyourplugin).Forexample,theimplementationofourpluginmaydefineafunctioncalled"format"whichformatsthehilighttext.Ourpluginmaynowlooklikethis,withthedefaultimplementationoftheformatmethoddefinedbelowthehilightfunction:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Plugindefinition.
$.fn.hilight=function(options){
//Iterateandreformateachmatchedelement.
returnthis.each(function(){
varelem=$(this);
//...
varmarkup=elem.html();
//Callourformatfunction.
markup=$.fn.hilight.format(markup);
elem.html(markup);
});
};
//Defineourformatfunction.
$.fn.hilight.format=function(txt){
return"<strong>"+txt+"</strong>";
};
[/code]
Wecouldhavejustaseasilysupportedanotherpropertyontheoptionsobjectthatallowedacallbackfunctiontobeprovidedtooverridethedefaultformatting.That'sanotherexcellentwaytosupportcustomizationofyourplugin.Thetechniqueshownheretakesthisastepfurtherbyactuallyexposingtheformatfunctionsothatitcanberedefined.Withthistechniqueitwouldbepossibleforotherstoshiptheirowncustomoverridesofyourplugin–inotherwords,itmeansotherscanwritepluginsforyourplugin.
Consideringthetrivialexamplepluginwe'rebuildinginthisarticle,youmaybewonderingwhenthiswouldeverbeuseful.Onereal-worldexampleisthe
1
2
3
4
5
$.fn.cycle.transitions={
//...
};
[/code]
Thistechniquemakesitpossibleforotherstodefineandshiptransitiondefinitionsthatplug-intotheCyclePlugin.
Thetechniqueofexposingpartofyourplugintobeoverriddencanbeverypowerful.Butyouneedtothinkcarefullyaboutwhatpartsofyourimplementationtoexpose.Onceit'sexposed,youneedtokeepinmindthatanychangestothecallingargumentsorsemanticsmaybreakbackwardcompatibility.Asageneralrule,ifyou'renotsurewhethertoexposeaparticularfunction,thenyouprobablyshouldn't.
Sohowthendowedefinemorefunctionswithoutclutteringthenamespaceandwithoutexposingtheimplementation?Thisisajobforclosures.Todemonstrate,we'lladdanotherfunctiontoourplugincalled"debug".Thedebugfunctionwilllogthenumberofselectedelementstotheconsole.Tocreateaclosure,wewraptheentireplugindefinitioninafunction(asdetailedinthejQueryAuthoringGuidelines).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Createclosure.
(function($){
//Plugindefinition.
$.fn.hilight=function(options){
debug(this);
//...
};
//Privatefunctionfordebugging.
functiondebug(obj){
if(window.console&&window.console.log){
window.console.log("hilightselectioncount:"+obj.length);
}
};
//...
//Endofclosure.
})(jQuery);
[/code]
Our"debug"methodcannotbeaccessedfromoutsideoftheclosureandthusisprivatetoourimplementation.
Let'ssayBobhascreatedawickednewgalleryplugin(called"superGallery")whichtakesalistofimagesandmakesthemnavigable.Bob'sthrowninsomeanimationtomakeitmoreinteresting.He'striedtomakethepluginascustomizableaspossible,andhasendedupwithsomethinglikethis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
jQuery.fn.superGallery=function(options){
//Bob'sdefaultsettings:
vardefaults={
textColor:"#000",
backgroundColor:"#fff",
fontSize:"1em",
delay:"quitelong",
getTextFromTitle:true,
getTextFromRel:false,
getTextFromAlt:false,
animateWidth:true,
animateOpacity:true,
animateHeight:true,
animationDuration:500,
clickImgToGoToNext:true,
clickImgToGoToLast:false,
nextButtonText:"next",
previousButtonText:"previous",
nextButtonTextColor:"red",
previousButtonTextColor:"red"
};
varsettings=$.extend({},defaults,options);
returnthis.each(function(){
//Plugincodewouldgohere...
});
};
[/code]
Thefirstthingthatprobablycomestoyourmind(OK,maybenotthefirst)istheprospectofhowhugethispluginmustbetoaccommodatesuchalevelofcustomization.Theplugin,ifitweren'tfictional,wouldprobablybealotlargerthannecessary.Thereareonlysomanykilobytespeoplewillbewillingtospend!
Now,ourfriendBobthinksthisisallfine;infact,he'squiteimpressedwiththepluginanditslevelofcustomization.Hebelievesthatalltheoptionsmakeforamoreversatilesolution,onewhichcanbeusedinmanydifferentsituations.
Sue,anotherfriendofours,hasdecidedtousethisnewplugin.Shehassetupalloftheoptionsrequiredandnowhasaworkingsolutionsittinginfrontofher.It'sonlyfiveminuteslater,afterplayingwiththeplugin,thatsherealizesthegallerywouldlookmuchnicerifeachimage'swidthwereanimatedataslowerspeed.ShehastilysearchesthroughBob'sdocumentationbutfindsnoanimateWidthDurationoption!
It'snotreallyabouthowmanyoptionsyourpluginhas;butwhatoptionsithas!
Bobhasgonealittleoverthetop.Thelevelofcustomizationhe'soffering,whileitmayseemhigh,isactuallyquitelow,especiallyconsideringallthepossiblethingsonemightwanttocontrolwhenusingthisplugin.Bobhasmadethemistakeofofferingalotofridiculouslyspecificoptions,renderinghispluginmuchmoredifficulttocustomize!
Soit'sprettyobvious:Bobneedsanewcustomizationmodel,onewhichdoesnotrelinquishcontrolorabstractawaythenecessarydetails.
ThereasonBobissodrawntothishigh-levelsimplicityisthatthejQueryframeworkverymuchlendsitselftothismindset.OfferingapreviousButtonTextColoroptionisniceandsimple,butlet'sfaceit,thevastmajorityofpluginusersaregoingtowantwaymorecontrol!
Hereareafewtipswhichshouldhelpyoucreateabettersetofcustomizableoptionsforyourplugins:
Developerswhouseyourpluginshouldn'thavetolearnanewlanguageorterminologyjusttogetthejobdone.
Bobthoughthewasofferingmaximumcustomizationwithhisdelayoption(lookabove).Hemadeitsothatwithhispluginyoucanspecifyfourdifferentdelays,"quiteshort,""veryshort,""quitelong,"or"verylong":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
vardelayDuration=0;
switch(settings.delay){
case"veryshort":
delayDuration=100;
break;
case"quiteshort":
delayDuration=200;
break;
case"quitelong":
delayDuration=300;
break;
case"verylong":
delayDuration=400;
break;
default:
delayDuration=200;
}
[/code]
Notonlydoesthislimitthelevelofcontrolpeoplehave,butittakesupquiteabitofspace.Twelvelinesofcodejusttodefinethedelaytimeisabitmuch,don'tyouthink?Abetterwaytoconstructthisoptionwouldbetoletpluginusersspecifytheamountoftime(inmilliseconds)asanumber,sothatnoprocessingoftheoptionneedstotakeplace.
Thekeyhereisnottodiminishthelevelofcontrolthroughyourabstraction.Yourabstraction,whateveritis,canbeassimplisticasyouwant,butmakesurethatpeoplewhouseyourpluginwillstillhavethatmuch-sought-afterlow-levelcontrol!(Bylow-levelImeannon-abstracted.)
IfyourplugincreateselementstobeusedwithintheDOM,thenit'sagoodideatoofferpluginuserssomewaytoaccessthoseelements.SometimesthismeansgivingcertainelementsIDsorclasses.Butnotethatyourpluginshouldn'trelyonthesehooksinternally:
Abadimplementation:
1
2
3
4
//Plugincode
$("<divclass='gallery-wrapper'/>").appendTo("body");
$(".gallery-wrapper").append("...");
[/code]
Toallowuserstoaccessandevenmanipulatethatinformation,youcanstoreitinavariablecontainingthesettingsofyourplugin.Abetterimplementationofthepreviouscodeisshownbelow:
1
2
3
4
5
6
7
//Retainaninternalreference:
varwrapper=$("<div/>")
.attr(settings.wrapperAttrs)
.appendTo(settings.container);
//Easytoreferencelater...
wrapper.append("...");
[/code]
Noticethatwe'vecreatedareferencetotheinjectedwrapperandwe'realsocallingthe
.attr()methodtoaddanyspecifiedattributestotheelement.So,inoursettingsitmightbehandledlikethis:
1
2
3
4
5
6
7
8
9
10
vardefaults={
wrapperAttrs:{
class:"gallery-wrapper"
},
//...restofsettings...
};
//Wecanusetheextendmethodtomergeoptions/settingsasusual:
//ButwiththeaddedfirstparameterofTRUEtosignifyaDEEPCOPY:
varsettings=$.extend(true,{},defaults,options);
[/code]
The$.extend()methodwillnowrecursethroughallnestedobjectstogiveusamergedversionofboththedefaultsandthepassedoptions,givingthepassedoptionsprecedence.
ThepluginusernowhasthepowertospecifyanyattributeofthatwrapperelementsoiftheyrequirethattherebeahookforanyCSSstylesthentheycanquiteeasilyaddaclassorchangethenameoftheIDwithouthavingtogodiggingaroundinpluginsource.
ThesamemodelcanbeusedtolettheuserdefineCSSstyles:
1
2
3
4
5
6
7
8
9
10
vardefaults={
wrapperCSS:{},
//...restofsettings...
};
//Lateroninthepluginwherewedefinethewrapper:
varwrapper=$("<div/>")
.attr(settings.wrapperAttrs)
.css(settings.wrapperCSS)//**SetCSS!
.appendTo(settings.container);
[/code]
YourpluginmayhaveanassociatedstylesheetwheredeveloperscanaddCSSstyles.Eveninthissituationit'sagoodideatooffersomeconvenientwayofsettingstylesinJavaScript,withouthavingtouseaselectortogetattheelements.
Whatisacallback?–Acallbackisessentiallyafunctiontobecalledlater,normallytriggeredbyanevent.It'spassedasanargument,usuallytotheinitiatingcallofacomponent,inthiscase,ajQueryplugin.
Ifyourpluginisdrivenbyeventsthenitmightbeagoodideatoprovideacallbackcapabilityforeachevent.Plus,youcancreateyourowncustomeventsandthenprovidecallbacksforthose.Inthisgallerypluginitmightmakesensetoaddan"onImageShow"callback.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
vardefaults={
//Wedefineanemptyanonymousfunctionsothat
//wedon'tneedtocheckitsexistencebeforecallingit.
onImageShow:function(){},
//...restofsettings...
};
//Lateronintheplugin:
nextButton.on("click",showNextImage);
functionshowNextImage(){
//Returnsreferencetothenextimagenode
varimage=getNextImage();
//Stufftoshowtheimagehere...
//Here'sthecallback:
settings.onImageShow.call(image);
}
[/code]
Insteadofinitiatingthecallbackviatraditionalmeans(addingparenthesis)we'recallingitinthecontextof
imagewhichwillbeareferencetotheimagenode.Thismeansthatyouhaveaccesstotheactualimagenodethroughthe
thiskeywordwithinthecallback:
1
2
3
4
5
6
7
$("ul.imgsli").superGallery({
onImageShow:function(){
$(this).after("<span>"+$(this).attr("longdesc")+"</span>");
},
//...otheroptions...
});
[/code]
Similarlyyoucouldaddan"onImageHide"callbackandnumerousotherones.Thepointofcallbacksistogivepluginusersaneasywaytoaddadditionalfunctionalitywithoutdiggingaroundinthesource.
Yourpluginisnotgoingtobeabletoworkineverysituation.Andequally,it'snotgoingtobeveryusefulifyouoffernoorveryfewmethodsofcontrol.So,remember,it'salwaysgoingtobeacompromise.Threethingsyoumustalwaystakeintoaccountare:
Flexibility:Howmanysituationswillyourpluginbeabletodealwith?
Size:Doesthesizeofyourplugincorrespondtoitsleveloffunctionality?I.e.Wouldyouuseaverybasictooltippluginifitwas20kinsize?–Probablynot!
Performance:Doesyourpluginheavilyprocesstheoptionsinanyway?Doesthisaffectspeed?Istheoverheadcausedworthitfortheenduser?
相关文章推荐
- SpringMVC常用注解,返回方式,路径匹配形式,验证
- spring bean setter属性注入
- Debug与Release
- Python 类属性的理解
- Ngui忽略ui界面的物体
- web项目接入cas单点登陆
- 当我们谈开机的时候我们在谈论些什么
- tornado 学习笔记10 Web应用中模板(Template)的工作流程分析
- hibernate一对一外键单向关联
- 【C语言】 实现strncat
- QQ音乐远程控制,旧iPhone连音响当播放器,另一个手机远程控制
- android开发的一些网址
- didReceiveMemoryWarning-内存警告处理方法
- JAVA学习9_@SuppressWarnings注解用法详解
- iOS编程中的内存管理方式
- CSS 伪类与伪元素
- css代码之所以初始化
- python 判断内网IP方法及实例应用
- 1)①爬取中国新闻网科技相关部分新闻
- Java单机爬虫