Skip to content
Mithril.js 2
Main Navigation 指南API

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

外觀

Sidebar Navigation

API

核心 API

m(selector, attributes, children)

render(element, vnodes)

mount(root, component)

route(root, defaultRoute, routes)

request(options)

parseQueryString(string)

buildQueryString(object)

buildPathname(object)

parsePathname(string)

trust(html)

fragment(attrs, children)

redraw()

censor(object, extra)

可選 API

stream()

指南

本頁導覽

m(selector, attributes, children) ​

描述 ​

表示 Mithril.js 視圖中的 HTML 元素

javascript
m('div.foo', { style: { color: 'red' } }, 'hello');
// 渲染為以下 HTML:
// <div class="foo" style="color: red">hello</div>

您也可以使用類似 HTML 的語法,稱為 JSX,並使用 Babel 將其轉換為等效的 hyperscript 調用。這與上面的範例等效。

jsx
<div class="foo" style="color: red">
  hello
</div>

簽章 ​

vnode = m(selector, attrs, children)

參數類型是否必填描述
selectorString|Object|Function是CSS 選擇器或元件
attrsObject否HTML 屬性或元素屬性
childrenArray<Vnode>|String|Number|Boolean否子 vnode。可以寫成 splat 參數
回傳值Vnodevnode

如何閱讀簽章

運作原理 ​

Mithril.js 提供了一個 hyperscript 函數 m(),允許使用 JavaScript 語法表達任何 HTML 結構。它接受一個 selector 字串(必填)、一個 attrs 物件(可選)和一個 children 陣列(可選)。

javascript
m('div', { id: 'box' }, 'hello');

// 渲染為以下 HTML:
// <div id="box">hello</div>

m() 函數實際上並不會回傳 DOM 元素。相反地,它會返回一個 虛擬 DOM 節點,或稱 vnode,它是一個 JavaScript 物件,表示要創建的 DOM 元素。

javascript
// 一個 vnode
var vnode = {
  tag: 'div',
  attrs: { id: 'box' },
  children: [
    /*...*/
  ],
};

若要將 vnode 轉換為實際的 DOM 元素,請使用 m.render() 函數:

javascript
m.render(document.body, m('br')); // 在 <body> 中放入一個 <br>

多次調用 m.render() 不會每次都從頭重新創建 DOM 樹。相反地,每次調用只會在絕對必要時才對 DOM 樹進行變更,以反映傳入調用的虛擬 DOM 樹。這種行為是可取的,因為從頭重新創建 DOM 非常耗費資源,並且會導致諸如失去輸入焦點等問題。相比之下,僅在必要時更新 DOM 速度更快,並且更容易維護處理多個使用者情境的複雜 UI。

彈性 ​

m() 函數既是 多型態的 也是 可變參數的。換句話說,它在期望的輸入參數方面非常靈活:

javascript
// 簡單標籤
m('div'); // <div></div>

// 屬性和子節點是可選的
m('a', { id: 'b' }); // <a id="b"></a>
m('span', 'hello'); // <span>hello</span>

// 具有子節點的標籤
m('ul', [
  // <ul>
  m('li', 'hello'), //   <li>hello</li>
  m('li', 'world'), //   <li>world</li>
]); // </ul>

// 陣列是可選的
m(
  'ul', // <ul>
  m('li', 'hello'), //   <li>hello</li>
  m('li', 'world') //   <li>world</li>
); // </ul>

CSS 選擇器 ​

m() 的第一個參數可以是任何可以描述 HTML 元素的 CSS 選擇器。它接受 # (id)、. (class) 和 [] (attribute) 語法的任何有效 CSS 組合。

javascript
m('div#hello');
// <div id="hello"></div>

m('section.container');
// <section class="container"></section>

m('input[type=text][placeholder=Name]');
// <input type="text" placeholder="Name" />

m("a#exit.external[href='https://example.com']", 'Leave');
// <a id="exit" class="external" href="https://example.com">Leave</a>

如果省略標籤名稱,Mithril.js 會假定為 div 標籤。

javascript
m('.box.box-bordered'); // <div class="box box-bordered"></div>

通常,建議您對靜態屬性(即值不變的屬性)使用 CSS 選擇器,並為動態屬性值傳遞屬性物件。

javascript
var currentURL = '/';

m(
  'a.link[href=/]',
  {
    class: currentURL === '/' ? 'selected' : '',
  },
  'Home'
);

// 渲染為以下 HTML:
// <a href="/" class="link selected">Home</a>

作為第二個參數傳遞的屬性 ​

您可以在第二個可選的參數中傳遞屬性、特性、事件和生命週期鉤子(詳情請參閱下一節)。

JS
m("button", {
  class: "my-button",
  onclick: function() {/* ... */},
  oncreate: function() {/* ... */}
})

如果此類屬性的值為 null 或 undefined,則將其視為該屬性不存在。

如果 m() 的第一個和第二個參數中都有類別名稱,則它們會如您所期望的那樣合併在一起。如果第二個參數中類別的值為 null 或 undefined,則會忽略它。

如果另一個屬性同時存在於第一個和第二個參數中,則第二個參數優先,即使它是 null 或 undefined。

DOM 屬性 ​

Mithril.js 使用 JavaScript API 和 DOM API (setAttribute) 來解析屬性。這表示您可以使用兩種語法來引用屬性。

例如,在 JavaScript API 中,readonly 屬性稱為 element.readOnly(請注意大寫)。在 Mithril.js 中,支援以下所有內容:

javascript
m('input', { readonly: true }); // 小寫
m('input', { readOnly: true }); // 大寫
m('input[readonly]');
m('input[readOnly]');

這甚至包括自訂元素。例如,您可以在 Mithril.js 中使用 A-Frame,沒有問題!

javascript
m('a-scene', [
  m('a-box', {
    position: '-1 0.5 -3',
    rotation: '0 45 0',
    color: '#4CC3D9',
  }),

  m('a-sphere', {
    position: '0 1.25 -5',
    radius: '1.25',
    color: '#EF2D5E',
  }),

  m('a-cylinder', {
    position: '1 0.75 -3',
    radius: '0.5',
    height: '1.5',
    color: '#FFC65D',
  }),

  m('a-plane', {
    position: '0 0 -4',
    rotation: '-90 0 0',
    width: '4',
    height: '4',
    color: '#7BC8A4',
  }),

  m('a-sky', {
    color: '#ECECEC',
  }),
]);

對於自訂元素,它不會自動字串化屬性,以防它們是物件、數字或某些其他非字串值。因此,假設您有一個自訂元素 my-special-element,它具有一個 elem.whitelist 陣列 getter/setter 屬性,您可以執行此操作,並且它會如您所期望的那樣工作:

javascript
m('my-special-element', {
  whitelist: [
    'https://example.com',
    'https://neverssl.com',
    'https://google.com',
  ],
});

如果您有這些元素的類別或 ID,則速記仍然可以如您所期望的那樣工作。若要提取另一個 A-Frame 範例:

javascript
// 這兩個是等效的
m('a-entity#player');
m('a-entity', { id: 'player' });

請注意,所有具有特殊語義的屬性,例如生命週期屬性、onevent 處理器、key、class 和 style,它們的處理方式與普通 HTML 元素相同。

Style 屬性 ​

Mithril.js 支援字串和物件作為有效的 style 值。換句話說,支援以下所有內容:

javascript
m('div', { style: 'background:red;' });
m('div', { style: { background: 'red' } });
m('div[style=background:red]');

如果重新繪製元素,則使用字串作為 style 會覆寫元素中的所有內嵌樣式,而不僅僅是值已變更的 CSS 規則。

您可以使用連字號 CSS 屬性名稱(例如 background-color)和駝峰式 DOM style 屬性名稱(例如 backgroundColor)。如果您的瀏覽器支援,您也可以定義 CSS 自訂屬性。

Mithril.js 不會嘗試將單位新增至數字值。它只是將它們字串化。

事件 ​

Mithril.js 支持所有 DOM 事件的事件處理常式繫結,包括其規範未定義 on${event} 屬性的事件,例如 touchstart

javascript
function doSomething(e) {
  console.log(e);
}

m('div', { onclick: doSomething });

Mithril.js 接受函數和 EventListener 物件。因此,這也有效:

javascript
var clickListener = {
  handleEvent: function (e) {
    console.log(e);
  },
};

m('div', { onclick: clickListener });

預設情況下,當使用 hyperscript 附加的事件觸發時,這將在您的事件回呼返回後觸發 Mithril.js 的自動重新繪製(假設您使用 m.mount 或 m.route 而不是直接使用 m.render)。您可以透過在事件上設定 e.redraw = false 來專門針對單個事件停用自動重新繪製:

javascript
m('div', {
  onclick: function (e) {
    // 阻止自動重新繪製
    e.redraw = false;
  },
});

屬性 ​

Mithril.js 支援可透過屬性存取的 DOM 功能,例如 <select> 的 selectedIndex 和 value 屬性。

javascript
m('select', { selectedIndex: 0 }, [
  m('option', 'Option A'),
  m('option', 'Option B'),
]);

元件 ​

元件 允許您將邏輯封裝到一個單元中,並像使用元素一樣使用它。它們是製作大型、可擴展應用程式的基礎。

元件是任何包含 view 方法的 JavaScript 物件。若要使用元件,請將元件作為第一個參數傳遞給 m(),而不是傳遞 CSS 選擇器字串。您可以透過定義屬性和子節點將參數傳遞給元件,如下例所示。

javascript
// 定義一個元件
var Greeter = {
  view: function (vnode) {
    return m('div', vnode.attrs, ['Hello ', vnode.children]);
  },
};

// 使用它
m(Greeter, { style: 'color:red;' }, 'world');

// 渲染為以下 HTML:
// <div style="color:red;">Hello world</div>

若要瞭解有關元件的更多資訊,請參閱元件頁面。

生命週期方法 ​

Vnode 和元件可以具有生命週期方法(也稱為 hooks),這些方法在 DOM 元素的生命週期中的各個點調用。Mithril.js 支持的生命週期方法有:oninit、oncreate、onupdate、onbeforeremove、onremove 和 onbeforeupdate。

生命週期方法的定義方式與 DOM 事件處理常式相同,但接收 vnode 作為參數,而不是 Event 物件:

javascript
function initialize(vnode) {
  console.log(vnode);
}

m('div', { oninit: initialize });
Hook描述
oninit(vnode)在將 vnode 渲染到實際 DOM 元素之前執行
oncreate(vnode)在將 vnode 附加到 DOM 後執行
onupdate(vnode)每次在 DOM 元素附加到文件時發生重新繪製時執行
onbeforeremove(vnode)在從文件中移除 DOM 元素之前執行。如果回傳 Promise,則 Mithril.js 僅在 Promise 完成後才分離 DOM 元素。此方法僅在從其父 DOM 元素分離的元素上觸發,但不在其子元素上觸發。
onremove(vnode)在從文件中移除 DOM 元素之前執行。如果定義了 onbeforeremove hook,則在調用 done 後調用 onremove。此方法在從其父元素分離的元素及其所有子元素上觸發
onbeforeupdate(vnode, old)在 onupdate 之前執行,如果它回傳 false,則會阻止元素及其所有子元素的差異比較

若要瞭解有關生命週期方法的更多資訊,請參閱生命週期方法頁面。

Keys ​

列表中的 Vnode 可以具有一個稱為 key 的特殊屬性,該屬性可用於在產生 vnode 列表的模型數據變更時管理 DOM 元素的識別。

通常,key 應該是數據陣列中物件的唯一識別碼欄位。

javascript
var users = [
  { id: 1, name: 'John' },
  { id: 2, name: 'Mary' },
];

function userInputs(users) {
  return users.map(function (u) {
    return m('input', { key: u.id }, u.name);
  });
}

m.render(document.body, userInputs(users));

具有 key 表示如果 users 陣列被打亂並且重新渲染視圖,則輸入將以完全相同的順序被打亂,以便保持正確的焦點和 DOM 狀態。

若要瞭解有關 key 的更多資訊,請參閱 key 頁面。

SVG 和 MathML ​

Mithril.js 完全支持 SVG。也支持 Xlink,但與 Mithril.js 的 v1.0 之前的版本不同,必須明確定義命名空間:

javascript
m('svg', [m("image[xlink:href='image.gif']")]);

MathML 也完全支持。

使範本動態化 ​

由於巢狀 vnode 只是普通的 JavaScript 表達式,因此您可以簡單地使用 JavaScript 功能來操作它們

動態文字 ​

javascript
var user = { name: 'John' };

m('.name', user.name); // <div class="name">John</div>

迴圈 ​

使用 Array 方法,例如 map 來迭代數據列表

javascript
var users = [{ name: 'John' }, { name: 'Mary' }];

m(
  'ul',
  users.map(function (u) {
    // <ul>
    return m('li', u.name); //   <li>John</li>
    //   <li>Mary</li>
  })
); // </ul>

// ES6+:
// m("ul", users.map(u =>
//   m("li", u.name)
// ))

條件式 ​

使用三元運算子有條件地在視圖上設定內容

javascript
var isError = false;

m('div', isError ? 'An error occurred' : 'Saved'); // <div>Saved</div>

您不能在 JavaScript 表達式中使用 JavaScript 語句,例如 if 或 for。最好完全避免使用這些語句,而是專門使用上面的結構,以便保持範本的結構線性且宣告式。

轉換 HTML ​

在 Mithril.js 中,格式良好的 HTML 是有效的 JSX。除了複製貼上之外,幾乎不需要任何努力即可將獨立產生的 HTML 文件整合到使用 JSX 的項目中。

使用 hyperscript 時,必須先將 HTML 轉換為 hyperscript 語法,然後才能執行程式碼。為了方便起見,您可以使用 HTML-to-Mithril-template 轉換器。

避免反面模式 ​

雖然 Mithril.js 具有彈性,但不鼓勵使用某些代碼模式:

避免動態選擇器 ​

不同的 DOM 元素具有不同的屬性,並且通常具有不同的行為。使選擇器可配置可能會將元件的實現細節洩漏出其單元。

javascript
// 避免
var BadInput = {
  view: function (vnode) {
    return m('div', [m('label'), m(vnode.attrs.type || 'input')]);
  },
};

您應該明確地編碼每個有效的可能性,或重構代碼的變化部分,而不是使選擇器動態化。

javascript
// 偏好明確代碼
var BetterInput = {
  view: function (vnode) {
    return m('div', [m('label', vnode.attrs.title), m('input')]);
  },
};
var BetterSelect = {
  view: function (vnode) {
    return m('div', [m('label', vnode.attrs.title), m('select')]);
  },
};

// 偏好重構變異性
var BetterLabeledComponent = {
  view: function (vnode) {
    return m('div', [m('label', vnode.attrs.title), vnode.children]);
  },
};

避免在視圖之外建立 vnode ​

當重新繪製遇到一個與先前渲染中的 vnode 完全相等的 vnode 時,它將被跳過,並且其內容將不會被更新。雖然這看起來像是效能優化的機會,但應避免這樣做,因為它會阻止該節點樹中的動態變更 - 這會導致諸如下游生命週期方法無法在重新繪製時觸發的副作用。從這個意義上說,Mithril.js vnode 是不可變的:新的 vnode 會與舊的 vnode 進行比較;對 vnode 的變更不會持久化。

元件文件包含更多詳細資訊和此反面模式的範例。

Pager
上一頁API
下一頁render(element, vnodes)

以 MIT 授權條款 發布。

版權所有 (c) 2024 Mithril Contributors

https://mithril.js.org/hyperscript.html

以 MIT 授權條款 發布。

版權所有 (c) 2024 Mithril Contributors