自动重绘系统
介绍
为了实现快速渲染,Mithril 实现了一个虚拟 DOM diff 系统,此外,还提供了各种机制来实现对渲染粒度的控制。
Mithril 的自动重绘系统,会在数据层的数据改变后,同步更改 DOM。当你调用 m.mount
后将开启自动重绘系统。当你使用 m.route
时,在调用了 m.render
后也将开启自动重绘系统。
自动重绘功能其实只是在完成某些功能后执行的重新渲染。
事件处理函数之后
Mithril 会在视图中的 DOM 事件处理函数执行完后,进行自动重绘:
var MyComponent = {
view: function() {
return m("div", {onclick: doSomething})
}
}
function doSomething() {
// 函数执行完后,同步进行重绘
}
m.mount(document.body, MyComponent)
你可以通过在事件处理函数中设置 e.redraw
为 false
来禁用该事件的自动重绘:
var MyComponent = {
view: function() {
return m("div", {onclick: doSomething})
}
}
function doSomething(e) {
e.redraw = false
// 触发该事件处理函数后,不再执行自动重绘
}
m.mount(document.body, MyComponent)
m.request 之后
Mithril 会在 m.request 完成后执行自动重绘:
m.request("/api/v1/users").then(function() {
// 函数执行完后会进行自动重绘
})
你可以把 background
设置为 true
,来禁用指定请求的自动重绘功能:
m.request("/api/v1/users", {background: true}).then(function() {
// 不再触发自动重绘
})
路由改变之后
Mithril 会在调用 m.route.set() 后,或者点击使用了 m.route.link 的链接后,执行自动重绘:
var RoutedComponent = {
view: function() {
return [
// a redraw happens asynchronously after the route changes
m("a", {href: "/", oncreate: m.route.link}),
m("div", {
onclick: function() {
m.route.set("/")
}
}),
]
}
}
m.route(document.body, "/", {
"/": RoutedComponent,
})
何时不进行重绘
Mithril 在 setTimeout
、setInterval
、requestAnimationFrame
、Promise
以及第三方库的事件处理函数(例如 Socket.io 回调)的回调中不会执行自动重绘。在这种情况下,你必须手动调用 m.redraw()。
在生命周期方法执行完后,Mithril 也不会自动重绘。在 oninit
之后部分 UI 可能会重绘,但另一部分 UI 可能在触发 oninit
时已经重绘完成。oncreate
和 onupdate
触发时 UI 已经重绘完成。
如果你希望在生命周期方法中触发重绘,可以调用 m.redraw()
,这将触发异步重绘:
var StableComponent = {
oncreate: function(vnode) {
vnode.state.height = vnode.dom.offsetHeight
m.redraw()
},
view: function() {
return m("div", "This component is " + vnode.state.height + "px tall")
}
}
Mithirl 不会对通过 m.render
渲染的 vnode 进行自动重绘。这意味着,通过 m.render
渲染的组件在触发事件和调用 m.request
后不会触发重绘。因此,如果你希望手动控制重绘发生的时机,则应该使用 m.render
而不是 m.mount
。
注意,m.render
传入的参数是一个 vnode,而 m.mount
传入的参数是一个组件:
// 使用 m.render 时需要把组件包裹在 m() 函数中
m.render(document.body, m(MyComponent))
// 使用 m.mount 时,直接传入组件即可
m.mount(document.body, MyComponent)
如果重绘的频率高于动画帧(通常为16ms),则 Mithril 会适当的避免自动重绘。这意味着,当使用 onresize
或 onscroll
这类事件时,Mithril 会自动调节重绘频率。