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

入门

安装

简单应用

资源

JSX

在旧版浏览器上使用 ES6+

动画

测试

示例

第三方库集成

路径处理

关键概念

虚拟 DOM

组件

生命周期方法

键(Key)

自动重绘系统

杂项

框架对比

从 v1.x 迁移

从 v0.2.x 迁移

API

页面导航

从 v1.x 迁移 ​

v2.x 的 API 几乎完全兼容 v1.x,但仍存在一些不兼容的变更。

赋值给 vnode.state ​

在 v1.x 中,你可以随意操作 vnode.state 并赋值任何内容。但在 v2.x 中,尝试修改它会抛出错误。迁移方法因情况而异,但在大多数情况下,只需将对 vnode.state 的引用更改为 vnode.state.foo,并为 foo 选择一个合适的名称(例如,如果它表示计数器的当前值,可以命名为 count)。

v1.x ​

javascript
var Counter = {
  oninit: function (vnode) {
    vnode.state = 0;
  },
  view: function (vnode) {
    return m('.counter', [
      m(
        'button',
        {
          onclick: function () {
            vnode.state--;
          },
        },
        '-'
      ),
      vnode.state,
      m(
        'button',
        {
          onclick: function () {
            vnode.state++;
          },
        },
        '+'
      ),
    ]);
  },
};

v2.x ​

javascript
var Counter = {
  oninit: function (vnode) {
    vnode.state.count = 0;
  },
  view: function (vnode) {
    return m('.counter', [
      m(
        'button',
        {
          onclick: function () {
            vnode.state.count--;
          },
        },
        '-'
      ),
      vnode.state.count,
      m(
        'button',
        {
          onclick: function () {
            vnode.state.count++;
          },
        },
        '+'
      ),
    ]);
  },
};

当 v1.0 首次发布时,类组件和闭包组件还不存在,因此 Mithril 只是从 vnode.tag 中提取所需的信息。这个实现细节允许你这样做,并且在文档的某些地方也暗示了这一点。现在,情况有所不同,从实现的角度来看,管理起来更容易一些,因为只有一个对状态的引用,而不是两个。

路由锚点的更改 ​

在 v1.x 中,你使用 oncreate: m.route.link,如果链接可能发生变化,则同时使用 onupdate: m.route.link。它们都是 vnode 上的生命周期钩子,用于路由导航。在 v2.x 中,现在使用 m.route.Link 组件。如果使用 m("a", ...) 以外的元素,可以通过 selector: 属性指定选择器,通过 options: 指定选项,通过 disabled: 属性禁用它,并且可以内联指定其他属性,包括 href:(必需)。selector: 本身可以包含任何作为 m 的第一个参数有效的选择器,并且属性 [href=...] 和 [disabled] 可以在选择器中以及普通选项中指定。

v1.x ​

javascript
m('a', {
  href: '/path',
  oncreate: m.route.link,
});

m('button', {
  href: '/path',
  oncreate: m.route.link,
});

m('button.btn[href=/path]', {
  oncreate: m.route.link,
});

v2.x ​

javascript
m(m.route.Link, {
  href: '/path',
});

m(m.route.Link, {
  selector: 'button',
  href: '/path',
});

m(m.route.Link, {
  selector: 'button.btn[href=/path]',
});

m.request 错误的更改 ​

在 v1.x 中,m.request 解析来自 JSON 调用的错误,并将解析后对象的属性赋值给响应。因此,如果收到一个状态码为 403 的响应,且响应体 (body) 为 {"code": "backoff", "timeout": 1000},那么错误对象将包含两个额外的属性:err.code = "backoff" 和 err.timeout = 1000。

在 v2.x 中,响应被赋值给结果的 response 属性,而 code 属性包含 HTTP 状态码。因此,如果你收到一个状态码为 403 的响应,且响应体 (body) 为 {"code": "backoff", "timeout": 1000},则该错误将被赋值两个属性:err.response = {code: "backoff", timeout: 1000} 和 err.code = 403。

m.withAttr 已移除 ​

在 v1.x 中,事件监听器可以使用 oninput: m.withAttr("value", func) 这样的方式。在 v2.x 中,只需直接从事件目标读取它们。虽然它与流(stream)配合得很好,但由于 m.withAttr("value", stream) 的使用频率远低于 m.withAttr("value", prop),m.withAttr 的实用性大大降低,因此被移除。

v1.x ​

javascript
var value = '';

// In your view
m('input[type=text]', {
  value: value(),
  oninput: m.withAttr('value', function (v) {
    value = v;
  }),
});

// OR

var value = m.stream('');

// In your view
m('input[type=text]', {
  value: value(),
  oninput: m.withAttr('value', value),
});

v2.x ​

javascript
var value = '';

// In your view
m('input[type=text]', {
  value: value,
  oninput: function (ev) {
    value = ev.target.value;
  },
});

// OR

var value = m.stream('');

// In your view
m('input[type=text]', {
  value: value(),
  oninput: function (ev) {
    value(ev.target.value);
  },
});

m.route.prefix ​

在 v1.x 中,m.route.prefix 是一个通过 m.route.prefix(prefix) 调用的函数。现在它是一个你可以通过 m.route.prefix = prefix 设置的属性。

v1.x ​

javascript
m.route.prefix('/root');

v2.x ​

javascript
m.route.prefix = '/root';

m.request/m.jsonp 的 params 和 body ​

data 和 useBody 被重构为 params (用于将查询参数插入到 URL 并附加到请求) 和 body (用于在底层 XHR 中发送请求体)。这让你更好地控制实际发送的请求,并允许你既可以使用 POST 请求将参数插入到查询参数中,也可以创建带有 body 的 GET 请求。

m.jsonp 没有有意义的 "body",只使用 params,因此将 data 重命名为 params 对于该方法来说就足够了。

v1.x ​

javascript
m.request('https://example.com/api/user/:id', {
  method: 'GET',
  data: { id: user.id },
});

m.request('https://example.com/api/user/create', {
  method: 'POST',
  data: userData,
});

v2.x ​

javascript
m.request('https://example.com/api/user/:id', {
  method: 'GET',
  params: { id: user.id },
});

m.request('https://example.com/api/user/create', {
  method: 'POST',
  body: userData,
});

路径模板 ​

在 v1.x 中,有三种独立的路径模板语法,虽然它们很相似,但有两种单独设计的语法和三种不同的实现。它的定义方式相当随意,并且参数通常不会进行转义。现在,对于 :key,所有内容都会被编码;对于 :key...,则保持原始状态。如果遇到意外的编码,请使用 :path...。就这么简单。

具体来说,以下是它如何影响每个方法:

m.request 和 m.jsonp 的 URL,m.route.set 的路径 ​

在 v2.x 中,路径组件在进行插值时会自动进行转义。假设你调用 m.route.set("/user/:name/photos/:id", {name: user.name, id: user.id})。以前,如果 user 是 {name: "a/b", id: "c/d"},这将把路由设置为 /user/a%2Fb/photos/c/d,但现在它将把它设置为 /user/a%2Fb/photos/c%2Fd。如果你确实需要插入一个未经转义的键,请使用 :key...。

v2.x 中的键不能包含任何 . 或 - 的实例。在 v1.x 中,它们可以包含除 / 之外的任何内容。

在 v2.x 中,不会执行内联查询字符串中的插值,例如 /api/search?q=:query。请通过带有适当键名的 params 传递这些参数,而无需在查询字符串中指定它。

m.route 路由模式 ​

对于 :key... 形式的路径键,v1.x 返回的是 URL 解码后的值,而 v2.x 返回的是原始 URL。

以前,像 :key.md 这样的写法会被错误地接受,并将生成的参数的值设置为 keymd: "..."。现在情况并非如此 - .md 现在是模式的一部分,而不是名称。

生命周期调用顺序 ​

在 v1.x 中,组件 vnode 属性上的生命周期钩子函数总是在组件自身的生命周期钩子函数之前被调用。在 v2.x 中,只有 onbeforeupdate 钩子函数是这种情况。因此,你可能需要相应地调整代码。

v1.x ​

javascript
var Comp = {
  oncreate: function () {
    console.log('Component oncreate');
  },
  view: function () {
    return m('div');
  },
};

m.mount(document.body, {
  view: function () {
    return m(Comp, {
      oncreate: function () {
        console.log('Attrs oncreate');
      },
    });
  },
});

// Logs:
// Attrs oncreate
// Component oncreate

v2.x ​

javascript
var Comp = {
  oncreate: function () {
    console.log('Component oncreate');
  },
  view: function () {
    return m('div');
  },
};

m.mount(document.body, {
  view: function () {
    return m(Comp, {
      oncreate: function () {
        console.log('Attrs oncreate');
      },
    });
  },
});

// Logs:
// Component oncreate
// Attrs oncreate

m.redraw 同步性 ​

v2.x 中的 m.redraw() 始终是异步的。你可以通过 m.redraw.sync() 显式请求同步重绘,前提是当前没有正在进行的重绘。

选择器属性优先级 ​

在 v1.x 中,选择器属性优先于属性对象中指定的属性。例如,m("[a=b]", {a: "c"}).attrs 返回 {a: "b"}。

在 v2.x 中,属性对象中指定的属性优先于选择器属性。例如,m("[a=b]", {a: "c"}).attrs 返回 {a: "c"}。

请注意,这实际上是恢复到了 v0.2.x 版本的行为。

子节点规范化 ​

在 v1.x 中,组件 vnode 子节点像其他 vnode 一样被规范化。在 v2.x 中,情况已经改变,你需要据此进行调整。这不会影响在渲染时完成的规范化。

m.request 标头 ​

在 v1.x 中,Mithril.js 在所有非 GET 请求上设置了这两个标头,但仅当 useBody 设置为 true(默认值)并且满足列出的其他条件时:

  • 对于包含 JSON 请求体的请求,Content-Type: application/json; charset=utf-8
  • 对于预期返回 JSON 响应的请求,Accept: application/json, text/*

在 v2.x 中,对于所有包含非空 ( != null ) JSON 请求体的请求,Mithril.js 会设置第一个标头。否则,默认情况下会省略该标头。此行为与所选的 HTTP 方法无关,包括 GET 请求。

这两个标头中的其中第一个标头,Content-Type,将触发 CORS 预检,因为它不是 CORS 安全列表请求标头,因为指定的内容类型,并且这可能会引入新的错误,具体取决于 CORS 在你的服务器上的配置方式。如果遇到此类问题,你可能需要通过传递 headers: {"Content-Type": "text/plain"} 来覆盖该标头。(Accept 标头不会触发任何内容,因此你无需覆盖它。)

Fetch 规范允许避免 CORS 预检检查的唯一内容类型是 application/x-www-form-urlencoded、multipart/form-data 和 text/plain。它不允许任何其他内容,并且它有意不允许 JSON。

路由中哈希字符串中的查询参数 ​

在 v1.x 中,你可以在查询字符串和哈希字符串中为路由指定查询参数,因此 m.route.set("/route?foo=1&bar=2")、m.route.set("/route?foo=1#bar=2") 和 m.route.set("/route#foo=1&bar=2") 都是等效的,并且从中提取的属性将是 {foo: "1", bar: "2"}。

在 v2.x 中,哈希字符串的内容将被忽略但保留。因此,从以下每个 URL 中提取的属性将是:

  • m.route.set("/route?foo=1&bar=2") → {foo: "1", bar: "2"}
  • m.route.set("/route?foo=1#bar=2") → {foo: "1"}
  • m.route.set("/route#foo=1&bar=2") → {}

这样做的原因是像 https://example.com/#!/route#key 这样的 URL 在技术上根据 URL 规范 是无效的,甚至根据 之前的 RFC 也是无效的,并且只是 HTML 规范的一个特殊处理允许它们。

或者简而言之,停止使用无效的 URL!

键 ​

在 v1.x 中,你可以自由地混合键控和非键控 vnode。如果第一个节点是键控的,则执行键控差异,假设每个元素都有一个键,并且只是忽略它前进时的空洞。否则,将执行迭代差异。如果一个节点包含键,则在检查标签等属性的同时,还会检查该键是否发生了更改。

在 v2.x 中,片段和元素的子节点列表必须全部键控或全部非键控。为了进行此检查,空洞也被认为是非键控的 - 它不再忽略它们。

如果需要规避此限制,可以使用包含单个 vnode 的片段,例如 [m("div", {key: whatever})]。

m.version 已移除 ​

它通常用处不大,你可以根据需要自行添加。你应该更喜欢使用特性检测来了解哪些特性可用,并且 v2.x API 旨在更好地支持这一点。

Pager
上一页框架对比
下一页从 v0.2.x 迁移

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors

https://mithril.js.org/migration-v1x.html

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors