Skip to content

Instantly share code, notes, and snippets.

@jixunmoe
Last active May 7, 2018 15:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jixunmoe/9ad359759597f706f61d07a09995c7d9 to your computer and use it in GitHub Desktop.
Save jixunmoe/9ad359759597f706f61d07a09995c7d9 to your computer and use it in GitHub Desktop.
es5 implementation of jsx without state management.
/** @jsx h */
// See https://c.jixun.moe/ui for live-demo
(function(root) {
function UnsafeHtml({ html }) {
var div = (<i />);
div.innerHTML = html;
return div.childNodes;
}
function ExternalLink({ className, href, children }) {
return (
<a className={className} href={href} target="_blank">
{ children }
</a>
);
}
function Author({ author, uri }) {
var AuthorTag = uri ? ExternalLink : "i";
return (
<AuthorTag className="author" href={uri}>
{author || "无名氏"}
</AuthorTag>
);
}
function Comment({ website, author, uri, text }) {
return (
<div className="comment">
<p>
<Author className="author" author={author} uri={website} />
(来源: <ExternalLink href={`https://jixun.moe` + uri}>{uri}</ExternalLink>)
</p>
<div className="body">
<UnsafeHtml html={text} />
</div>
</div>
);
}
function App({ comments }) {
return (
<div className="comments">
{comments.map(comment => (
<Comment {...comment} />
))}
</div>
);
}
var xhr = new XMLHttpRequest();
xhr.open("GET", "/latest");
xhr.onload = xhr.onerror = function () {
var data;
try {
data = JSON.parse(xhr.responseText);
mount(root, <App {...data} />);
} catch (error) {
root.textContent = "获取评论出错。";
}
}
xhr.send();
})(document.getElementById("app"));
var h = (function () {
function deref(fn) {
return Function.call.bind(fn);
}
var slice = deref(Array.prototype.slice);
// Lodash code starts here
var MAX_SAFE_INTEGER = 9007199254740991;
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
function isArrayLike(value) {
return value != null && isLength(value.length) && !isFunction(value);
}
function isObjectLike (value) {
return value != null && typeof value == "object";
}
// Lodash code ends here
function isFunction(value) {
return value instanceof Function;
}
function makeArray(v) {
return (isArrayLike(v) && typeof v !== "string") ? slice(v) : [v];
}
function isNode(el) {
return el instanceof Node;
}
function isObjectLikeNotArray(value) {
return isObjectLike(value) && !isArrayLike(value);
}
/**
* 深度对象合并
* @param {Object} src 需要扩展的对象。
* @param {Object} [...ext] 待扩展的属性。
*/
function merge(src) {
slice(arguments, 1).forEach(function (ext) {
if (isObjectLikeNotArray(ext)) {
Object.keys(ext).forEach(function (key) {
var value = ext[key];
if (isObjectLikeNotArray(value)) {
if (!src[key]) {
src[key] = {};
}
merge(src[key], value);
} else {
src[key] = value;
}
});
}
});
return src;
}
/**
* 建立一个 HTML 元素
* @param {String|Function} tag 元素标签,或传入 Stateless 组件函数。
* @param {Object.<String.String|Bool|Number>} [attrs = {}] 元素属性集合。
* @param {Array.<String|Node>|String|Node} [...children] 子元素集合。
*/
function h(tag, attrs) {
var children = slice(arguments, 2);
// Stateless 组件建立
if (isFunction(tag)) {
return tag(Object.assign({ children }, attrs));
}
var el = merge(document.createElement(tag), attrs);
children.forEach(function (children) {
makeArray(children).forEach(function (child) {
el.appendChild(isNode(child) ? child : document.createTextNode(child));
});
});
return el;
}
return h;
})();
/**
* 将建立的元素挂载到一个 HTML 节点 (会先暴力清空节点内容)。
* @param {HTMLElement} mnt 挂载点。
* @param {Node} node HTML 元素或节点。
*/
function mount(mnt, node) {
mnt.innerHTML = "";
mnt.appendChild(node);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment