node.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /**
  2. * 编辑器模拟的节点类
  3. * @file
  4. * @module UE
  5. * @class uNode
  6. * @since 1.2.6.1
  7. */
  8. /**
  9. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  10. * @unfile
  11. * @module UE
  12. */
  13. (function() {
  14. /**
  15. * 编辑器模拟的节点类
  16. * @unfile
  17. * @module UE
  18. * @class uNode
  19. */
  20. /**
  21. * 通过一个键值对,创建一个uNode对象
  22. * @constructor
  23. * @param { Object } attr 传入要创建的uNode的初始属性
  24. * @example
  25. * ```javascript
  26. * var node = new uNode({
  27. * type:'element',
  28. * tagName:'span',
  29. * attrs:{style:'font-size:14px;'}
  30. * })
  31. * ```
  32. */
  33. var uNode = (UE.uNode = function(obj) {
  34. this.type = obj.type;
  35. this.data = obj.data;
  36. this.tagName = obj.tagName;
  37. this.parentNode = obj.parentNode;
  38. this.attrs = obj.attrs || {};
  39. this.children = obj.children;
  40. });
  41. var notTransAttrs = {
  42. href: 1,
  43. src: 1,
  44. _src: 1,
  45. _href: 1,
  46. cdata_data: 1
  47. };
  48. var notTransTagName = {
  49. style: 1,
  50. script: 1
  51. };
  52. var indentChar = " ",
  53. breakChar = "\n";
  54. function insertLine(arr, current, begin) {
  55. arr.push(breakChar);
  56. return current + (begin ? 1 : -1);
  57. }
  58. function insertIndent(arr, current) {
  59. //插入缩进
  60. for (var i = 0; i < current; i++) {
  61. arr.push(indentChar);
  62. }
  63. }
  64. //创建uNode的静态方法
  65. //支持标签和html
  66. uNode.createElement = function(html) {
  67. if (/[<>]/.test(html)) {
  68. return UE.htmlparser(html).children[0];
  69. } else {
  70. return new uNode({
  71. type: "element",
  72. children: [],
  73. tagName: html
  74. });
  75. }
  76. };
  77. uNode.createText = function(data, noTrans) {
  78. return new UE.uNode({
  79. type: "text",
  80. data: noTrans ? data : utils.unhtml(data || "")
  81. });
  82. };
  83. function nodeToHtml(node, arr, formatter, current) {
  84. switch (node.type) {
  85. case "root":
  86. for (var i = 0, ci; (ci = node.children[i++]); ) {
  87. //插入新行
  88. if (
  89. formatter &&
  90. ci.type == "element" &&
  91. !dtd.$inlineWithA[ci.tagName] &&
  92. i > 1
  93. ) {
  94. insertLine(arr, current, true);
  95. insertIndent(arr, current);
  96. }
  97. nodeToHtml(ci, arr, formatter, current);
  98. }
  99. break;
  100. case "text":
  101. isText(node, arr);
  102. break;
  103. case "element":
  104. isElement(node, arr, formatter, current);
  105. break;
  106. case "comment":
  107. isComment(node, arr, formatter);
  108. }
  109. return arr;
  110. }
  111. function isText(node, arr) {
  112. if (node.parentNode.tagName == "pre") {
  113. //源码模式下输入html标签,不能做转换处理,直接输出
  114. arr.push(node.data);
  115. } else {
  116. arr.push(
  117. notTransTagName[node.parentNode.tagName]
  118. ? utils.html(node.data)
  119. : node.data.replace(/[ ]{2}/g, " &nbsp;")
  120. );
  121. }
  122. }
  123. function isElement(node, arr, formatter, current) {
  124. var attrhtml = "";
  125. if (node.attrs) {
  126. attrhtml = [];
  127. var attrs = node.attrs;
  128. for (var a in attrs) {
  129. //这里就针对
  130. //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
  131. //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
  132. //有可能做的不够
  133. attrhtml.push(
  134. a +
  135. (attrs[a] !== undefined
  136. ? '="' +
  137. (notTransAttrs[a]
  138. ? utils.html(attrs[a]).replace(/["]/g, function(a) {
  139. return "&quot;";
  140. })
  141. : utils.unhtml(attrs[a])) +
  142. '"'
  143. : "")
  144. );
  145. }
  146. attrhtml = attrhtml.join(" ");
  147. }
  148. arr.push(
  149. "<" +
  150. node.tagName +
  151. (attrhtml ? " " + attrhtml : "") +
  152. (dtd.$empty[node.tagName] ? "/" : "") +
  153. ">"
  154. );
  155. //插入新行
  156. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
  157. if (node.children && node.children.length) {
  158. current = insertLine(arr, current, true);
  159. insertIndent(arr, current);
  160. }
  161. }
  162. if (node.children && node.children.length) {
  163. for (var i = 0, ci; (ci = node.children[i++]); ) {
  164. if (
  165. formatter &&
  166. ci.type == "element" &&
  167. !dtd.$inlineWithA[ci.tagName] &&
  168. i > 1
  169. ) {
  170. insertLine(arr, current);
  171. insertIndent(arr, current);
  172. }
  173. nodeToHtml(ci, arr, formatter, current);
  174. }
  175. }
  176. if (!dtd.$empty[node.tagName]) {
  177. if (
  178. formatter &&
  179. !dtd.$inlineWithA[node.tagName] &&
  180. node.tagName != "pre"
  181. ) {
  182. if (node.children && node.children.length) {
  183. current = insertLine(arr, current);
  184. insertIndent(arr, current);
  185. }
  186. }
  187. arr.push("</" + node.tagName + ">");
  188. }
  189. }
  190. function isComment(node, arr) {
  191. arr.push("<!--" + node.data + "-->");
  192. }
  193. function getNodeById(root, id) {
  194. var node;
  195. if (root.type == "element" && root.getAttr("id") == id) {
  196. return root;
  197. }
  198. if (root.children && root.children.length) {
  199. for (var i = 0, ci; (ci = root.children[i++]); ) {
  200. if ((node = getNodeById(ci, id))) {
  201. return node;
  202. }
  203. }
  204. }
  205. }
  206. function getNodesByTagName(node, tagName, arr) {
  207. if (node.type == "element" && node.tagName == tagName) {
  208. arr.push(node);
  209. }
  210. if (node.children && node.children.length) {
  211. for (var i = 0, ci; (ci = node.children[i++]); ) {
  212. getNodesByTagName(ci, tagName, arr);
  213. }
  214. }
  215. }
  216. function nodeTraversal(root, fn) {
  217. if (root.children && root.children.length) {
  218. for (var i = 0, ci; (ci = root.children[i]); ) {
  219. nodeTraversal(ci, fn);
  220. //ci被替换的情况,这里就不再走 fn了
  221. if (ci.parentNode) {
  222. if (ci.children && ci.children.length) {
  223. fn(ci);
  224. }
  225. if (ci.parentNode) i++;
  226. }
  227. }
  228. } else {
  229. fn(root);
  230. }
  231. }
  232. uNode.prototype = {
  233. /**
  234. * 当前节点对象,转换成html文本
  235. * @method toHtml
  236. * @return { String } 返回转换后的html字符串
  237. * @example
  238. * ```javascript
  239. * node.toHtml();
  240. * ```
  241. */
  242. /**
  243. * 当前节点对象,转换成html文本
  244. * @method toHtml
  245. * @param { Boolean } formatter 是否格式化返回值
  246. * @return { String } 返回转换后的html字符串
  247. * @example
  248. * ```javascript
  249. * node.toHtml( true );
  250. * ```
  251. */
  252. toHtml: function(formatter) {
  253. var arr = [];
  254. nodeToHtml(this, arr, formatter, 0);
  255. return arr.join("");
  256. },
  257. /**
  258. * 获取节点的html内容
  259. * @method innerHTML
  260. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  261. * @return { String } 返回节点的html内容
  262. * @example
  263. * ```javascript
  264. * var htmlstr = node.innerHTML();
  265. * ```
  266. */
  267. /**
  268. * 设置节点的html内容
  269. * @method innerHTML
  270. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  271. * @param { String } htmlstr 传入要设置的html内容
  272. * @return { UE.uNode } 返回节点本身
  273. * @example
  274. * ```javascript
  275. * node.innerHTML('<span>text</span>');
  276. * ```
  277. */
  278. innerHTML: function(htmlstr) {
  279. if (this.type != "element" || dtd.$empty[this.tagName]) {
  280. return this;
  281. }
  282. if (utils.isString(htmlstr)) {
  283. if (this.children) {
  284. for (var i = 0, ci; (ci = this.children[i++]); ) {
  285. ci.parentNode = null;
  286. }
  287. }
  288. this.children = [];
  289. var tmpRoot = UE.htmlparser(htmlstr);
  290. for (var i = 0, ci; (ci = tmpRoot.children[i++]); ) {
  291. this.children.push(ci);
  292. ci.parentNode = this;
  293. }
  294. return this;
  295. } else {
  296. var tmpRoot = new UE.uNode({
  297. type: "root",
  298. children: this.children
  299. });
  300. return tmpRoot.toHtml();
  301. }
  302. },
  303. /**
  304. * 获取节点的纯文本内容
  305. * @method innerText
  306. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  307. * @return { String } 返回节点的存文本内容
  308. * @example
  309. * ```javascript
  310. * var textStr = node.innerText();
  311. * ```
  312. */
  313. /**
  314. * 设置节点的纯文本内容
  315. * @method innerText
  316. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  317. * @param { String } textStr 传入要设置的文本内容
  318. * @return { UE.uNode } 返回节点本身
  319. * @example
  320. * ```javascript
  321. * node.innerText('<span>text</span>');
  322. * ```
  323. */
  324. innerText: function(textStr, noTrans) {
  325. if (this.type != "element" || dtd.$empty[this.tagName]) {
  326. return this;
  327. }
  328. if (textStr) {
  329. if (this.children) {
  330. for (var i = 0, ci; (ci = this.children[i++]); ) {
  331. ci.parentNode = null;
  332. }
  333. }
  334. this.children = [];
  335. this.appendChild(uNode.createText(textStr, noTrans));
  336. return this;
  337. } else {
  338. return this.toHtml().replace(/<[^>]+>/g, "");
  339. }
  340. },
  341. /**
  342. * 获取当前对象的data属性
  343. * @method getData
  344. * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
  345. * @example
  346. * ```javascript
  347. * node.getData();
  348. * ```
  349. */
  350. getData: function() {
  351. if (this.type == "element") return "";
  352. return this.data;
  353. },
  354. /**
  355. * 获取当前节点下的第一个子节点
  356. * @method firstChild
  357. * @return { UE.uNode } 返回第一个子节点
  358. * @example
  359. * ```javascript
  360. * node.firstChild(); //返回第一个子节点
  361. * ```
  362. */
  363. firstChild: function() {
  364. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  365. // return this;
  366. // }
  367. return this.children ? this.children[0] : null;
  368. },
  369. /**
  370. * 获取当前节点下的最后一个子节点
  371. * @method lastChild
  372. * @return { UE.uNode } 返回最后一个子节点
  373. * @example
  374. * ```javascript
  375. * node.lastChild(); //返回最后一个子节点
  376. * ```
  377. */
  378. lastChild: function() {
  379. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  380. // return this;
  381. // }
  382. return this.children ? this.children[this.children.length - 1] : null;
  383. },
  384. /**
  385. * 获取和当前节点有相同父亲节点的前一个节点
  386. * @method previousSibling
  387. * @return { UE.uNode } 返回前一个节点
  388. * @example
  389. * ```javascript
  390. * node.children[2].previousSibling(); //返回子节点node.children[1]
  391. * ```
  392. */
  393. previousSibling: function() {
  394. var parent = this.parentNode;
  395. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  396. if (ci === this) {
  397. return i == 0 ? null : parent.children[i - 1];
  398. }
  399. }
  400. },
  401. /**
  402. * 获取和当前节点有相同父亲节点的后一个节点
  403. * @method nextSibling
  404. * @return { UE.uNode } 返回后一个节点,找不到返回null
  405. * @example
  406. * ```javascript
  407. * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
  408. * ```
  409. */
  410. nextSibling: function() {
  411. var parent = this.parentNode;
  412. for (var i = 0, ci; (ci = parent.children[i++]); ) {
  413. if (ci === this) {
  414. return parent.children[i];
  415. }
  416. }
  417. },
  418. /**
  419. * 用新的节点替换当前节点
  420. * @method replaceChild
  421. * @param { UE.uNode } target 要替换成该节点参数
  422. * @param { UE.uNode } source 要被替换掉的节点
  423. * @return { UE.uNode } 返回替换之后的节点对象
  424. * @example
  425. * ```javascript
  426. * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
  427. * ```
  428. */
  429. replaceChild: function(target, source) {
  430. if (this.children) {
  431. if (target.parentNode) {
  432. target.parentNode.removeChild(target);
  433. }
  434. for (var i = 0, ci; (ci = this.children[i]); i++) {
  435. if (ci === source) {
  436. this.children.splice(i, 1, target);
  437. source.parentNode = null;
  438. target.parentNode = this;
  439. return target;
  440. }
  441. }
  442. }
  443. },
  444. /**
  445. * 在节点的子节点列表最后位置插入一个节点
  446. * @method appendChild
  447. * @param { UE.uNode } node 要插入的节点
  448. * @return { UE.uNode } 返回刚插入的子节点
  449. * @example
  450. * ```javascript
  451. * node.appendChild( newNode ); //在node内插入子节点newNode
  452. * ```
  453. */
  454. appendChild: function(node) {
  455. if (
  456. this.type == "root" ||
  457. (this.type == "element" && !dtd.$empty[this.tagName])
  458. ) {
  459. if (!this.children) {
  460. this.children = [];
  461. }
  462. if (node.parentNode) {
  463. node.parentNode.removeChild(node);
  464. }
  465. for (var i = 0, ci; (ci = this.children[i]); i++) {
  466. if (ci === node) {
  467. this.children.splice(i, 1);
  468. break;
  469. }
  470. }
  471. this.children.push(node);
  472. node.parentNode = this;
  473. return node;
  474. }
  475. },
  476. /**
  477. * 在传入节点的前面插入一个节点
  478. * @method insertBefore
  479. * @param { UE.uNode } target 要插入的节点
  480. * @param { UE.uNode } source 在该参数节点前面插入
  481. * @return { UE.uNode } 返回刚插入的子节点
  482. * @example
  483. * ```javascript
  484. * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
  485. * ```
  486. */
  487. insertBefore: function(target, source) {
  488. if (this.children) {
  489. if (target.parentNode) {
  490. target.parentNode.removeChild(target);
  491. }
  492. for (var i = 0, ci; (ci = this.children[i]); i++) {
  493. if (ci === source) {
  494. this.children.splice(i, 0, target);
  495. target.parentNode = this;
  496. return target;
  497. }
  498. }
  499. }
  500. },
  501. /**
  502. * 在传入节点的后面插入一个节点
  503. * @method insertAfter
  504. * @param { UE.uNode } target 要插入的节点
  505. * @param { UE.uNode } source 在该参数节点后面插入
  506. * @return { UE.uNode } 返回刚插入的子节点
  507. * @example
  508. * ```javascript
  509. * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
  510. * ```
  511. */
  512. insertAfter: function(target, source) {
  513. if (this.children) {
  514. if (target.parentNode) {
  515. target.parentNode.removeChild(target);
  516. }
  517. for (var i = 0, ci; (ci = this.children[i]); i++) {
  518. if (ci === source) {
  519. this.children.splice(i + 1, 0, target);
  520. target.parentNode = this;
  521. return target;
  522. }
  523. }
  524. }
  525. },
  526. /**
  527. * 从当前节点的子节点列表中,移除节点
  528. * @method removeChild
  529. * @param { UE.uNode } node 要移除的节点引用
  530. * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
  531. * @return { * } 返回刚移除的子节点
  532. * @example
  533. * ```javascript
  534. * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
  535. * ```
  536. */
  537. removeChild: function(node, keepChildren) {
  538. if (this.children) {
  539. for (var i = 0, ci; (ci = this.children[i]); i++) {
  540. if (ci === node) {
  541. this.children.splice(i, 1);
  542. ci.parentNode = null;
  543. if (keepChildren && ci.children && ci.children.length) {
  544. for (var j = 0, cj; (cj = ci.children[j]); j++) {
  545. this.children.splice(i + j, 0, cj);
  546. cj.parentNode = this;
  547. }
  548. }
  549. return ci;
  550. }
  551. }
  552. }
  553. },
  554. /**
  555. * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
  556. * @method getAttr
  557. * @param { String } attrName 要获取的属性名称
  558. * @return { * } 返回attrs对象下的属性值
  559. * @example
  560. * ```javascript
  561. * node.getAttr('title');
  562. * ```
  563. */
  564. getAttr: function(attrName) {
  565. return this.attrs && this.attrs[attrName.toLowerCase()];
  566. },
  567. /**
  568. * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
  569. * @method setAttr
  570. * @param { String } attrName 要设置的属性名称
  571. * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
  572. * @return { * } 返回attrs对象下的属性值
  573. * @example
  574. * ```javascript
  575. * node.setAttr('title','标题');
  576. * ```
  577. */
  578. setAttr: function(attrName, attrVal) {
  579. if (!attrName) {
  580. delete this.attrs;
  581. return;
  582. }
  583. if (!this.attrs) {
  584. this.attrs = {};
  585. }
  586. if (utils.isObject(attrName)) {
  587. for (var a in attrName) {
  588. if (!attrName[a]) {
  589. delete this.attrs[a];
  590. } else {
  591. this.attrs[a.toLowerCase()] = attrName[a];
  592. }
  593. }
  594. } else {
  595. if (!attrVal) {
  596. delete this.attrs[attrName];
  597. } else {
  598. this.attrs[attrName.toLowerCase()] = attrVal;
  599. }
  600. }
  601. },
  602. /**
  603. * 获取当前节点在父节点下的位置索引
  604. * @method getIndex
  605. * @return { Number } 返回索引数值,如果没有父节点,返回-1
  606. * @example
  607. * ```javascript
  608. * node.getIndex();
  609. * ```
  610. */
  611. getIndex: function() {
  612. var parent = this.parentNode;
  613. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  614. if (ci === this) {
  615. return i;
  616. }
  617. }
  618. return -1;
  619. },
  620. /**
  621. * 在当前节点下,根据id查找节点
  622. * @method getNodeById
  623. * @param { String } id 要查找的id
  624. * @return { UE.uNode } 返回找到的节点
  625. * @example
  626. * ```javascript
  627. * node.getNodeById('textId');
  628. * ```
  629. */
  630. getNodeById: function(id) {
  631. var node;
  632. if (this.children && this.children.length) {
  633. for (var i = 0, ci; (ci = this.children[i++]); ) {
  634. if ((node = getNodeById(ci, id))) {
  635. return node;
  636. }
  637. }
  638. }
  639. },
  640. /**
  641. * 在当前节点下,根据元素名称查找节点列表
  642. * @method getNodesByTagName
  643. * @param { String } tagNames 要查找的元素名称
  644. * @return { Array } 返回找到的节点列表
  645. * @example
  646. * ```javascript
  647. * node.getNodesByTagName('span');
  648. * ```
  649. */
  650. getNodesByTagName: function(tagNames) {
  651. tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
  652. var arr = [],
  653. me = this;
  654. utils.each(tagNames, function(tagName) {
  655. if (me.children && me.children.length) {
  656. for (var i = 0, ci; (ci = me.children[i++]); ) {
  657. getNodesByTagName(ci, tagName, arr);
  658. }
  659. }
  660. });
  661. return arr;
  662. },
  663. /**
  664. * 根据样式名称,获取节点的样式值
  665. * @method getStyle
  666. * @param { String } name 要获取的样式名称
  667. * @return { String } 返回样式值
  668. * @example
  669. * ```javascript
  670. * node.getStyle('font-size');
  671. * ```
  672. */
  673. getStyle: function(name) {
  674. var cssStyle = this.getAttr("style");
  675. if (!cssStyle) {
  676. return "";
  677. }
  678. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
  679. var match = cssStyle.match(reg);
  680. if (match && match[0]) {
  681. return match[2];
  682. }
  683. return "";
  684. },
  685. /**
  686. * 给节点设置样式
  687. * @method setStyle
  688. * @param { String } name 要设置的的样式名称
  689. * @param { String } val 要设置的的样值
  690. * @example
  691. * ```javascript
  692. * node.setStyle('font-size', '12px');
  693. * ```
  694. */
  695. setStyle: function(name, val) {
  696. function exec(name, val) {
  697. var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
  698. cssStyle = cssStyle.replace(reg, "$1");
  699. if (val) {
  700. cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle;
  701. }
  702. }
  703. var cssStyle = this.getAttr("style");
  704. if (!cssStyle) {
  705. cssStyle = "";
  706. }
  707. if (utils.isObject(name)) {
  708. for (var a in name) {
  709. exec(a, name[a]);
  710. }
  711. } else {
  712. exec(name, val);
  713. }
  714. this.setAttr("style", utils.trim(cssStyle));
  715. },
  716. /**
  717. * 传入一个函数,递归遍历当前节点下的所有节点
  718. * @method traversal
  719. * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
  720. * @example
  721. * ```javascript
  722. * traversal(node, function(){
  723. * console.log(node.type);
  724. * });
  725. * ```
  726. */
  727. traversal: function(fn) {
  728. if (this.children && this.children.length) {
  729. nodeTraversal(this, fn);
  730. }
  731. return this;
  732. }
  733. };
  734. })();