mithril 组件学习记录
基本组件:
var Example = {
view: function() {
return m("div", "Hello")
}
}
m(Example)
组件传递参数:
var Example = {
view: function (vnode) {
return m("div", "Hello, " + vnode.attrs.name)
}
}
m(Example, {name: "Floyd"})
组件事件函数:
定义在组件内部的函数 oninit, oncreate, onupdate, onbeforeremove, onremove and onbeforeupdate.
var ComponentWithHooks = {
oninit: function(vnode) {
console.log("initialized")
},
oncreate: function(vnode) {
console.log("DOM created")
},
onupdate: function(vnode) {
console.log("DOM updated")
},
onbeforeremove: function(vnode) {
console.log("exit animation can start")
return new Promise(function(resolve) {
// call after animation completes
resolve()
})
},
onremove: function(vnode) {
console.log("removing DOM element")
},
onbeforeupdate: function(vnode, old) {
return true
},
view: function(vnode) {
return "hello"
}
}
也可以指定外部函数作为事件函数:
function initialize() {
console.log("initialized as vnode")
}
m(ComponentWithHooks, {oninit: initialize})
在组件内部定义变量:
function closureComponent(vnode) {
// vnode.state is undefined at this point
var kind = "closure component"
return {
view: function() {
return m("div", "Hello from a " + kind)
},
oncreate: function() {
console.log("We've created a " + kind)
}
}
}
利用 State 存储数据:
var ComponentWithInitialState = {
data: "Initial content",
view: function(vnode) {
return m("div", vnode.state.data)
}
}
m(ComponentWithInitialState)
给 state 赋值
var ComponentWithDynamicState = {
oninit: function(vnode) {
vnode.state.data = vnode.attrs.text
},
view: function(vnode) {
return m("div", vnode.state.data)
}
}
m(ComponentWithDynamicState, {text: "Hello"})
也可以通过关键字this 来访问state
var ComponentUsingThis = {
oninit: function(vnode) {
this.data = vnode.attrs.text
},
view: function(vnode) {
return m("div", this.data)
}
}
m(ComponentUsingThis, {text: "Hello"})
避免过于庞大的组件
// 应该避免下面的大组件
var Login = {
username: "",
password: "",
setUsername: function(value) {
this.username = value
},
setPassword: function(value) {
this.password = value
},
canSubmit: function() {
return this.username !== "" && this.password !== ""
},
login: function() {/*...*/},
view: function() {
return m(".login", [
m("input[type=text]", {oninput: m.withAttr("value", this.setUsername.bind(this)), value: this.username}),
m("input[type=password]", {oninput: m.withAttr("value", this.setPassword.bind(this)), value: this.password}),
m("button", {disabled: !this.canSubmit(), onclick: this.login}, "Login"),
])
}
}
定义的组件应该能复用
// models/Auth.js
// PREFER
var Auth = {
username: "",
password: "",
setUsername: function(value) {
Auth.username = value
},
setPassword: function(value) {
Auth.password = value
},
canSubmit: function() {
return Auth.username !== "" && Auth.password !== ""
},
login: function() {/*...*/},
}
module.exports = Auth
// views/Login.js
// PREFER
var Auth = require("../models/Auth")
var Login = {
view: function() {
return m(".login", [
m("input[type=text]", {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}),
m("input[type=password]", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}),
m("button", {disabled: !Auth.canSubmit(), onclick: Auth.login}, "Login"),
])
}
}
避免把属性写死
// button 的onclick 属性写死了
var RestrictiveComponent = {
view: function(vnode) {
return m("button", {onclick: vnode.attrs.onclick}, [
"Click to " + vnode.attrs.text
])
}
}
// 应该传入属性
var FlexibleComponent = {
view: function(vnode) {
return m("button", vnode.attrs, [
"Click to ", vnode.children
])
}
}
避免操作children
// 避免
var Header = {
view: function(vnode) {
return m(".section", [
m(".header", vnode.children[0]),
m(".tagline", vnode.children[1]),
])
}
}
m(Header, [
m("h1", "My title"),
m("h2", "Lorem ipsum"),
])
// awkward consumption use case
m(Header, [
[
m("h1", "My title"),
m("small", "A small note"),
],
m("h2", "Lorem ipsum"),
])
// 应该
var BetterHeader = {
view: function(vnode) {
return m(".section", [
m(".header", vnode.attrs.title),
m(".tagline", vnode.attrs.tagline),
])
}
}
m(BetterHeader, {
title: m("h1", "My title"),
tagline: m("h2", "Lorem ipsum"),
})
// clearer consumption use case
m(BetterHeader, {
title: [
m("h1", "My title"),
m("small", "A small note"),
],
tagline: m("h2", "Lorem ipsum"),
})
静态定义组件,动态调用它们
// 避免
var ComponentFactory = function(greeting) {
// creates a new component on every call
return {
view: function() {
return m("div", greeting)
}
}
}
m.render(document.body, m(ComponentFactory("hello")))
// calling a second time recreates div from scratch rather than doing nothing
m.render(document.body, m(ComponentFactory("hello")))
// 应该
var Component = {
view: function(vnode) {
return m("div", vnode.attrs.greeting)
}
}
m.render(document.body, m(Component, {greeting: "hello"}))
// calling a second time does not modify DOM
m.render(document.body, m(Component, {greeting: "hello"}))
避免在view 之外创建组件实例
// AVOID
var Counter = {
count: 0,
view: function(vnode) {
return m("div",
m("p", "Count: " + vnode.state.count ),
m("button", {
onclick: function() {
vnode.state.count++
}
}, "Increase count")
)
}
}
var counter = m(Counter)
m.mount(document.body, {
view: function(vnode) {
return [
m("h1", "My app"),
counter
]
}
})
// PREFER
var Counter = {
count: 0,
view: function(vnode) {
return m("div",
m("p", "Count: " + vnode.state.count ),
m("button", {
onclick: function() {
vnode.state.count++
}
}, "Increase count")
)
}
}
m.mount(document.body, {
view: function(vnode) {
return [
m("h1", "My app"),
m(Counter)
]
}
})
0
See Also
Nearby
- 上一篇 › mithril 路由学习笔记
- 下一篇 › tachyons CSS 框架不错,准备用它来改youBBS theme