Riot.js的版本是1.0.4。官网地址:https://muut.com/riotjs
整个Riot.js只有3个可以在外面调用的函数接口,分别是observable、render、route。
1、observable函数
observable函数只有一个参数el,指向Model,该接口的作用是预处理Model,使得Model具有事件定义和发布功能,返回值是处理后的Model。我们来看源码:
riot.observable = function(el) {
var callbacks = {}, slice = [].slice;
el.on = function(events, fn) {
if (typeof fn === "function") {
events.replace(/\S+/g, function(name, pos) {
(callbacks[name] = callbacks[name] || []).push(fn);
fn.typed = pos > 0;
});
}
return el;
};
el.off = function(events, fn) {
if (events === "*") callbacks = {};
else if (fn) {
var arr = callbacks[events];
for (var i = 0, cb; (cb = arr && arr[i]); ++i) {
if (cb === fn) { arr.splice(i, 1); i--; }
}
} else {
events.replace(/\S+/g, function(name) {
callbacks[name] = [];
});
}
return el;
};
// only single event supported
el.one = function(name, fn) {
if (fn) fn.one = true;
return el.on(name, fn);
};
el.trigger = function(name) {
var args = slice.call(arguments, 1),
fns = callbacks[name] || [];
for (var i = 0, fn; (fn = fns[i]); ++i) {
if (!fn.busy) {
fn.busy = true;
fn.apply(el, fn.typed ? [name].concat(args) : args);
if (fn.one) { fns.splice(i, 1); i--; }
fn.busy = false;
}
}
return el;
};
return el;
};
2、render函数
render函数顾名思义就是用来呈现html模板的。直接上代码:
var FN = {}, // Precompiled templates (JavaScript functions)
template_escape = {"\\": "\\\\", "\n": "\\n", "\r": "\\r", "'": "\\'"},
render_escape = {'&': '&', '"': '"', '<': '<', '>': '>'};
function default_escape_fn(str, key) {
return str == null ? '' : (str+'').replace(/[&\"<>]/g, function(char) {
return render_escape[char];
});
}
riot.render = function(tmpl, data, escape_fn) {
if (escape_fn === true) escape_fn = default_escape_fn;
tmpl = tmpl || '';
return (FN[tmpl] = FN[tmpl] || new Function("_", "e", "return '" +
tmpl.replace(/[\\\n\r']/g, function(char) {
return template_escape[char];
}).replace(/{\s*([\w\.]+)\s*}/g, "' + (e?e(_.$1,'$1'):_.$1||(_.$1==null?'':_.$1)) + '") + "'")
)(data, escape_fn);
};
3、route函数
route函数的参数是一个回调函数,用来在”页面加载“时触发。
这段代码比较有意思。
pops = riot.observable({})
先通过observable函数定义一个”临时model“,用来可以订阅和发布事件(这里主要是页面加载事件)。
// listen
if (typeof to === "function") return pops.on("pop", to);
通过route函数,传入回调函数to,定义pops上得”pop“事件,回调函数为to。
function pop(hash) {
hash = hash.type ? location.hash : hash;
if (hash !== currentHash) pops.trigger("pop", hash);
currentHash = hash;
}
/* Always fire pop event upon page load (normalize behaviour across browsers) */
// standard browsers
if (listen) {
listen("popstate", pop, false);
doc.addEventListener("DOMContentLoaded", pop, false);
// IE
} else {
doc.attachEvent("onreadystatechange", function() {
if (doc.readyState === "complete") pop("");
});
}
监听页面的加载事件,然后触发”pop“事件。
下面是整个route函数的相关代码:
/* Cross browser popstate */
(function () {
// for browsers only
if (typeof window === "undefined") return;
var currentHash,
pops = riot.observable({}),
listen = window.addEventListener,
doc = document;
function pop(hash) {
hash = hash.type ? location.hash : hash;
if (hash !== currentHash) pops.trigger("pop", hash);
currentHash = hash;
}
/* Always fire pop event upon page load (normalize behaviour across browsers) */
// standard browsers
if (listen) {
listen("popstate", pop, false);
doc.addEventListener("DOMContentLoaded", pop, false);
// IE
} else {
doc.attachEvent("onreadystatechange", function() {
if (doc.readyState === "complete") pop("");
});
}
/* Change the browser URL or listen to changes on the URL */
riot.route = function(to) {
// listen
if (typeof to === "function") return pops.on("pop", to);
// fire
if (history.pushState) history.pushState(0, 0, to);
pop(to);
};
})();