Merge remote-tracking branch 'origin/next' into next
This commit is contained in:
commit
432dbe9662
9 changed files with 46 additions and 21 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Leo Horie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -28,7 +28,7 @@ It's small (< 8kb gzip), fast and provides routing and XHR utilities out of the
|
|||
<div style="animation:grow 1.35s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:68%"></div>
|
||||
</div>
|
||||
<div style="width:50%;">
|
||||
<h5>Performance</h5>
|
||||
<h5>Rendering Time</h5>
|
||||
<small>Mithril (6.4ms)</small>
|
||||
<div style="animation:grow 0.64s;background:#1e5799;height:3px;margin:0 10px 10px 0;transform-origin:0;width:24%;"></div>
|
||||
<small style="color:#aaa;">Vue (9.8ms)</small>
|
||||
|
|
@ -223,7 +223,7 @@ Basically, XHR is just a way to talk to a server.
|
|||
|
||||
Let's change our click counter to make it save data on a server. For the server, we'll use [REM](http://rem-rest-api.herokuapp.com), a mock REST API designed for toy apps like this tutorial.
|
||||
|
||||
First we create a function that calls `m.request`. The `url` specifies an endpoint that represents a resource, the `method` specifies the type of action we're taking (typically the `PUT` method [upserts](https://en.wiktionary.org/wiki/upsert)), `data` is the payload that we're sending to the endpoint and `useCredentials` means to enable cookies (a requirement for the REM API to work)
|
||||
First we create a function that calls `m.request`. The `url` specifies an endpoint that represents a resource, the `method` specifies the type of action we're taking (typically the `PUT` method [upserts](https://en.wiktionary.org/wiki/upsert)), `data` is the payload that we're sending to the endpoint and `withCredentials` means to enable cookies (a requirement for the REM API to work)
|
||||
|
||||
```javascript
|
||||
var count = 0
|
||||
|
|
@ -232,7 +232,7 @@ var increment = function() {
|
|||
method: "PUT",
|
||||
url: "http://rem-rest-api.herokuapp.com/api/tutorial/1",
|
||||
data: {count: count + 1},
|
||||
useCredentials: true,
|
||||
withCredentials: true,
|
||||
})
|
||||
.then(function(data) {
|
||||
count = parseInt(data.count)
|
||||
|
|
|
|||
|
|
@ -102,4 +102,4 @@ Note that the `onbeforeremove` hook only fires on the element that loses its `pa
|
|||
|
||||
When creating animations, it's recommended that you only use the `opacity` and `transform` CSS rules, since these can be hardware-accelerated by modern browsers and yield better performance than animating `top`, `left`, `width`, and `height`.
|
||||
|
||||
It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute postioned element over a fixed element).
|
||||
It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. If you want to animate a `box-shadow`, consider [putting the `box-shadow` rule on a pseudo element, and animate that element's opacity instead](http://tobiasahlin.com/blog/how-to-animate-box-shadow/). Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute postioned element over a fixed element).
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ m.route(document.body, "/", {
|
|||
|
||||
### When Mithril does not redraw
|
||||
|
||||
Mithril does not redraw after `setTimeout`, `setInterval`, `requestAnimationFrame` and 3rd party library event handlers (e.g. Socket.io callbacks). In those cases, you must manually call [`m.redraw()`](redraw.md).
|
||||
Mithril does not redraw after `setTimeout`, `setInterval`, `requestAnimationFrame`, raw `Promise` resolutions and 3rd party library event handlers (e.g. Socket.io callbacks). In those cases, you must manually call [`m.redraw()`](redraw.md).
|
||||
|
||||
Mithril also does not redraw after lifecycle methods. Parts of the UI may be redrawn after an `oninit` handler, but other parts of the UI may already have been redrawn when a given `oninit` handler fires. Handlers like `oncreate` and `onupdate` fire after the UI has been redrawn.
|
||||
|
||||
|
|
|
|||
|
|
@ -53,13 +53,14 @@ The easiest way to try out Mithril is to include it from a CDN, and follow this
|
|||
Let's create an HTML file to follow along:
|
||||
|
||||
```markup
|
||||
<body></body>
|
||||
<script src="http://unpkg.com/mithril/mithril.js"></script>
|
||||
<script>
|
||||
var root = document.body
|
||||
<body>
|
||||
<script src="http://unpkg.com/mithril/mithril.js"></script>
|
||||
<script>
|
||||
var root = document.body
|
||||
|
||||
// your code goes here!
|
||||
</script>
|
||||
// your code goes here!
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -106,9 +106,11 @@ var Button = {
|
|||
return m("button", {key: vnode.attrs.id}, u.name)
|
||||
}
|
||||
}
|
||||
|
||||
// PREFER
|
||||
users.map(function(u) {
|
||||
return m("div", [
|
||||
m(Button, {id: u.id}, u.name) // key should be here, not in component
|
||||
m(Button, {key: u.id}, u.name) // key should be here, not in component
|
||||
])
|
||||
})
|
||||
```
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@ We replaced each component with a [RouteResolver](route.md#routeresolver) (basic
|
|||
|
||||
The interesting thing to pay attention to is how components can be used instead of a selector string in a `m()` call. Here, in the `/list` route, we have `m(Layout, m(UserList))`. This means there's a root vnode that represents an instance of `Layout`, which has a `UserList` vnode as its only child.
|
||||
|
||||
In the `/edit/:id` route, there's also a `vnode` argument that carries the route parameters into the `UserForm` component. So if the URL is `/edit/1`, then `vnode.attrs` in this case is `{id: 1}`, and this `m(UserForm, vnode.attrs)` is equivalent to `m(UserForm, {id: 1})`. The equivalent JSX code would be `<UserForm id={vnode.attrs} />`.
|
||||
In the `/edit/:id` route, there's also a `vnode` argument that carries the route parameters into the `UserForm` component. So if the URL is `/edit/1`, then `vnode.attrs` in this case is `{id: 1}`, and this `m(UserForm, vnode.attrs)` is equivalent to `m(UserForm, {id: 1})`. The equivalent JSX code would be `<UserForm id={vnode.attrs.id} />`.
|
||||
|
||||
Refresh the page in the browser and now you'll see the global navigation on every page in the app.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
body {-webkit-text-size-adjust: 100%;}
|
||||
body,table,h5 {font:normal 16px 'Open Sans';}
|
||||
header,main {margin:auto;max-width:1000px;}
|
||||
header section {position:absolute;width:250px;}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
### What is virtual DOM
|
||||
|
||||
A virtual DOM tree is a Javascript data structure that describes a DOM tree. It consists of nested virtual DOM nodes, also known *vnodes*.
|
||||
A virtual DOM tree is a Javascript data structure that describes a DOM tree. It consists of nested virtual DOM nodes, also known as *vnodes*.
|
||||
|
||||
The first time a virtual DOM tree is rendered, it is used as a blueprint to create a DOM tree that matches its structure.
|
||||
|
||||
Typically, Virtual DOM trees are then recreated every render cycle, which normally occurs in response to event handlers or to data changes. Mithril *diffs* a vnode tree against its previous version and only modifies DOM elements in spots where there are changes.
|
||||
Typically, virtual DOM trees are then recreated every render cycle, which normally occurs in response to event handlers or to data changes. Mithril *diffs* a vnode tree against its previous version and only modifies DOM elements in spots where there are changes.
|
||||
|
||||
It may seem wasteful to recreate vnodes so frequently, but as it turns out, modern Javascript engines can create hundreds of thousands of objects in less than a millisecond. On the other hand, modifying the DOM is several orders of magnitude more expensive than creating vnodes.
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ For that reason, Mithril uses a sophisticated and highly optimized virtual DOM d
|
|||
|
||||
The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide [retained mode rendering](https://en.wikipedia.org/wiki/Retained_mode), a style of rendering that makes it drastically easier to manage UI complexity.
|
||||
|
||||
To illustrate why retained mode is so important, consider the DOM API and HTML. The DOM API is an [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) rendering system and requires writing out exact instructions to assemble a DOM tree procedurally. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances for introducing bugs and more chances to make code harder to understand.
|
||||
To illustrate why retained mode is so important, consider the DOM API and HTML. The DOM API is an [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) rendering system and requires writing out exact instructions to assemble a DOM tree procedurally. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances of introducing bugs and more chances to make code harder to understand.
|
||||
|
||||
In contrast, HTML is a retained mode rendering system. With HTML, you can write a DOM tree in a far more natural and readable way, without worrying about forgetting to append a child to a parent, running into stack overflows when rendering extremely deep trees, etc.
|
||||
|
||||
|
|
@ -35,13 +35,13 @@ Virtual DOM goes one step further than HTML by allowing you to write *dynamic* D
|
|||
|
||||
Virtual DOM nodes, or *vnodes*, are javascript objects that represent DOM elements (or parts of the DOM). Mithril's virtual DOM engine consumes a tree of vnodes to produce a DOM tree.
|
||||
|
||||
Vnodes can be created via the [`m()`](hyperscript.md) hyperscript utility:
|
||||
Vnodes are created via the [`m()`](hyperscript.md) hyperscript utility:
|
||||
|
||||
```javascript
|
||||
m("div", {id: "test"}, "hello")
|
||||
```
|
||||
|
||||
Vnodes can also consume [components](components.md):
|
||||
Hyperscript can also consume [components](components.md):
|
||||
|
||||
```javascript
|
||||
// define a component
|
||||
|
|
@ -70,8 +70,8 @@ Property | Type | Description
|
|||
`key` | `String?` | The value used to map a DOM element to its respective item in a array of data.
|
||||
`attrs` | `Object?` | A hashmap of [DOM attributes](hyperscript.md#dom-attributes), [events](hyperscript.md#events), [properties](hyperscript.md#properties) and [lifecycle methods](hyperscript.md#lifecycle-methods).
|
||||
`children` | `(Array|String|Number|Boolean)?` | In most vnode types, the `children` property is an array of vnodes. For text and trusted HTML vnodes, The `children` property is either a string, a number or a boolean.
|
||||
`text` | `(String|Number|Boolean)?` | This is used instead of `children` if a vnode contains a text node as its only child. This is done for performance reasons. Component vnodes never use the `text` property even if they have a text node as its only child.
|
||||
`dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragment and trusted HTML vnodes, `dom` points to the first element in the range.
|
||||
`text` | `(String|Number|Boolean)?` | This is used instead of `children` if a vnode contains a text node as its only child. This is done for performance reasons. Component vnodes never use the `text` property even if they have a text node as their only child.
|
||||
`dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragments and trusted HTML vnodes, `dom` points to the first element in the range.
|
||||
`domSize` | `Number?` | This is only set in fragment and trusted HTML vnodes, and it's `undefined` in all other vnode types. It defines the number of DOM elements that the vnode represents (starting from the element referenced by the `dom` property).
|
||||
`state` | `Object` | An object that is persisted between redraws. In component vnodes, `state` is a shallow clone of the component object.
|
||||
`events` | `Object?` | An object that is persisted between redraws and that stores event handlers so that they can be removed using the DOM API. The `events` property is `undefined` if there are no event handlers defined. This property is only used internally by Mithril, do not use it.
|
||||
|
|
@ -110,4 +110,4 @@ When creating libraries that emit vnodes, you should use this module instead of
|
|||
|
||||
Vnodes are supposed to represent the state of the DOM at a certain point in time. Mithril's rendering engine assumes a reused vnode is unchanged, so modifying a vnode that was used in a previous render will result in undefined behavior.
|
||||
|
||||
It is possible to reuse vnodes to prevent a diff, but it's preferable to use the `onbeforeupdate` hook to make your intent clear to other developers (or your future self).
|
||||
It is possible to reuse vnodes to prevent a diff, but it's preferable to use the `onbeforeupdate` hook to make your intent clear to other developers (or your future self).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue