騰訊 Omio 釋出 - 全面相容 IE9 和移動端
在微信支付、手機QQ、騰訊TEG、騰訊IEG等團隊已經能夠使用 Omi 應用於大量的 to b 的專案以及內部管理系統,為了達到 Omi 全覆蓋,相容 to c 端各種瀏覽器環境,所以有了 Omio, 擁有幾乎和 Omi 一模一樣的語法。
相容老瀏覽器的 Omi 版本, ofollow,noindex">→ Github

立即使用
$ npm i omi-cli -g $ omi init-o my-app $ cd my-app $ npm start $ npm run build 複製程式碼
與 omi 不同之處
omio 擁有 omi一樣的語法,但是也有一些差異需要注意:
- omio 支援
staticCss
,omi 是不支援的
css
和 staticCss
的區別是 ? 例如:
render() { return ( <div> <my-ele name={this.name}></my-ele> <my-ele name={this.name}></my-ele> <my-ele name={this.name}></my-ele> </div> ) } 複製程式碼
如上面的例子, css
方法會渲染三次,並插入到 head,而 staticCss
只會渲染一次。 當你 update 元件或者 setState 時候, css
方法會渲染三次,並更新head裡對應三個地方的樣式, staticCss
不再渲染。
- Omio 不支援 slot, 請使用
props.children
代替,像 react 一樣 - Omio 支援 store 注入,但不支援 store path updating
- Omio 不支援 render array,未來可能支援
- Omio 不支援
fire
觸發自定義事件,可以和 react 一樣使用props.xxx()
去觸發。Omi 同時支援fire
andprops.xxx()
兩種方式。
Omi 專案中使用 Omio
先安裝:
npm i omio 複製程式碼
配置 Webpack Alias
如果你想在已經存在的 omi 專案下使用 omio,你可以使用下面配置,不用任何程式碼更改:
module.exports = { //... resolve: { alias: { omi: 'omio' } } }; 複製程式碼
相容 IE 踩坑
第一坑 - 偽陣列
IE下 querySelectorAll 出來的偽陣列,沒有 array 相關的方法:
const codes = document.querySelectorAll('xxx') //掛了 codesArr.forEach(() => { }) 複製程式碼
需要轉成真陣列:
const codes = Array.prototype.slice.call(document.querySelectorAll('xxx')) 複製程式碼
第二坑 - 靜態屬性丟失
這是 Omi 的原始碼:
function define(name, ctor) { if (ctor.is === 'WeElement') { options.mapping[name] = ctor; if (ctor.data && !ctor.pure) { ctor.updatePath = getUpdatePath(ctor.data); } } } 複製程式碼
但是在 IE 下進入不了 if 條件!!Omi 原始碼裡明明有有靜態屬性:
class WeElement { static is = 'WeElement' constructor(props, store) { ... } ... ... render() { } } 複製程式碼
為什麼丟失了呢?追根溯源一下:
使用 define:
define('my-p', class extends WeElement { render(props) { return props.children[0] } }) 複製程式碼
編譯後的程式碼:
define('my-p', function (_WeElement) { _inherits(_class, _WeElement); function _class() { _classCallCheck(this, _class); return _possibleConstructorReturn(this, _WeElement.apply(this, arguments)); } _class.prototype.render = function render$$1(props) { return props.children[0]; }; return _class; }(WeElement)); 複製程式碼
那麼問題就出在 _inherits 過程中把靜態屬性 is
丟失了!
function _inherits(subClass, superClass) { subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) { Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } } 複製程式碼
好,由於是編譯註入程式碼,後面可能也需要支援純函式的元件定義,所以這樣解決了:
function define(name, ctor) { //if (ctor.is === 'WeElement') { options.mapping[name] = ctor; if (ctor.data && !ctor.pure) { ctor.updatePath = getUpdatePath(ctor.data); } //} } 複製程式碼
第三坑 - Object.assign IE 不支援
由於 Omio 原始碼裡使用了 Object.assign,所以這裡需要 polyfill 一下:
if (typeof Object.assign != 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { value: function assign(target, varArgs) { // .length of function is 2 'use strict'; if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { // Skip over if undefined or null for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true }); } 複製程式碼
由於 IE9 支援了 ES5, webpack 編譯出來的 es5,所以並不需要引入 es5-shim 來相容。
第四坑 - Proxy 不支援
因為需要監聽資料變化,Omi 使用的是 Proxy,所以這裡需要一個降級方案 - obaa 庫 ,監聽任意物件的任意變化。
安裝 obaa
npm install obaa 複製程式碼
使用
observe object:
var obj = { a: 1 }; obaa(obj, function (name, value , old) { console.log(name + "__" + value + "__" + old); }); obj.a = 2; //a__2__1 複製程式碼
observe array:
var arr = [1, 2, 3]; obaa(arr, function (name, value, old) { console.log(name + "__" + value+"__"+old); }); arr.push(4);//Array-push__[1,2,3,4]__[1,2,3] arr[3] = 5;//3__5__4 複製程式碼
observe class instance:
var User = function (name, age) { this.name = name; this.age = age; //observe name only obaa(this, ["name"], function (name, value, oldValue) { console.log(name + "__" + value + "__" + oldValue); }); } var user = new User("lisi", 25); user.name = "wangwu";//name__wangwu__lisi user.age = 20; //nothing output 複製程式碼
其他:
arr.push(111) //trigger observe callback //every method of array has a pureXXX function arr.purePush(111) //don't trigger observe callback arr.size(2) //trigger observe callback arr.length = 2 //don't trigger observe callback //if obj.c is undefined obaa.set(obj, 'c', 3) obj.c = 4 //trigger observe callback //if obj.c is undefined obj.c = 3 obj.c = 4 //don't trigger observe callback 複製程式碼
第五坑 - MVVM 的 mappingjs 不支援

mappingjs 完全利用的 proxy,所以資料 mapping 的過程中會自動更新檢視。但是切換成 obaa 之後,發現數組 length 更新檢視不會更新,陣列增加檢視不會更新。review 了 mappingjs 發現:
- mappingjs 使用了 array.length 改變陣列長度
- mappingjs 使用 array[index] 增加元素
這樣在 obaa 是不允許的,不然的話無法監聽到變化, obaa 要求:
- 使用 array.size(len) 改變陣列長度
- 使用 array.push 增加元素
所以就有了 mappingjs-omio , 這樣的話, Omio 同樣可以使用真正的 MVVM 架構。