selectComponent.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. const createTraverse = () => {
  2. let stop = false;
  3. return function traverse(root, callback) {
  4. if (!stop && typeof callback === 'function') {
  5. let children = root.$children;
  6. for (let index = 0; !stop && index < children.length; index++) {
  7. let element = children[index];
  8. stop = callback(element) === true;
  9. traverse(element, callback);
  10. }
  11. }
  12. };
  13. };
  14. /**
  15. * 安全的JSON.stringify
  16. * @param {Object} node
  17. */
  18. function safeStringify(node) {
  19. var cache = [];
  20. var str = JSON.stringify(node, function(key, value) {
  21. if (typeof value === 'object' && value !== null) {
  22. if (cache.indexOf(value) !== -1) {
  23. // 移除
  24. return;
  25. }
  26. // 收集所有的值
  27. cache.push(value);
  28. }
  29. return value;
  30. });
  31. cache = null; // 清空变量,便于垃圾回收机制回收
  32. return str
  33. }
  34. const match = (node, selector) => {
  35. var vnode = node._vnode;
  36. //好家伙,在微信小程序里,node里面根本找不到class,因此这种方式没法搞了
  37. //关键之处!
  38. // console.log("attrs", (vnode.context.$vnode.data));
  39. vnode = vnode?.context?.$vnode ?? ""
  40. //console.log(vnode.data) --> [Object] {"staticClass":"bar","attrs":{"_i":0}} at selectComponent.js:72
  41. if (!vnode || !vnode.data) {
  42. return false
  43. }
  44. let attrs = vnode.data.attrs || {};
  45. let staticClass = vnode.data.staticClass || '';
  46. const id = attrs.id || '';
  47. if (selector[0] === '#') {
  48. return selector.substr(1) === id;
  49. } else {
  50. staticClass = staticClass.trim().split(' ');
  51. selector = selector.substr(1).split('.');
  52. return selector.reduce((a, c) => a && staticClass.includes(c), true);
  53. }
  54. };
  55. const selectorBuilder = (selector) => {
  56. selector = selector.replace(/>>>/g, '>');
  57. selector = selector.split('>').map(s => {
  58. return s.trim().split(' ').join(`').descendant('`);
  59. }).join(`').child('`);
  60. // 替换掉new Function方式,因为小程序不支持new Function和eval
  61. //return new Function('Selector', 'node', 'all', `return new Selector(node, all).descendant('` + selector + `')`);
  62. return function(Selector, node, all) {
  63. return new Selector(node, all).descendant(selector)
  64. }
  65. };
  66. class Selector {
  67. constructor(node, all = false) {
  68. this.nodes = [node];
  69. this.all = all;
  70. }
  71. child(selector) {
  72. let matches = [];
  73. if (this.all) {
  74. this.nodes.forEach(node => {
  75. matches.push(...node.$children.filter(node => match(node, selector)));
  76. });
  77. } else {
  78. if (this.nodes.length > 0) {
  79. let node = this.nodes[0].$children.find(node => match(node, selector));
  80. matches = node ? [node] : [];
  81. }
  82. }
  83. this.nodes = matches;
  84. return this;
  85. }
  86. descendant(selector) {
  87. let matches = [];
  88. this.nodes.forEach(root => {
  89. createTraverse()(root, (node) => {
  90. if (match(node, selector)) {
  91. matches.push(node);
  92. return !this.all;
  93. }
  94. });
  95. });
  96. this.nodes = matches;
  97. return this;
  98. }
  99. }
  100. ////////////////////////////////////////////selectComponent//////////////////////////////////////////////////
  101. /**
  102. * 其他平台,如APP
  103. * @param {Object} selector
  104. */
  105. function selectComponentOther(selector) {
  106. const selectors = selector.split(',').map(s => s.trim());
  107. if (!selectors[0]) {
  108. return null;
  109. }
  110. const querySelector = selectorBuilder(selectors[0]);
  111. return querySelector(Selector, this, false, selector).nodes[0];
  112. }
  113. /**
  114. * 还是用这个微信小程序的实现吧
  115. * @param {Object} selector
  116. */
  117. var selectComponentWeiXin2 = function(selector) {
  118. console.log(".$scope",this.$scope.selectComponent(selector))
  119. return this.$scope.selectComponent(selector)?.data || undefined
  120. }
  121. /**
  122. * selectComponent
  123. * @param {Object} args
  124. */
  125. export function selectComponent(args) {
  126. // console.log(".$scope",this.$scope)
  127. // #ifdef MP
  128. //H5和小程序能正常使用这个函数
  129. //重写selectComponent函数,因为默认会多一层$vm
  130. return selectComponentWeiXin2.call(this, args)
  131. // #endif
  132. // #ifndef MP
  133. // 因App的结构略有差异,此函数无法正常使用
  134. // function(e){return function e(t,n){if(n(t.$vnode||t._vnode))return t;for(var r=t.$children,i=0;i<r.length;i++){var o=e(r[i],n);if(o)return o}}(this,ov(e))}
  135. // return selectComponentOther(args)
  136. return selectComponentOther.call(this, args)
  137. // #endif
  138. }
  139. ////////////////////////////////////////////selectAllComponents//////////////////////////////////////////////////
  140. /**
  141. * 其他平台,如APP
  142. * @param {Object} selector
  143. */
  144. function selectAllComponentsOther(selector) {
  145. const selectors = selector.split(',').map(s => s.trim());
  146. let selected = [];
  147. selectors.forEach(selector => {
  148. const querySelector = selectorBuilder(selector);
  149. selected = selected.concat(querySelector(Selector, this, true, selector).nodes);
  150. });
  151. return selected;
  152. }
  153. /**
  154. * 还是用这个微信小程序的实现吧
  155. * @param {Object} selector
  156. */
  157. var selectAllComponentsWeiXin2 = function(selector) {
  158. var list = this.$scope.selectAllComponents(selector) || []
  159. list = list.map(item => item.data)
  160. return list
  161. }
  162. /**
  163. * selectAllComponents
  164. * @param {Object} args
  165. */
  166. export function selectAllComponents(args) {
  167. // #ifdef MP
  168. //H5和小程序能正常使用这个函数
  169. //重写selectComponent函数,因为默认会多一层$vm
  170. return selectAllComponentsWeiXin2.call(this, args)
  171. // #endif
  172. // #ifndef MP
  173. // 因App的结构略有差异,此函数无法正常使用
  174. return selectAllComponentsOther.call(this, args)
  175. // #endif
  176. }