Introduction to Drop 0.2 (Draft)
Introduction to Drop 0.2 (Draft)
Drop is an MV* framework targeting mobile web apps. It is designed for reasonable performance and generic syntax.
The core concept of Drop is decorator. It is quite similar to directive in Angular, but it will be compiled to elements instead of attributes so it will allow faster detection in a larger template using native getElementsByTagName API.
Since Angular 2, things are getting better and simpler. This is what Drop has been designed for since 0.1, and Drop 0.2 just lead the design to the next level.
Generic and Beautiful Template Syntax
In Angular 2, there's [...] for properties and (...) for events. It's great because it makes confusing expressions and statements more difficult.
However, Drop does it in a better way. As the core concept in Drop is decorator, every kind of decorator shares the same syntax. Whether the following sentence is an expression or a statement is not determined by the type of decorator, but the sentence given.
Decorator Types
There are several types of decorators in Drop, and doing different kind of works.
Processors
_Processor_ is the most frequently used decorator in Drop, and they are written without a "type marker".
E.g., if we have a processor called tap-link which redirect current page to a path given when the user taps its target element or elements, we may write something like this:
[tap-link "/new-path"]
<button>Redirect</button>
If this processor accept second parameter as an indicator of whether to open the link in a new tab, we may write something like this:
[tap-link "/new-path", true]
<button>Open</button>
Or if this processor takes an object as options, we may need to write something like this:
[tap-link "/new-path", {
open: true
}]
<button>Open</button>
See Write Processors.
_Attribute processor_ is a special kind of processor that deals with attribute binding.
To bind an attribute, we can do somthing like this (and yes it supports ES6 string template):
[@line-height `${lineHeight}px`]
<span></span>
[@style.height `${height}px`]
[@style.width `${width}px`]
<div></div>
[@style {
"line-height": `${lineHeight}px`,
"color": `${paragraphColor}px`
}]
<p></p>
_Event processor_ is another special kind of processor that deals with event handling.
To bind a handler to a specific event, we can do something like this:
[+click onClickFn]
<button>Click</button>
Or if we want the following sentence to be a statement instead of an expression that will be evaluated immediately after every updates, we may write something like this:
[+click :alert('click!')]
<button>Click</button>
The : before the sentence tells Drop that it is a statement instead of an expression.
This could also apply to any other decorators.
But what if we want to handle some special events like tap or other gestures? Actually we may use a processor to handle, but to make the code more readable, Drop provides a way to register these special events. So if related special event processors are found, Drop will give you a chance to initialize necessary logic.
See Customize Events.
Modifiers
_Modifier_ is even more powerful than processors, a common use case is the each modifier, which repeat the decorator target. Modifiers may create its own scope and it won't process the HTML template until the logic inside asks.
<ul>
[each list]
[+click "a", :alert(this.innerText)]
<li>
[@href url]
<a>{text}</a>
</li>
</ul>
See Write Modifiers.
You may noticed {text} in this example, we'll come to that later (but I think you have already understood what it does).
One-time Evaluation
For better performance, we may reduce the amount of change listeners by using one-time evaluation. Expressions start with :: would not react the changes of variables in themselves:
[@font-size ::`${fontSize}px`]
<div>{::text}</div>
Alternative Syntax
Sometimes it would be more intuitive to write these decorators as attributes, so Drop enables you to do so.
<div
%processorOrModifier="[argA, argB]"
@attribute="string literal"
+event=":statement"
></div>
Of course the notation is also generic. And if there's no space in your [expression], you may write it as:
<div @attribute=[value]></div>
Decorator Flow
Decorator flow is a mechanism that allows decorators to share or pass information so that multiple decorators will be able to cooperate.
For example:
[if condition]
<div>yes</div>
[else-if otherCondition]
<div>whatever</div>
[else]
<div>no</div>
Decorator Target with Multiple Elements
As you may have noticed, all decorators decorate only a single target follows. To decorate more than one element, you may use <dp:wrapper></dp:wrapper> to wrap them up.
[each list]
<dp:wrapper>
<span>{text}</span>
<a @href="[url]">{url}</a>
</dp:wrapper>
And of course it won't be in the final DOM tree.
Components
As decorators are applied to decorator targets. Components, on the other hand, can be treated as decorator targets, and may contains decorators (and their targets) itself.
Text and HTML Components
Text and HTML components are the most basic components built-in, and have specified syntax for more frequent usage.
For usage of text:
<div>
<h1>{title}</h1>
<p>{content}</p>
</div>
Or with filter:
<div>{new Date() | date-time}</div>
For direct HTML output (do consider XSS risks when using this):
<div>{=htmlContent}</div>
General Components
Components are playing a more and more important role in web development. Assuming we have a component named timer and accepts property total as a number and start-immediately as a boolean, we may want to write something like this:
<div>
<timer total="60" start-immediately="true" />
</div>
See Write Components.
Scopes
Drop shares similar scope (closure) logic with JavaScript. It searches variable from the current scope and up, and finally reaches JavaScript global scope. And this is used as a reference of the current scope (might also be any value includes primitives).
So the example of each can be written as:
<ul>
[each list]
<li>
[@href this.url]
<a>{this.text}</a>
</li>
</ul>
It's not exactly the same as when using this, it tries only to search the variable under current scope.