You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -128,68 +128,92 @@ Also EFML is the first language that can be parsed into the AST which ef support
128
128
Here is an example.
129
129
130
130
```efml
131
-
Tree structure
132
-
Lines not started with >#%@.|+- are considered as comments
133
-
The escape character of EFML is '&', for prevention of conflicts with js escapes.
134
-
Except for changes of the characters, all the usage should remain the same on all versions.
135
-
this is a comment
131
+
Lines not start with >#%@.|+- are comments.
132
+
For example, this line is a comment.
133
+
The escape character of EFML is `&`, for prevention of conflicts with js escapes.
136
134
137
-
Lines starting with '>' stand for a new tag
135
+
Lines starting with '>' stand for a new tag, for example, a `div` tag can be written as:
138
136
>div
139
-
Lines with exactly one indent after a tag definition are considered to be all things belongs to the defined tag
137
+
138
+
`.` following a tag definition is the short hand for writing class names, for example:
139
+
>div.my.class.name
140
+
would be rendered as `<div class="my class name">`
141
+
142
+
Class names can have mustaches mixed together:
143
+
>div.my.{{dynamic}}.class.name
144
+
would be rendered as `<div class="my class name">` when `instance.$data.dynamic` is empty, `<div class="my dynamic class name">` when `instance.$data.dynamic` is 'dynamic'
145
+
146
+
`#` at the end of a tag definition means the reference name for this element, for example:
147
+
>div#myDiv
148
+
this `div` tag is now accessable form `instance.$refs.myDiv`.
149
+
150
+
New lines with exactly one indent after a tag definition are all things that belong to the defined tag, for example:
151
+
>div
152
+
#attribute = myAttr
153
+
%property = myProp
154
+
@event = myEventHandler
155
+
>ChildElement
140
156
141
157
Lines starting with '#' stand for attributes
142
-
Mustaches are used for binding data
143
-
Contents inside mustaches after '=' stand for the default value for this binding
144
-
Contents without mustaches stand for static data,
145
-
which means that you can not modify them through ef.js
146
-
#class = {{class = some class name}}
147
-
#style = {{attr.style = background: #ECECEC}}
148
-
#id = testdiv
158
+
159
+
This means an attribute without any parameters:
160
+
#flagattr
161
+
162
+
Contents without mustaches stand for static data:
163
+
#id = myID
149
164
#some-attr = some text
150
-
#content
151
165
152
-
Lines starting with '%' stand for properties
166
+
Mustaches are used for binding data:
167
+
#class = {{myClass}}
168
+
The element's class name can then be set via `instance.$data.myClass = 'some class names'`
169
+
170
+
Contents inside mustaches after '=' stand for the default value for this binding:
171
+
#class = {{myClass = some class name}}
172
+
#style = {{attr.style = background: #ECECEC}}
173
+
174
+
Static content and mustaches can be mixed:
175
+
#class = static and {{mixed}} classes
176
+
177
+
Lines starting with '%' stand for properties that can be accessed from the DOM object
153
178
%title = Welcome, {{name}}
154
179
%anotherProperty = text
155
180
156
-
Lines starting with '@' stand for events
157
-
Contents after ':' are considered as value to be passed to the handler
181
+
Lines starting with '@' stand for events that triggers an event handler method:
182
+
@click = clickHandler
183
+
184
+
Contents after ':' are values to be passed to the handler:
158
185
@click = updateInfo:{{binding.value}} and static value
159
-
modifier keys now can bind easily
186
+
187
+
modifier keys now can bind with predefined aliases:
160
188
@mousedown.shift.alt.ctrl.meta = select
161
-
bind to keys is also easy
189
+
190
+
bind to specific key code by writing the code directely:
162
191
@keypress.13 = submit
163
-
use '.prevent' to `preventDefault`, '.stop' to `stopPropagation`, '.stopImmediate' to `stopImmediatePropagation`
192
+
193
+
use '.prevent' for `preventDefault`, '.stop' for `stopPropagation`, '.stopImmediate' for `stopImmediatePropagation`
164
194
use '.passive' to make the event listener passive, '.!passive' to explicitly claim a non-passive listener
165
195
use '.once' to create a trigger once listener
166
196
@keydown.8.prevent.stop = stopbackspace
197
+
167
198
use '.capture' to capture an event
168
199
@submit.capture.stopImmediate = submit
169
200
170
201
Lines starting with '.' stand for text nodes
171
202
.Name: {{name}}&nJob: {{job}}
203
+
172
204
>pre
173
205
Lines starting with '|' stand for multiline text
174
206
|Line 1
175
207
|Line 2
176
208
|Line 3
177
-
>br
178
209
179
210
Lines starting with '-' stand for single node mounting point
180
211
-node1
212
+
use `instance.node1 = anotherInstance` to put another EF component right at the point.
181
213
182
214
Lines starting with '+' stand for multi node mounting point
183
215
+list1
184
-
185
-
'.' after a tag name stand for class names for this tag
186
-
>p.some.{{binding.class}}.class.names
187
-
188
-
'#' at the end of a tag name stand for the reference name of the node
189
-
Mustaches after a dot will bind to 'class' automatically
190
-
>span.{{emergency = emergency}}#notice_box
191
-
.Notice: {{notice}}
192
-
.some text
216
+
use `instance.list1.push(...newInstances)` to put other EF components here.
193
217
```
194
218
195
219
For standalone eft parser see [eft-parser](https://github.com/ClassicOldSong/eft-parser).
@@ -230,7 +254,7 @@ ef.toEFComponent(Any)
230
254
```
231
255
### Attribute Mapping
232
256
233
-
Data on ef.js components are not always that easy to access, so since v0.10.4, a stable version of attribute mapping helper is bundled with ef.js. For documents, please refer to the [comments](https://github.com/TheNeuronProject/ef-core/blob/master/src/lib/map-attrs.js#L50-L67) for now. It would be extremely useful when using with custom components and JSX.
257
+
Data on ef.js components are not always that easy to access, so since v0.10.4, a stable version of attribute mapping helper is bundled with ef.js. For documents, please refer to the [comments](https://github.com/TheNeuronProject/ef-core/blob/master/src/lib/map-attrs.js#L50-L67) for now. It would be extremely useful when using with custom components.
234
258
235
259
## Custom Components
236
260
@@ -521,52 +545,73 @@ const scope3 = {
521
545
constcomponent3=newTpl(null, scope3) // in this case the `namespaceURI` is not ignored, element is rendered under `http://some.other.ns/myns`
522
546
```
523
547
524
-
## JSX
548
+
## Initialization API
525
549
526
-
ef.js now comes with JSX support since v0.9.0. Demo [here](https://codepan.net/gist/192a1870d23e05d775d3667389162e63).
550
+
Initialization APIs are added since v0.17.0.
527
551
528
-
### JSX Fragments
552
+
**NOTE:**`state` and `$data` are not fully initialized yet upon initlization. They're passed here only for reference. You should retrive any mount point or reactive value within your handler methods.
529
553
530
-
ef.js supports JSX fragments. You can create fragments just like what you do in React:
531
-
```jsx
532
-
<>
533
-
<h1>Hello JSX!</h1>
534
-
<MyCustomComponent>Now ef.js comes withJSX fragment support!</MyCustomComponent>
535
-
</>
536
-
```
554
+
```js
555
+
importTplfrom'./template.eft'
556
+
importComponentfrom'./my-component.eft'
557
+
558
+
constApp=classextendsTpl {
559
+
560
+
// Prepare initial methods. The return value will be used as-is.
561
+
staticinitMethods(state, $data, watch) {
562
+
let count =0
563
+
return {
564
+
clickBtn() {
565
+
count +=1
566
+
$data.count= count
567
+
alert(`You have clicked ${count} times!`)
568
+
}
569
+
}
570
+
}
537
571
538
-
**Note:** JSX fragments are not always the same from ef fragments. No ef bindings can be set on JSX fragments in the meantime.
572
+
// Prepare initial data. The return value is non-reactive.
573
+
staticinitData(state, $data, watch) {
574
+
// Watch is equivalent for '$subscribe', but you have to use `watch` instead during initlization.
575
+
watch('count', ({value}) => {
576
+
console.log('Count has changed to', value)
577
+
})
539
578
540
-
### With Transpilers
579
+
return {
580
+
count:'You have not clicked.'
581
+
btnText:'Click Me!'
582
+
}
583
+
}
541
584
542
-
**Babel:** As documented [here](https://babeljs.io/docs/en/babel-preset-react), you can customize your jsx pragma when using babel. For example:
// Prepare scope. The return value will be merged and supress previous assigned values.
586
+
staticinitScope(state, $data, watch) {
587
+
return {
588
+
// In this case, all `div` will be rendered as `h1`, all `MyComponent` will be rendered as `Component`
589
+
div:'h1',
590
+
MyComponent: Component
591
+
}
592
+
}
593
+
594
+
// Notice: overriding `init` will supress all above methods.
595
+
staticinit(state, $data, watch) {
596
+
return {
597
+
methods: {},
598
+
data: {},
599
+
scope: {},
600
+
beforeMount() {},
601
+
afterMount() {},
602
+
beforeUmount() {},
603
+
afterUmount() {},
604
+
beforeDestroy() {},
605
+
afterDestroy() {},
606
+
onCreated() {}
607
+
}
608
+
}
555
609
}
556
610
```
557
611
558
-
**Buble:** A [pull request on custom `Fragment` pragma](https://github.com/bublejs/buble/pull/199) has been merged but not yet properly [documented](https://buble.surge.sh/guide/#using-the-javascript-api). Below is a correct example:
0 commit comments