Let's say I have a big list, 23,018 cities (DOM elements) on a page, the user interact with the page (searching for cities). When the user type a key to fetch data it causes page reflow. Look, the searchbar is using documentFragment to reduce redraws and repaints.
In the following experiment, I'm going to use this SearchBar component. We're filtering a big list
23,018 cities.
unit uSearchBar;
{ ╔═════════════════════════════╗
║ _______ _______ _______ ║
║ ( ____ \( )( ____ \ ║
║ | ( \/| () () || ( \/ ║
║ | (_____ | || || || (_____ ║
║ (_____ )| |(_)| |(_____ ) ║
║ ) || | | | ) | ║
║ /\____) || ) ( |/\____) | ║
║ \_______)|/ \|\_______) ║
║ component by: warleyalex ║
╚═════════════════════════════╝ }
interface
uses
SmartCL.System,
SmartCL.Components,
DataModule,
FW7, ECMA.JSON, w3C.HTML5, W3C.Console, W3C.DOM;
type
THandleArray = array of variant;
TNotifyEvent = procedure(Sender: TObject);
TSearchBar = class(TW3CustomControl)
private
{ Private declarations }
FSelected: Boolean;
FStore: Variant;
FLeft, FTop, FWidth, FHeight: variant = 0;
protected
{ Protected declarations }
procedure setSelected(Const Value:Boolean);
procedure createSearchBar;
procedure InitializeObject; override;
{ procedure ObjectReady; override; }
empty;
procedure ListItems(arrayStore: variant);
public
{ Public declarations }
published
{ Published declarations }
property store: Variant read FStore write FStore;
property SearchItems: Boolean read FSelected write setSelected;
end;
implementation
function document: variant; external "document" property;
{ ╔════════════════════════════════════════════╗
║ Insert here the Component Events Handlers ║
╚════════════════════════════════════════════╝ }
procedure SearchBarOnFocus(e: variant);
begin
var input := SMS(e.target);
input.parents(".searchbar").addClass("searchbar-active");
end;
procedure SearchBarOnClick(e: variant);
begin
var btn = SMS(e.target);
btn.parents(".searchbar").removeClass("searchbar-active");
end;
procedure SearchBarOnBlur(e: variant);
begin
var input = SMS(e.target);
input.parents(".searchbar").removeClass("searchbar-active");
end;
{ ╔═══════════════════════════════════════════════════════════════════════╗
║ ### refs ### ║
║ You can set up references / bindEvents listeners to components ║
║ This allows you to retrieve and manipulate components on the page ║ ║
╚═══════════════════════════════════════════════════════════════════════╝ }
var bindings : THandleArray =
[CLASS
element := '.searchbar input';
event := 'focus';
handler := @SearchBarOnFocus;
END,
CLASS
element := '.searchbar-cancel';
event := 'click';
handler := @SearchBarOnClick;
END,
CLASS
element := '.searchbar input';
event := 'blur';
handler := @SearchBarOnBlur;
END];
procedure bindEvents(bindings: THandleArray);
var i : integer;
begin
for i := Low(bindings) to High(bindings) do
begin
SMS(bindings[i].element).on(bindings[i].event, bindings[i].handler);
end;
end;
{ ╔════════════════╗
║ Constructor ║
╚════════════════╝ }
/*Constructor TSearchBar.create(AOwner: TW3Component;left,top,width,height: variant=0);
begin
inherited Create(AOwner);
FLeft := left;
FTop := top;
FWidth := width;
FHeight := height;
end;*/
procedure TSearchBar.ListItems(arrayStore: variant);
var
i, len: integer;
begin
len := arrayStore.length;
if len = 0 then arrayStore := "";
var myList := document.getElementById('list_'+Self.Handle.id);
var tempFrag := document.createDocumentFragment();
while (myList.firstChild <> nil) do begin
myList.removeChild(myList.firstChild);
end;
for i := 0 to len - 1 do
begin
var listItem := JHTMLLIElement(document.createElement('LI'));
listItem.setAttribute("class", "item-content");
tempFrag.appendChild(listItem);
var div0 := JHTMLDivElement(document.createElement('DIV'));
div0.setAttribute("class", "item-inner");
listItem.appendChild(div0);
var div_0 := JHTMLDivElement(document.createElement('DIV'));
div_0.setAttribute("class", "item-title");
div0.appendChild(div_0);
div_0.appendChild( JText(document.createTextNode(arrayStore[i])) );
end;
myList.appendChild(tempFrag.cloneNode(true));
end;
procedure TSearchBar.setSelected(Const Value:Boolean);
begin
//DataModule1
if value<>FSelected then
begin
FSelected:=Value;
If Value then
begin
SMS('input#search'+Self.Handle.id).on("change keyup", procedure(e: variant)
begin
var SearchIn := ( SMS('input#search'+Self.Handle.id).val() );
DataModule1.findByKey(SearchIn, Store, procedure(ds: variant)
begin
Self.ListItems(ds);
end);
end);
end;
end;
end;
{ ╔══════════════════════════════════════════════════╗
║ Insert here the innerComponent (generated code) ║
╚══════════════════════════════════════════════════╝ }
procedure TSearchBar.createSearchBar;
begin
{ ╔═══════════════════════════════════════════════════════════════════════════╗
║ Since the document fragment is in memory and not part of the main DOM ║
║ tree, appending children to it does not cause page reflow (computation ║
║ of elements position and geometry). Consequently, using documentfragments ║
║ often results in better performance. ║
╚═══════════════════════════════════════════════════════════════════════════╝ }
var docFragment: variant = JDocumentFragment(document.createDocumentFragment()); // contains all gathered nodes
var div1 := JHTMLDivElement(document.createElement('DIV'));
div1.setAttribute("class", "bar");
docFragment.appendChild(div1);
var div_0 := JHTMLDivElement(document.createElement('DIV'));
div_0.setAttribute("class", "searchbar ");
div1.appendChild(div_0);
var a := JHTMLAnchorElement(document.createElement('A'));
a.setAttribute("class", "searchbar-cancel");
div_0.appendChild(a);
var text_0 := JText(document.createTextNode("Cancel"));
a.appendChild(text_0);
var div_1 := JHTMLDivElement(document.createElement('DIV'));
div_1.setAttribute("class", "search-input");
div_0.appendChild(div_1);
var label := JHTMLLabelElement(document.createElement('LABEL'));
label.setAttribute("class", "icon icon-search");
label.setAttribute("for", "search");
div_1.appendChild(label);
var search := JHTMLInputElement(document.createElement('INPUT'));
search.setAttribute("type", "search");
search.setAttribute("id", "search"+Self.Handle.id);
search.setAttribute("placeholder", "type some city...");
div_1.appendChild(search);
//-------------------------------------------
var pageindex := JHTMLDivElement(document.createElement('DIV'));
pageindex.setAttribute("class", "content");
docFragment.appendChild(pageindex);
var pageindex1 := JHTMLDivElement(document.createElement('DIV'));
pageindex1.setAttribute("class", "list-block search-here searchbar-found");
pageindex.appendChild(pageindex1);
var list := JHTMLUListElement(document.createElement('UL'));
list.setAttribute("id", "list_"+Self.Handle.id);
pageindex1.appendChild(list);
//-----------------------------
Self.Handle.appendChild( docFragment );
end;
procedure TSearchBar.InitializeObject;
begin
inherited;
{ ╔══════════════════════════════════════════════════╗
║ this is a good place to initialize the component ║
╚══════════════════════════════════════════════════╝ }
createSearchBar;
//WriteLn (Self.Handle.id);
{ ╔═════════════════════════════════════════════════════════════════════╗
║ make the control display itself correctly when its ready in the DOM ║
╚═════════════════════════════════════════════════════════════════════╝ }
Handle.ReadyExecute(procedure()
begin
(* call createInnerComponent *)
bindEvents(bindings);
{ ╔══════════════════════════════════════════════════╗
║ some basic style attributes after render ║
╚══════════════════════════════════════════════════╝ }
Self.Handle.style['left'] := null;
Self.Handle.style['width'] := '100%';
Self.Handle.style['height'] := '100%';
end);
end;
/*procedure TSearchBar.FinalizeObject;
begin
inherited;
end;*/
Nenhum comentário:
Postar um comentário