index.uts 7.8 KB

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