index.uts 7.8 KB

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