{"id":50,"date":"2015-11-18T13:35:50","date_gmt":"2015-11-18T05:35:50","guid":{"rendered":"http:\/\/douhan.li\/?p=50"},"modified":"2015-11-18T13:50:16","modified_gmt":"2015-11-18T05:50:16","slug":"riot-js%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90","status":"publish","type":"post","link":"https:\/\/douhan.li\/?p=50","title":{"rendered":"Riot.js\u6e90\u7801\u5206\u6790"},"content":{"rendered":"<p>\u4e0a\u4e00\u7bc7\u65e5\u5fd7\u7b80\u5355\u7684\u4ecb\u7ecd\u4e86\u4e00\u4e0bRiot.js\u8fd9\u4e2a\u4e1c\u897f\uff0c\u8fd9\u4e09\u5468\u4ee5\u6765\u6211\u4e00\u76f4\u518d\u770bReact\u7684\u6e90\u7801\uff0c\u4f9d\u7136\u5bf9\u5b83\u7684batchUpdate\u4e00\u5934\u96fe\u6c34\uff0c\u6240\u4ee5\u51b3\u5b9a\u5148\u5206\u6790\u4e00\u4e0bRiot.js.<\/p>\n<p>Riot.js\u540c\u6837\u4f7f\u7528\u4e86VirtualDOM,\u4f46\u4e0eReact\u4e0d\u540c\u7684\u662f\uff0c\u5b83\u7684DOM\u5237\u65b0\u5e76\u4e0d\u50cfReact\u90a3\u6837\u662fBatchUpdate\u505a\u4e00\u4e0bDOM\u4e0eVirtualDOM diff,\u800c\u662f\u76f4\u63a5\u4fee\u6539nodeText,\u8fd9\u6837\u7684\u4e00\u4e2a\u597d\u5904\u662f\u5728\u4e8e\u7b97\u6cd5\u4e0d\u590d\u6742\uff0c\u53ea\u9700\u8981\u904d\u5386\u6240\u6709\u8282\u70b9\uff0c\u76f8\u5e94\u8fdb\u884c\u63d2\u5165\u5c31\u53ef\u4ee5\uff0e<\/p>\n<p>Riot\u540c\u6837\u5177\u6709\u81ea\u5b9a\u4e49\u8282\u70b9\u7684\u529f\u80fd\uff0c\u4e00\u822c\u60c5\u51b5\u4e0b\u6211\u4eec\u4e0d\u4f7f\u7528Riot.tag2\u8fdb\u884c\u81ea\u5b9a\u4e49\u8282\u70b9\u7684\u5b9a\u4e49\uff0c\u800c\u662f\u901a\u8fc7Riot\u63d0\u4f9b\u7684\u8bed\u6cd5\u8fdb\u884c\u5f00\u53d1\uff0c\u6700\u540e\u4f7f\u7528\u6d4f\u89c8\u5668\/\u670d\u52a1\u5668\u7aef\u7f16\u8bd1\u81ea\u52a8\u751f\u6210\uff0c\u4f46\u6700\u540e\u6267\u884c\u8fd8\u662f\u907f\u514d\u4e0d\u4e86Riot.tag2,\u56e0\u6b64\u9996\u5148\u4ece\u8be5\u65b9\u6cd5\u5f00\u59cb\u5206\u6790\uff0e<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nriot.tag2 = function(name, html, css, attrs, fn, bpair) {\r\n\/\/\u5982\u679c\u5177\u6709CSS,\u5219\u5c06CSS\u63d2\u5165\u5230&amp;lt;head&amp;gt;&amp;lt;\/head&amp;gt;\u4e2d\r\nif (css &amp;amp;&amp;amp; injectStyle) injectStyle(css)\r\n\/\/\u6ce8\u518c\u81ea\u5b9a\u4e49\u6807\u7b7e\r\n__tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }\r\nreturn name\r\n}\r\n<\/pre>\n<p>Riot\u7684\u6ce8\u518c\u6807\u7b7e\u6d41\u7a0b\u975e\u5e38\u7b80\u5355\uff0c\u4ec5\u505a\u4e86\u4e24\u6b65\u52a8\u4f5c\uff1a\u63d2\u5165CSS,\u5b58\u50a8\u5230__tagImpl\u5bf9\u8c61\u5f53\u4e2d<br \/>\n\u6ce8\u518c\u5b8c\u81ea\u5b9a\u4e49\u6807\u7b7e\u4e4b\u540e\u5c31\u53ef\u4ee5\u4f7f\u7528riot.mount\u5c06\u81ea\u5b9a\u4e49\u6807\u7b7e\u8f7d\u5165\u8fdb\u5b9e\u9645\u7684DOM\u8282\u70b9.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nriot.mount = function(selector, tagName, opts) {\r\n\r\nvar els,\r\nallTags,\r\ntags = []\r\n\r\n\/\/\u6dfb\u52a0Riot\u6807\u7b7e\r\n\r\nfunction addRiotTags(arr) {\r\nvar list = ''\r\n\/\/\u904d\u5386\u6bcf\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6dfb\u52a0Riot\u6807\u8bb0\r\neach(arr, function (e) {\r\nlist += ', *[' + RIOT_TAG + '=&quot;' + e.trim() + '&quot;]'\r\n})\r\n\/\/\u8fd4\u56de\u6807\u8bb0List\r\nreturn list\r\n}\r\n\r\n\/\/\u8fd4\u56de\u6240\u6709\u6807\u7b7e\r\n\r\nfunction selectAllTags() {\r\n\/\/\u8fd4\u56de\u81ea\u5b9a\u4e49\u6807\u7b7e\u5217\u8868\r\nvar keys = Object.keys(__tagImpl)\r\n\/\/\u8fd4\u56de\u65b0\u7684\u81ea\u5b9a\u4e49\u6807\u7b7e\u5217\u8868\r\nreturn keys + addRiotTags(keys)\r\n}\r\n\r\nfunction pushTags(root) {\r\nvar last\r\n\r\n\/\/\u5982\u679croot\u6807\u7b7e\u5b58\u5728\r\nif (root.tagName) {\r\n\/\/\u5982\u679croot\u6807\u7b7e\u8fd8\u672a\u521d\u59cb\u5316\r\nif (tagName &amp;amp;&amp;amp; (!(last = getAttr(root, RIOT_TAG)) || last != tagName))\r\n\/\/\u8bbe\u7f6eRIOT_TAG\r\nsetAttr(root, RIOT_TAG, tagName)\r\n\/\/\u63d2\u5165\u5230root\u4e2d\r\nvar tag = mountTo(root, tagName || root.getAttribute(RIOT_TAG) || root.tagName.toLowerCase(), opts)\r\n\/\/\u5982\u679c\u63d2\u5165\u6210\u529f\uff0c\u5219push\u5230tags\u5217\u8868\u4e2d\r\nif (tag) tags.push(tag)\r\n} else if (root.length)\r\n\/\/\u6bcf\u4e00\u4e2a\u5bf9\u8c61\u90fd\u8fdb\u884cmountTo\u64cd\u4f5c\r\neach(root, pushTags)\r\n}\r\n\/\/ ----- mount code ----\r\n\/\/\u5982\u679c\u521d\u59cb\u5316\u5c5e\u6027\u5b58\u5728(\u5bf9\u8c61)\r\nif (typeof tagName === T_OBJECT) {\r\nopts = tagName\r\ntagName = 0\r\n}\r\n\r\n\/\/\u6807\u7b7e\u68c0\u6d4b:\u5b57\u7b26\u4e32\r\nif (typeof selector === T_STRING) {\r\n\/\/\u5168\u90e8\u8282\u70b9\r\nif (selector === '*')\r\n\/\/ \u9009\u53d6\u6240\u6709\u81ea\u5b9a\u4e49\u8282\u70b9\r\nselector = allTags = selectAllTags()\r\nelse\r\n\/\/ \u9009\u53d6\u5f53\u524d\u4f20\u5165\u8282\u70b9\r\nselector += addRiotTags(selector.split(','))\r\n\r\n\/\/ \u9009\u62e9\u5668\u9009\u62e9DOM\u8282\u70b9\r\nels = selector ? $$(selector) : []\r\n}\r\nelse\r\n\/\/ \u4f20\u5165\u7684\u662fDOM\u5bf9\u8c61\uff0c\u76f4\u63a5\u9009\u53d6\r\nels = selector\r\n\r\n\/\/ \u5982\u679c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e3a\u8282\u70b9\r\nif (tagName === '*') {\r\n\/\/ \u83b7\u53d6\u6240\u6709\u8282\u70b9\r\ntagName = allTags || selectAllTags()\r\n\/\/ \u5982\u679c\u662f\u5355\u4e2a\u8282\u70b9\r\nif (els.tagName)\r\nels = $$(tagName, els)\r\nelse {\r\nvar nodeList = []\r\n\u9009\u53d6\u6240\u6709_el\u8282\u70b9\u4e0b\u7684tagName\u8282\u70b9\r\neach(els, function (_el) {\r\nnodeList.push($$(tagName, _el))\r\n})\r\nels = nodeList\r\n}\r\n\/\/ get rid of the tagName\r\ntagName = 0\r\n}\r\n\r\n\/\/\u5355\u4e2a\u8282\u70b9\r\nif (els.tagName)\r\npushTags(els)\r\nelse\r\n\/\/\u6279\u91cf\u8282\u70b9\r\neach(els, pushTags)\r\n\/\/\u8fd4\u56de\u8282\u70b9\u5bf9\u8c61\r\nreturn tags\r\n}\r\n<\/pre>\n<p>\u4ece\u4ee3\u7801\u4e2d\u53ef\u4ee5\u770b\u51fa\uff0cmount\u65b9\u6cd5\u4e3b\u8981\u5b8c\u6210\u5206\u6790DOM\u8282\u70b9\u5e76\u4f9d\u6b21\u751f\u6210\u81ea\u5b9a\u4e49\u6807\u7b7e\u7684\u8fc7\u7a0b\uff0e\u800c\u5177\u4f53\u7684\u751f\u6210\u903b\u8f91\u5219\u5728mountTo\u65b9\u6cd5\u4e2d.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction mountTo(root, tagName, opts) {\r\n\/\/\u4ece\u6ce8\u518c\u7684\u6807\u7b7e\u5e93\u5bf9\u8c61\u4e2d\u83b7\u53d6\r\nvar tag = __tagImpl[tagName],\r\n\/\/ \u5b58\u50a8root\u4e2d\u7684innerHTML,\u5b9e\u4e3ayield\r\ninnerHTML = root._innerHTML = root._innerHTML || root.innerHTML\r\n\/\/ \u6e05\u7a7ainnerHTML\r\nroot.innerHTML = ''\r\n\/\/\u81ea\u5b9a\u4e49\u6807\u7b7e\u548c\u5bb9\u5668\u90fd\u5b58\u5728\uff0c\u751f\u6210tag\u5bf9\u8c61\r\nif (tag &amp;amp;&amp;amp; root) tag = new Tag(tag, { root: root, opts: opts }, innerHTML)\r\n\/\/tag\u5bf9\u8c61\u751f\u6210\u6210\u529f\r\nif (tag &amp;amp;&amp;amp; tag.mount) {\r\n\/\/\u63d2\u5165\u5230\u6587\u6863\u4e2d\r\ntag.mount()\r\n\/\/ \u6dfb\u52a0\u8be5tag\u5bf9\u8c61\u5230__virtualDom\u5217\u8868\u4e2d\r\nif (!contains(__virtualDom, tag)) __virtualDom.push(tag)\r\n}\r\n\/\/\u8fd4\u56detag\u5bf9\u8c61\r\nreturn tag\r\n}\r\n<\/pre>\n<p>mountTo\u505a\u4e86\u4e24\u9879\u5de5\u4f5c:\u5b58\u50a8&amp;\u6e05\u7a7a\u5f53\u524d\u8282\u70b9,\u6ce8\u518c\u65b0tag\u5230virtualDOM\u4e2d\uff0c\u7136\u540e\u5c06\u5176\u4f59\u5de5\u4f5c\u4ea4\u7ed9\u4e86Tag\u7c7b\uff1a<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction Tag(impl, conf, innerHTML) {\r\n\r\n\/\/\u4f7ftag\u5177\u6709\u4e8b\u4ef6\u529f\u80fd\r\nvar self = riot.observable(this),\r\n\/\/\u7ee7\u627f\u4f20\u5165\u7684opts\r\nopts = inherit(conf.opts) || {},\r\n\/\/\u521b\u5efaDOM\u5bb9\u5668\r\ndom = mkdom(impl.tmpl),\r\n\/\/\u7236\u8282\u70b9\r\nparent = conf.parent,\r\n\/\/\u662f\u5faa\u73af\u8282\u70b9\r\nisLoop = conf.isLoop,\r\n\/\/\r\nhasImpl = conf.hasImpl,\r\n\/\/\u83b7\u53d6\u5916\u7f6e\u6570\u636e\r\nitem = cleanUpData(conf.item),\r\n\/\/\u8868\u8fbe\u5f0f\u5217\u8868\r\nexpressions = [],\r\n\/\/\u5b50\u8282\u70b9\u5217\u8868\r\nchildTags = [],\r\n\/\/DOM\u8282\u70b9\r\nroot = conf.root,\r\n\/\/\u6269\u5c55\u65b9\u6cd5\r\nfn = impl.fn,\r\n\/\/\u6807\u7b7e\u540d\u79f0\r\ntagName = root.tagName.toLowerCase(),\r\n\/\/\u5c5e\u6027\r\nattr = {},\r\npropsInSyncWithParent = []\r\n\/\/\u82e5\u5df2\u7ecf\u5b58\u5728\uff0c\u5219\u5378\u8f7d\r\nif (fn &amp;amp;&amp;amp; root._tag) root._tag.unmount(true)\r\n\r\n\/\/ \u6807\u8bb0\u4e3a\u5c1a\u672a\u8f7d\u5165\r\nthis.isMounted = false\r\n\/\/\u662f\u5426\u4e3a\u5faa\u73af\u8282\u70b9\r\nroot.isLoop = isLoop\r\n\r\n\/\/ \u4fdd\u6301tag\u5bf9\u8c61\u7684\u5f15\u7528\uff0c\u8fd9\u6837\u53ef\u4ee5\u591a\u6b21\u8fdb\u884c\u8be5\u6807\u7b7e\u7684\u88c5\u8f7d\r\nroot._tag = this\r\n\r\n\/\/ \u4e3a\u8be5tag\u5bf9\u8c61\u5206\u914d\u552f\u4e00id,\u8fd9\u6837\u53ef\u4ee5\u63d0\u5347virtualDOM\u7684\u6e32\u67d3\u6548\u679c\r\n\/\/\u81f3\u4e8e\u5982\u4f55\u63d0\u5347\uff0c\u5728\u968f\u540e\u7684\u5206\u6790\u4e2d\u5c06\u770b\u5230\r\ndefineProperty(this, '_riot_id', ++__uid)\r\n\r\n\/\/\u5728tag\u5bf9\u8c61\u4e0a\u6ce8\u518c\u8fd9\u4e9b\u5f15\u7528\r\nextend(this, { parent: parent, root: root, opts: opts, tags: {} }, item)\r\n\r\n\/\/ \u904d\u5386\u6bcf\u4e00\u4e2a\u5c5e\u6027\r\neach(root.attributes, function(el) {\r\nvar val = el.value\r\n\/\/ \u5c06\u5177\u6709\u8868\u8fbe\u5f0f\u7684\u5c5e\u6027\u653e\u5165attr\u5bf9\u8c61\u4e2d\r\nif (tmpl.hasExpr(val)) attr[el.name] = val\r\n})\r\n\r\n\/\/dom\u4e2d\u5177\u6709\u5185\u5bb9\u5e76\u4e14\u4e0d\u5b58\u5728\u7279\u6b8a\u8282\u70b9\r\nif (dom.innerHTML &amp;amp;&amp;amp; !\/^(select|optgroup|table|tbody|tr|col(?:group)?)$\/.test(tagName))\r\n\/\/ \u5c06yeild\u66ff\u6362\u4e3ainnerHTML\u4e2d\u7684\u5185\u5bb9\r\ndom.innerHTML = replaceYield(dom.innerHTML, innerHTML)\r\n\r\n\/\/ options\r\nfunction updateOpts() {\r\nvar ctx = hasImpl &amp;amp;&amp;amp; isLoop ? self : parent || self\r\n\r\n\/\/ update opts from current DOM attributes\r\neach(root.attributes, function(el) {\r\nopts[toCamel(el.name)] = tmpl(el.value, ctx)\r\n})\r\n\/\/ recover those with expressions\r\neach(Object.keys(attr), function(name) {\r\nopts[toCamel(name)] = tmpl(attr[name], ctx)\r\n})\r\n}\r\n\r\nfunction normalizeData(data) {\r\nfor (var key in item) {\r\nif (typeof self[key] !== T_UNDEF &amp;amp;&amp;amp; isWritable(self, key))\r\nself[key] = data[key]\r\n}\r\n}\r\n\r\nfunction inheritFromParent () {\r\nif (!self.parent || !isLoop) return\r\neach(Object.keys(self.parent), function(k) {\r\n\/\/ some properties must be always in sync with the parent tag\r\nvar mustSync = !contains(RESERVED_WORDS_BLACKLIST, k) &amp;amp;&amp;amp; contains(propsInSyncWithParent, k)\r\nif (typeof self[k] === T_UNDEF || mustSync) {\r\n\/\/ track the property to keep in sync\r\n\/\/ so we can keep it updated\r\nif (!mustSync) propsInSyncWithParent.push(k)\r\nself[k] = self.parent[k]\r\n}\r\n})\r\n}\r\n\r\ndefineProperty(this, 'update', function(data) {\r\n\r\n\/\/\u9632\u6b62\u8282\u70b9\u7684\u6838\u5fc3\u65b9\u6cd5\u88ab\u8986\u76d6\r\ndata = cleanUpData(data)\r\n\/\/\u5904\u7406\u7236\u8282\u70b9\u7684\u5185\u7f6e\u5c5e\u6027\r\ninheritFromParent()\r\n\/\/\u5904\u7406\u975e\u53ef\u5199\u5c5e\u6027\u4e0eundefined\u5c5e\u6027\r\nif (data &amp;amp;&amp;amp; typeof item === T_OBJECT) {\r\nnormalizeData(data)\r\nitem = data\r\n}\r\n\r\n\/\/\u6d45\u62f7\u8d1d\r\nextend(self, data)\r\n\/\/\u5c5e\u6027\u540d\u8f6c\u6362\r\nupdateOpts()\r\n\/\/\u89e6\u53d1update\u4e8b\u4ef6(\u5f00\u59cb\u66f4\u65b0)\r\nself.trigger('update', data)\r\n\/\/\u66f4\u65b0\u8868\u8fbe\u5f0f\r\nupdate(expressions, self)\r\n\/\/\u89e6\u53d1updated\u4e8b\u4ef6(\u66f4\u65b0\u5b8c\u6bd5)\r\nself.trigger('updated')\r\nreturn this\r\n})\r\n\r\ndefineProperty(this, 'mixin', function() {\r\neach(arguments, function(mix) {\r\nmix = typeof mix === T_STRING ? riot.mixin(mix) : mix\r\neach(Object.keys(mix), function(key) {\r\n\/\/ bind methods to self\r\nif (key != 'init')\r\nself[key] = isFunction(mix[key]) ? mix[key].bind(self) : mix[key]\r\n})\r\n\/\/ init method will be called automatically\r\nif (mix.init) mix.init.bind(self)()\r\n})\r\nreturn this\r\n})\r\n\r\ndefineProperty(this, 'mount', function() {\r\n\r\n\/\/\u8bbe\u7f6e\u540d\u8f6c\u6362\r\nupdateOpts()\r\n\r\n\/\/ \u6dfb\u52a0\u81ea\u5b9a\u4e49\u51fd\u6570\r\nif (fn) fn.call(self, opts)\r\n\r\n\/\/ \u9012\u5f52\u5904\u7406\u8868\u8fbe\u5f0f\r\nparseExpressions(dom, self, expressions)\r\n\r\n\/\/ \u52a0\u8f7d\u81ea\u5b9a\u4e49\u5b50\u8282\u70b9\r\ntoggle(true)\r\n\r\n\/\/ \u83b7\u53d6\u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u63d0\u53d6\u8868\u8fbe\u5f0f\r\nif (impl.attrs || hasImpl) {\r\nwalkAttributes(impl.attrs, function (k, v) { setAttr(root, k, v) })\r\nparseExpressions(self.root, self, expressions)\r\n}\r\n\r\n\/\/\u81ea\u5b9a\u4e49\u8282\u70b9\u4e0d\u662f\u5b50\u8282\u70b9\u4e5f\u975e\u5faa\u73af\u8282\u70b9,\u6267\u884c\u66f4\u65b0\r\nif (!self.parent || isLoop) self.update(item)\r\n\r\n\/\/\u4ec5\u9650\u5185\u90e8\u4f7f\u7528\u7684mount\u4e8b\u4ef6\u4e4b\u540e\u7684\u4e8b\u4ef6\uff0c\u5f00\u53d1\u8005\u9700\u8981\u4f7f\u7528mounted\u4e8b\u4ef6\r\nself.trigger('before-mount')\r\n\r\nif (isLoop &amp;amp;&amp;amp; !hasImpl) {\r\n\/\/ \u4eceloop\u8282\u70b9\u4e2d\u53d6\u51fa\u5b9e\u9645\u8282\u70b9\r\nself.root = root = dom.firstChild\r\n\r\n} else {\r\n\/\/\u63d2\u5165\u5230root\u8282\u70b9\u4e2d\r\nwhile (dom.firstChild) root.appendChild(dom.firstChild)\r\nif (root.stub) self.root = root = parent.root\r\n}\r\n\r\n\/\/ \u63d2\u5165\u5230root\u8282\u70b9\u4e2d\r\nif (isLoop)\r\nparseNamedElements(self.root, self.parent, null, true)\r\n\r\n\/\/ \u89e6\u53d1\u9876\u5c42\u81ea\u5b9a\u4e49\u8282\u70b9\u7684mount\u4e8b\u4ef6\uff0c\u8bbe\u7f6e\u5b9a\u4e49\u8282\u70b9\u7684\u5df2\u52a0\u8f7d\u6807\u8bb0\r\nif (!self.parent || self.parent.isMounted) {\r\nself.isMounted = true\r\nself.trigger('mount')\r\n}\r\n\/\/ \u89e6\u53d1\u5f53\u524d\u8282\u70b9\u7684mount\u4e8b\u4ef6\uff0c\u540c\u65f6\u8bbe\u7f6e\u7236\u8282\u70b9\u548c\u5f53\u524d\u8282\u70b9\u7684\u5df2\u52a0\u8f7d\u6807\u8bb0\r\nelse self.parent.one('mount', function() {\r\nif (!isInStub(self.root)) {\r\nself.parent.isMounted = self.isMounted = true\r\nself.trigger('mount')\r\n}\r\n})\r\n})\r\n\r\ndefineProperty(this, 'unmount', function(keepRootTag) {\r\n\/\/\u5f85\u5378\u8f7d\u8282\u70b9\r\nvar el = root,\r\n\/\/\u7236\u8282\u70b9\r\np = el.parentNode,\r\nptag\r\n\r\n\/\/\u89e6\u53d1\u5378\u8f7d\u524d\u4e8b\u4ef6\r\nself.trigger('before-unmount')\r\n\r\n\/\/ \u4ecevirtualDom\u4e2d\u5220\u9664\r\n__virtualDom.splice(__virtualDom.indexOf(self), 1)\r\n\r\n\/\/\u5177\u6709\u76f8\u5173\u5176\u4ed6\u8282\u70b9\r\nif (this._virts) {\r\neach(this._virts, function(v) {\r\nv.parentNode.removeChild(v)\r\n})\r\n}\r\n\r\n\/\/\u5b58\u5728\u7236\u8282\u70b9\r\nif (p) {\r\n\r\nif (parent) {\r\nptag = getImmediateCustomParentTag(parent)\r\n\/\/ \u4ece\u7236\u8282\u70b9\u4e2d\u5220\u9664\u6240\u6709\u8be5\u6807\u7b7e\u8282\u70b9\r\nif (isArray(ptag.tags[tagName]))\r\neach(ptag.tags[tagName], function(tag, i) {\r\nif (tag._riot_id == self._riot_id)\r\nptag.tags[tagName].splice(i, 1)\r\n})\r\nelse\r\nptag.tags[tagName] = undefined\r\n}\r\n\r\nelse\r\n\/\/\u5220\u9664\u5f53\u524d\u8282\u70b9\u5185\u9996\u8282\u70b9\r\nwhile (el.firstChild) el.removeChild(el.firstChild)\r\n\r\n\/\/\u5220\u9664\u6839\u8282\u70b9\u4e2d\u7684el\r\nif (!keepRootTag)\r\np.removeChild(el)\r\nelse\r\n\/\/ \u4ec5\u5220\u9664riot\u63a7\u5236\uff0c\u4e0d\u5220\u9664\u8282\u70b9\r\nremAttr(p, 'riot-tag')\r\n}\r\n\r\nself.trigger('unmount')\r\ntoggle()\r\nself.off('*')\r\nself.isMounted = false\r\n\/\/ somehow ie8 does not like `delete root._tag`\r\nroot._tag = null\r\n\r\n})\r\n\r\nfunction toggle(isMount) {\r\n\r\n\/\/ mount\/unmount children\r\neach(childTags, function(child) { child[isMount ? 'mount' : 'unmount']() })\r\n\r\n\/\/ listen\/unlisten parent (events flow one way from parent to children)\r\nif (parent) {\r\nvar evt = isMount ? 'on' : 'off'\r\n\r\n\/\/ the loop tags will be always in sync with the parent automatically\r\nif (isLoop)\r\nparent[evt]('unmount', self.unmount)\r\nelse\r\nparent[evt]('update', self.update)[evt]('unmount', self.unmount)\r\n}\r\n}\r\n\r\n\/\/ \u63d2\u5165\u8282\u70b9\uff0c\r\nparseNamedElements(dom, this, childTags)\r\n\r\n}\r\n<\/pre>\n<p>\u4e0a\u9762\u7684\u90e8\u5206\u4e3b\u8981\u5de5\u4f5c\u662f\u4e3atag\u5bf9\u8c61\u6dfb\u52a0\u76f8\u5173\u65b9\u6cd5\u5c5e\u6027\uff0c\u4e3a\u751f\u6210DOM\u5904\u7406\u505a\u51c6\u5907,\u51c6\u5907\u5b8c\u6210\u4e4b\u540e\u4f1a\u8c03\u7528parseNamedElements\u51fd\u6570\uff0cparseNamedElements\u51fd\u6570\u4e3b\u8981\u662f\u8c03\u7528\u9012\u5f52\u51fd\u6570walk<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction parseNamedElements(root, tag, childTags, forceParsingNamed) {\r\n\/\/\u9012\u5f52\u533f\u540d\u51fd\u6570\r\nwalk(root, function(dom) {\r\n\/\/\u4e3aelement\u8282\u70b9\r\nif (dom.nodeType == 1) {\r\n\/\/\u5faa\u73afDOM\r\ndom.isLoop = dom.isLoop || (dom.parentNode &amp;amp;&amp;amp; dom.parentNode.isLoop || getAttr(dom, 'each')) ? 1 : 0\r\n\r\n\/\/ \u5b58\u5728\u81ea\u5b9a\u4e49\u8282\u70b9\r\nif (childTags) {\r\n\/\/\u83b7\u53d6\u81ea\u5b9a\u4e49tag\r\nvar child = getTag(dom)\r\n\/\/\u5b58\u5728\u81ea\u5b9a\u4e49tag\u5e76\u4e14\u4e0d\u662f\u5faa\u73afDOM\r\nif (child &amp;amp;&amp;amp; !dom.isLoop)\r\n\/\/\u521d\u59cb\u5316tag\u5e76push\u5230childTags\u5217\u8868\r\nchildTags.push(initChildTag(child, {root: dom, parent: tag}, dom.innerHTML, tag))\r\n}\r\n\/\/\r\nif (!dom.isLoop || forceParsingNamed)\r\nsetNamed(dom, tag, [])\r\n}\r\n})\r\n\r\n}\r\n\r\n\/\/\u9012\u5f52\u51fd\u6570\r\nfunction walk(dom, fn) {\r\n\/\/ \u5982\u679cDOM\u8282\u70b9\u5b58\u5728\r\nif (dom) {\r\n\/\/\u5982\u679c\u6267\u884cfn\u8fd4\u56defalse,\u7ed3\u675f\u5f53\u524d\u9012\u5f52\u64cd\u4f5c,\u8fd4\u56de\u4e0a\u4e00\u5c42\r\nif (fn(dom) === false) return\r\nelse {\r\n\/\/\u9009\u53d6\u7b2c\u4e00\u4e2a\u5b50\u8282\u70b9\r\ndom = dom.firstChild\r\n\r\nwhile (dom) {\r\n\/\/\u9012\u5f52\u6267\u884c\r\nwalk(dom, fn)\r\n\/\/\u79fb\u5230\u4e0b\u4e00\u4e2a\u8282\u70b9\r\ndom = dom.nextSibling\r\n}\r\n}\r\n}\r\n}\r\n<\/pre>\n<p>\u9012\u5f52\u5904\u7406\u4e3b\u8981\u5904\u7406\u4ee5\u4e0b\u4e24\u90e8\u5206:<br \/>\n\u81ea\u5b9a\u4e49\u5b50\u8282\u70b9<br \/>\n\u5177\u6709name\u5c5e\u6027\u7684\u8282\u70b9<\/p>\n<p>\u5904\u7406\u5b8c\u4e4b\u540e\uff0ctag\u5bf9\u8c61\u5c06\u8fd4\u56de\uff0c\u7ee7\u7eed\u56de\u5230\u8c03\u7528\u5904\u5411\u4e0b\u6267\u884ctag.mount,\u5b9e\u9645\u4ee3\u7801\u5728new Tag()\u65f6\u88ab\u6dfb\u52a0\u8fdb,\u4e3b\u8981\u63d0\u53d6\u6240\u6709\u8868\u8fbe\u5f0f\uff0c\u5c06\u63d0\u53d6\u5904\u7684\u8868\u8fbe\u5f0f\u4f20\u7ed9update\u51fd\u6570\u8fdb\u884c\u8868\u8fbe\u5f0f\u8ba1\u7b97,update\u51fd\u6570\u5982\u4e0b\uff1a<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction update(expressions, tag) {\r\n\/\/\u904d\u5386\u6bcf\u4e00\u4e2a\u8868\u8fbe\u5f0f\r\neach(expressions, function(expr, i) {\r\n\/\/\u8868\u8fbe\u5f0f\u8282\u70b9\r\nvar dom = expr.dom,\r\n\/\/\u8868\u8fbe\u5f0f\u5c5e\u6027\u503c(\u5982\u679c\u662f\u5c5e\u6027\u8282\u70b9)\r\nattrName = expr.attr,\r\n\/\/\u8ba1\u7b97\u8868\u8fbe\u5f0f\r\nvalue = tmpl(expr.expr, tag),\r\n\/\/\u8868\u8fbe\u5f0f\u8282\u70b9\u7684\u7236\u8282\u70b9\r\nparent = expr.dom.parentNode\r\n\/\/fix\u3000\u5e03\u5c14\u8868\u8fbe\u5f0f\r\nif (expr.bool)\r\nvalue = value ? attrName : false\r\n\/\/fix\u3000\u975e\u5e03\u5c14\u8868\u8fbe\u5f0f\r\nelse if (value == null)\r\nvalue = ''\r\n\r\n\/\/ textarea\u8282\u70b9\u7684\u7279\u6b8a\u5904\u7406\r\nif (parent &amp;amp;&amp;amp; parent.tagName == 'TEXTAREA') value = ('' + value).replace(\/riot-\/g, '')\r\n\r\n\/\/ \u65e0\u53d8\u5316\r\nif (expr.value === value) return\r\nexpr.value = value\r\n\r\n\/\/ \u8868\u8fbe\u5f0f\u6240\u5728\u8282\u70b9\u662f\u6587\u672c\u8282\u70b9\r\nif (!attrName) {\r\n\/\/\u66ff\u6362\u5f53\u524d\u503c\r\ndom.nodeValue = '' + value \/\/ #815 related\r\nreturn\r\n}\r\n\r\n\/\/ \u5220\u9664\u539f\u6765\u7684\u5c5e\u6027\r\nremAttr(dom, attrName)\r\n\/\/ \u5982\u679c\u662f\u51fd\u6570\r\nif (isFunction(value)) {\r\n\/\/\u7ed1\u5b9a\u4e8b\u4ef6\r\nsetEventHandler(attrName, value, dom, tag)\r\n\r\n\/\/ \u5177\u6709\u903b\u8f91\u7684expression\r\n} else if (attrName == 'if') {\r\nvar stub = expr.stub,\r\nadd = function() { insertTo(stub.parentNode, stub, dom) },\r\nremove = function() { insertTo(dom.parentNode, dom, stub) }\r\n\r\n\/\/ \u6dfb\u52a0\u5230DOM\u8282\u70b9\r\nif (value) {\r\nif (stub) {\r\nadd()\r\ndom.inStub = false\r\n\/\/ avoid to trigger the mount event if the tags is not visible yet\r\n\/\/ maybe we can optimize this avoiding to mount the tag at all\r\nif (!isInStub(dom)) {\r\nwalk(dom, function(el) {\r\nif (el._tag &amp;amp;&amp;amp; !el._tag.isMounted) el._tag.isMounted = !!el._tag.trigger('mount')\r\n})\r\n}\r\n}\r\n\/\/ \u4eceDOM\u8282\u70b9\u5220\u9664\r\n} else {\r\nstub = expr.stub = stub || document.createTextNode('')\r\n\/\/ if the parentNode is defined we can easily replace the tag\r\nif (dom.parentNode)\r\nremove()\r\n\/\/ otherwise we need to wait the updated event\r\nelse (tag.parent || tag).one('updated', remove)\r\n\r\ndom.inStub = true\r\n}\r\n\/\/ show \/ hide\u3000\u5c5e\u6027\u7279\u6b8a\u5904\u7406\r\n} else if (\/^(show|hide)$\/.test(attrName)) {\r\nif (attrName == 'hide') value = !value\r\ndom.style.display = value ? '' : 'none'\r\n\r\n\/\/ value\u5c5e\u6027\u7279\u6b8a\u5904\u7406\r\n} else if (attrName == 'value') {\r\ndom.value = value\r\n\r\n\/\/ &lt;img src=&quot;{ expr }&quot; alt=&quot;&quot; \/&gt;\u3000\u7279\u6b8a\u5904\u7406\r\n} else if (startsWith(attrName, RIOT_PREFIX) &amp;amp;&amp;amp; attrName != RIOT_TAG) {\r\nif (value)\r\nsetAttr(dom, attrName.slice(RIOT_PREFIX.length), value)\r\n\/\/\u666e\u901a\u5c5e\u6027\r\n} else {\r\nif (expr.bool) {\r\ndom[attrName] = value\r\nif (!value) return\r\n}\r\n\/\/Object\u65e0\u6cd5\u8d4b\u503c\u5230\u5c5e\u6027\u5f53\u4e2d\r\nif (typeof value !== T_OBJECT) setAttr(dom, attrName, value)\r\n\r\n}\r\n\r\n})\r\n\r\n}\r\n<\/pre>\n<p>\u6267\u884c\u5b8cupdate\u4e4b\u540e\uff0cDOM\u4e2d\u7684\u6570\u636e\u5df2\u7ecf\u66f4\u65b0\u5b8c\u6bd5\uff0c\u63a5\u7740\u4f1a\u6267\u884cmount\u7684\u540e\u7eed\u64cd\u4f5c<\/p>\n<p>\u5206\u6790\u4e2d\u53ef\u4ee5\u53d1\u73b0\uff0criot\u5bf9\u4e8etext\u8282\u70b9\u548c\u5c5e\u6027\u8282\u70b9\u7684\u63a7\u5236\u80fd\u529b\u76f8\u5bf9\u597d\uff0c\u800c\u5bf9\u4e8e\u52a8\u6001\u5220\u9664DOM\u8282\u70b9\uff0c\u5219\u4f1a\u51fa\u73b0\u4e00\u4e9b\u95ee\u9898\uff0c\u800cReact\u7684batchUpdate\u7b97\u6cd5\u53ef\u4ee5diff\u8282\u70b9\u7ea7\u7684\u53d8\u5316\uff0c\u800c\u5feb\u901f\u505a\u51fa\u53cd\u5e94\uff0eriot\u5bf9DOM\u8282\u70b9\u7684\u63a7\u5236\u4e0d\u662f\u589e\u52a0\u5220\u9664\u7ea7\u522b\u7684\u63a7\u5236\uff0c\u800c\u662fcss\u7ea7\u522b\u7684\u63a7\u5236\uff0c\u8fd9\u6709\u533a\u522b\u4e8eReact.<\/p>\n<p>riot\u7684\u6570\u636e\u66f4\u65b0\u4e0d\u662f\u81ea\u52a8\u5316\u7684\uff0c\u9700\u8981\u901a\u8fc7\u624b\u52a8\u53bb\u7ef4\u62a4DOM\u4e0e\u6570\u636e\u6a21\u578b\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u907f\u514d\u51fa\u73b0\u4e0d\u540c\u6b65\u7684\u95ee\u9898\uff0c\u800cReact\u7684update\u662f\u81ea\u52a8\u5316\u7684\uff0c\u4f46\u4ece\u4ee5\u524d\u4f7f\u7528\u7c7bReact\u6846\u67b6\u7684\u7ecf\u9a8c\u770b\u6765\uff0c\u5b8c\u5168\u7684\u81ea\u52a8update\u8fd8\u662f\u4e0d\u53ef\u9760\uff0c\u7ec4\u4ef6\u4e4b\u95f4\u7684\u901a\u4fe1\u8fd8\u662f\u514d\u4e0d\u4e86\u624b\u52a8\u66f4\u65b0\uff0c\u56e0\u6b64\u8fd9\u4e2a\u4e1c\u897f\u6709\u7684\u65f6\u5019\u611f\u89c9\u6bd4\u8f83\u9e21\u808b\uff0c\u5982\u679c\u9700\u8981\u7684\u8bddriot\u4e5f\u53ef\u4ee5\u6574\u5408\u8fdb\u76f8\u5173\u529f\u80fd\uff0e<\/p>\n<p>\u603b\u4f53\u6765\u8bf4,riot.js\u6846\u67b6\u4ee3\u7801\u91cf\u5c11\uff0c\u6613\u7406\u89e3\uff0c\u4e8c\u6b21\u5f00\u53d1\u7684\u6210\u672c\u6bd4\u8f83\u4f4e\uff0e\u6240\u4ee5\u6bd4\u8f83\u9002\u5408\u5b9a\u5236\u5316\u7a0b\u5ea6\u9ad8\u7684\u9879\u76ee\u4e0e\u5c0f\u578b\u9879\u76ee\u5feb\u901f\u5f00\u53d1\uff0e<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e0a\u4e00\u7bc7\u65e5\u5fd7\u7b80\u5355\u7684\u4ecb\u7ecd\u4e86\u4e00\u4e0bRiot.js\u8fd9\u4e2a\u4e1c\u897f\uff0c\u8fd9\u4e09\u5468\u4ee5\u6765\u6211\u4e00\u76f4\u518d\u770bReact\u7684\u6e90\u7801\uff0c\u4f9d\u7136\u5bf9\u5b83\u7684batchU &hellip; <a href=\"https:\/\/douhan.li\/?p=50\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">Riot.js\u6e90\u7801\u5206\u6790<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[3,4,6,5],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/posts\/50"}],"collection":[{"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/douhan.li\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=50"}],"version-history":[{"count":5,"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/posts\/50\/revisions"}],"predecessor-version":[{"id":55,"href":"https:\/\/douhan.li\/index.php?rest_route=\/wp\/v2\/posts\/50\/revisions\/55"}],"wp:attachment":[{"href":"https:\/\/douhan.li\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=50"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/douhan.li\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=50"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/douhan.li\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=50"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}