index.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // @ts-nocheck
  2. import {isDef} from '../isDef'
  3. // #ifdef UNI-APP-X
  4. import {type ComponentPublicInstance} from '../vue'
  5. // #endif
  6. type HasSelectorFunc = (selector : string, element : UniElement) => boolean
  7. const hasSelectorClassName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
  8. return element.classList.includes(selector)
  9. }
  10. const hasSelectorId : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
  11. return element.getAttribute("id") == selector
  12. }
  13. const hasSelectorTagName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
  14. return element.tagName!.toLowerCase() == selector.toLowerCase()
  15. }
  16. type ProcessSelectorResult = {
  17. selectorValue : string
  18. hasSelector : HasSelectorFunc
  19. }
  20. const processSelector = (selector : string) : ProcessSelectorResult => {
  21. const selectorValue = /#|\./.test(selector) ? selector.substring(1) : selector
  22. let hasSelector : HasSelectorFunc
  23. if (selector.startsWith('.')) {
  24. hasSelector = hasSelectorClassName
  25. } else if (selector.startsWith('#')) {
  26. hasSelector = hasSelectorId
  27. } else {
  28. hasSelector = hasSelectorTagName
  29. }
  30. return {
  31. selectorValue,
  32. hasSelector
  33. } as ProcessSelectorResult
  34. }
  35. function isNotEmptyString(str:string): boolean {
  36. return str.length > 0;
  37. }
  38. function isElement(element:UniElement|null):boolean {
  39. return isDef(element) && element?.tagName != 'COMMENT';
  40. }
  41. type ElementArray = Array<UniElement|null>
  42. class Query {
  43. context : ComponentPublicInstance | null = null
  44. selector : string = ''
  45. elements : ElementArray = []
  46. constructor(selector : string | null, context : ComponentPublicInstance | null) {
  47. this.context = context
  48. if(selector != null){
  49. this.selector = selector
  50. }
  51. this.find(this.selector)
  52. }
  53. in(context : ComponentPublicInstance) : Query {
  54. return new Query(this.selector, context)
  55. }
  56. findAll(selector : string): Query {
  57. if (isDef(this.context)) {
  58. const root = this.context?.$el //as Element | null;
  59. if (isDef(root)) {
  60. this.elements = [root!] //as ElementArray
  61. }
  62. const { selectorValue, hasSelector } = processSelector(selector)
  63. const foundElements : ElementArray = [];
  64. function findChildren(element : UniElement) {
  65. element.children.forEach((child : UniElement) => {
  66. if (hasSelector(selectorValue, child)) {
  67. foundElements.push(child)
  68. }
  69. })
  70. }
  71. this.elements.forEach(el => {
  72. findChildren(el!);
  73. });
  74. this.elements = foundElements
  75. } else if (selector.startsWith('#')) {
  76. const element = uni.getElementById(selector)
  77. if (isElement(element!)) {
  78. this.elements = [element]
  79. }
  80. }
  81. return this;
  82. }
  83. /**
  84. * 在当前元素集合中查找匹配的元素
  85. */
  86. find(selector : string) : Query {
  87. if (isDef(this.context)) {
  88. const root = this.context?.$el //as Element | null;
  89. if (isElement(root)) {
  90. this.elements = [root] //as ElementArray
  91. }
  92. if(isNotEmptyString(selector) && this.elements.length > 0){
  93. const { selectorValue, hasSelector } = processSelector(selector)
  94. const foundElements : ElementArray = [];
  95. function findChildren(element : UniElement) {
  96. element.children.forEach((child : UniElement) => {
  97. if (hasSelector(selectorValue, child) && foundElements.length < 1) {
  98. foundElements.push(child)
  99. }
  100. if (foundElements.length < 1) {
  101. findChildren(child);
  102. }
  103. })
  104. }
  105. this.elements.forEach(el => {
  106. findChildren(el!);
  107. });
  108. this.elements = foundElements
  109. }
  110. } else if (selector.startsWith('#')) {
  111. const element = uni.getElementById(selector)
  112. if (isElement(element!)) {
  113. this.elements = [element]
  114. }
  115. }
  116. return this;
  117. }
  118. /**
  119. * 获取当前元素集合的直接子元素
  120. */
  121. children() : Query {
  122. // if (this.elements.length > 0) {
  123. // const children = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.children)], []);
  124. // this.elements = children;
  125. // }
  126. return this;
  127. }
  128. /**
  129. * 获取当前元素集合的父元素
  130. */
  131. parent() : Query {
  132. // if (this.elements.length > 0) {
  133. // const parents = this.elements.map(el => el.parentElement).filter(parent => parent !== null) as ElementArray;
  134. // this.elements = parents
  135. // // this.elements = Array.from(new Set(parents));
  136. // }
  137. return this;
  138. }
  139. /**
  140. * 获取当前元素集合的兄弟元素
  141. */
  142. siblings() : Query {
  143. // if (this.elements.length > 0) {
  144. // const siblings = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.parentElement?.children || [])], []);
  145. // this.elements = siblings.filter(sibling => sibling !== null && !this.elements?.includes(sibling));
  146. // }
  147. return this;
  148. }
  149. /**
  150. * 获取当前元素集合的下一个兄弟元素
  151. */
  152. next() : Query {
  153. // if (this.elements.length > 0) {
  154. // const nextElements = this.elements.map(el => el.nextElementSibling).filter(next => next !== null) as ElementArray;
  155. // this.elements = nextElements;
  156. // }
  157. return this;
  158. }
  159. /**
  160. * 获取当前元素集合的上一个兄弟元素
  161. */
  162. prev() : Query {
  163. // if (this.elements.length > 0) {
  164. // const prevElements = this.elements.map(el => el.previousElementSibling).filter(prev => prev !== null) as ElementArray;
  165. // this.elements = prevElements;
  166. // }
  167. return this;
  168. }
  169. /**
  170. * 从当前元素开始向上查找匹配的元素
  171. */
  172. closest(selector : string) : Query {
  173. if (isDef(this.context)) {
  174. // && this.context.$parent != null && this.context.$parent.$el !== null
  175. if(this.elements.length == 0 && isDef(this.context?.$parent) && isElement(this.context!.$parent?.$el)){
  176. this.elements = [this.context!.$parent?.$el!]
  177. }
  178. const selectorsArray = selector.split(',')
  179. // const { selectorValue, hasSelector } = processSelector(selector)
  180. const processedSelectors = selectorsArray.map((selector: string):ProcessSelectorResult => processSelector(selector))
  181. const closestElements = this.elements.map((el) : UniElement | null => {
  182. let closestElement : UniElement | null = el
  183. while (closestElement !== null) {
  184. // if (hasSelector(selectorValue, closestElement)) {
  185. // break;
  186. // }
  187. const isMatchingSelector = processedSelectors.some(({selectorValue, hasSelector}):boolean => {
  188. return hasSelector(selectorValue, closestElement!)
  189. })
  190. if(isMatchingSelector){
  191. break;
  192. }
  193. closestElement = closestElement.parentElement;
  194. }
  195. return closestElement
  196. })
  197. this.elements = closestElements.filter((closest : UniElement | null) : boolean => isDef(closest))// as ElementArray
  198. }
  199. return this;
  200. }
  201. /**
  202. * 从当前元素集合中过滤出匹配的元素
  203. */
  204. filter() : Query {
  205. return this;
  206. }
  207. /**
  208. * 从当前元素集合中排除匹配的元素
  209. */
  210. not() { }
  211. /**
  212. * 从当前元素集合中查找包含匹配元素的元素
  213. */
  214. has() { }
  215. /**
  216. * 获取当前元素集合的第一个
  217. */
  218. first() : Query {
  219. if (this.elements.length > 0) {
  220. // this.elements = [this.elements[0]];
  221. }
  222. return this;
  223. }
  224. /**
  225. * 最后一个元素
  226. */
  227. last() : Query {
  228. if (this.elements.length > 0) {
  229. // this.elements = [this.elements[this.elements.length - 1]];
  230. }
  231. return this;
  232. }
  233. /**
  234. * 获取当前元素在其兄弟元素中的索引
  235. */
  236. index() : number | null {
  237. // if (this.elements.length > 0 && this.elements.length > 0 && this.elements[0].parentElement !== null) {
  238. // return Array.from(this.elements[0].parentElement.children).indexOf(this.elements[0]);
  239. // }
  240. return null;
  241. }
  242. get(index : number) : UniElement | null {
  243. if (this.elements.length > index) {
  244. return this.elements[index] //as Element
  245. }
  246. return null
  247. }
  248. }
  249. export function selectElement(selector : string | null = null) : Query {
  250. // if(typeof selector == 'string' || selector == null){
  251. // return new Query(selector as string | null, null)
  252. // }
  253. // else if(selector instanceof ComponentPublicInstance){
  254. // return new Query(null, selector)
  255. // }
  256. return new Query(selector, null)
  257. }
  258. // $('xxx').in(this).find('xxx')
  259. // $('xxx').in(this).get()