// @ts-nocheck
|
|
import {isDef} from '../isDef'
|
|
import {type ComponentPublicInstance} from 'vue'
|
|
|
|
type HasSelectorFunc = (selector : string, element : UniElement) => boolean
|
|
|
|
const hasSelectorClassName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
|
return element.classList.includes(selector)
|
|
}
|
|
const hasSelectorId : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
|
return element.getAttribute("id") == selector
|
|
}
|
|
const hasSelectorTagName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
|
return element.tagName!.toLowerCase() == selector.toLowerCase()
|
|
}
|
|
|
|
type ProcessSelectorResult = {
|
|
selectorValue : string
|
|
hasSelector : HasSelectorFunc
|
|
}
|
|
const processSelector = (selector : string) : ProcessSelectorResult => {
|
|
|
|
const selectorValue = /#|\./.test(selector) ? selector.substring(1) : selector
|
|
let hasSelector : HasSelectorFunc
|
|
|
|
if (selector.startsWith('.')) {
|
|
hasSelector = hasSelectorClassName
|
|
} else if (selector.startsWith('#')) {
|
|
hasSelector = hasSelectorId
|
|
} else {
|
|
hasSelector = hasSelectorTagName
|
|
}
|
|
|
|
return {
|
|
selectorValue,
|
|
hasSelector
|
|
} as ProcessSelectorResult
|
|
}
|
|
|
|
|
|
function isNotEmptyString(str:string): boolean {
|
|
return str.length > 0;
|
|
}
|
|
|
|
function isElement(element:UniElement|null):boolean {
|
|
return isDef(element) && element?.tagName != 'COMMENT';
|
|
}
|
|
|
|
type ElementArray = Array<UniElement|null>
|
|
class Query {
|
|
context : ComponentPublicInstance | null = null
|
|
selector : string = ''
|
|
elements : ElementArray = []
|
|
constructor(selector : string | null, context : ComponentPublicInstance | null) {
|
|
this.context = context
|
|
if(selector != null){
|
|
this.selector = selector
|
|
}
|
|
this.find(this.selector)
|
|
}
|
|
in(context : ComponentPublicInstance) : Query {
|
|
return new Query(this.selector, context)
|
|
}
|
|
findAll(selector : string): Query {
|
|
if (isDef(this.context)) {
|
|
const root = this.context?.$el //as Element | null;
|
|
if (isDef(root)) {
|
|
this.elements = [root!] //as ElementArray
|
|
}
|
|
const { selectorValue, hasSelector } = processSelector(selector)
|
|
const foundElements : ElementArray = [];
|
|
|
|
function findChildren(element : UniElement) {
|
|
element.children.forEach((child : UniElement) => {
|
|
if (hasSelector(selectorValue, child)) {
|
|
foundElements.push(child)
|
|
}
|
|
})
|
|
}
|
|
this.elements.forEach(el => {
|
|
findChildren(el!);
|
|
});
|
|
this.elements = foundElements
|
|
} else if (selector.startsWith('#')) {
|
|
const element = uni.getElementById(selector)
|
|
if (isElement(element!)) {
|
|
this.elements = [element]
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* 在当前元素集合中查找匹配的元素
|
|
*/
|
|
find(selector : string) : Query {
|
|
if (isDef(this.context)) {
|
|
const root = this.context?.$el //as Element | null;
|
|
if (isElement(root)) {
|
|
this.elements = [root] //as ElementArray
|
|
}
|
|
if(isNotEmptyString(selector) && this.elements.length > 0){
|
|
const { selectorValue, hasSelector } = processSelector(selector)
|
|
const foundElements : ElementArray = [];
|
|
function findChildren(element : UniElement) {
|
|
element.children.forEach((child : UniElement) => {
|
|
if (hasSelector(selectorValue, child) && foundElements.length < 1) {
|
|
foundElements.push(child)
|
|
}
|
|
if (foundElements.length < 1) {
|
|
findChildren(child);
|
|
}
|
|
})
|
|
}
|
|
this.elements.forEach(el => {
|
|
findChildren(el!);
|
|
});
|
|
this.elements = foundElements
|
|
}
|
|
|
|
} else if (selector.startsWith('#')) {
|
|
const element = uni.getElementById(selector)
|
|
if (isElement(element!)) {
|
|
this.elements = [element]
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素集合的直接子元素
|
|
*/
|
|
children() : Query {
|
|
// if (this.elements.length > 0) {
|
|
// const children = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.children)], []);
|
|
// this.elements = children;
|
|
// }
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素集合的父元素
|
|
*/
|
|
parent() : Query {
|
|
// if (this.elements.length > 0) {
|
|
// const parents = this.elements.map(el => el.parentElement).filter(parent => parent !== null) as ElementArray;
|
|
// this.elements = parents
|
|
// // this.elements = Array.from(new Set(parents));
|
|
// }
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素集合的兄弟元素
|
|
*/
|
|
siblings() : Query {
|
|
// if (this.elements.length > 0) {
|
|
// const siblings = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.parentElement?.children || [])], []);
|
|
// this.elements = siblings.filter(sibling => sibling !== null && !this.elements?.includes(sibling));
|
|
// }
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素集合的下一个兄弟元素
|
|
*/
|
|
next() : Query {
|
|
// if (this.elements.length > 0) {
|
|
// const nextElements = this.elements.map(el => el.nextElementSibling).filter(next => next !== null) as ElementArray;
|
|
// this.elements = nextElements;
|
|
// }
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素集合的上一个兄弟元素
|
|
*/
|
|
prev() : Query {
|
|
// if (this.elements.length > 0) {
|
|
// const prevElements = this.elements.map(el => el.previousElementSibling).filter(prev => prev !== null) as ElementArray;
|
|
// this.elements = prevElements;
|
|
// }
|
|
return this;
|
|
}
|
|
/**
|
|
* 从当前元素开始向上查找匹配的元素
|
|
*/
|
|
closest(selector : string) : Query {
|
|
if (isDef(this.context)) {
|
|
// && this.context.$parent != null && this.context.$parent.$el !== null
|
|
if(this.elements.length == 0 && isDef(this.context?.$parent) && isElement(this.context!.$parent?.$el)){
|
|
this.elements = [this.context!.$parent?.$el!]
|
|
}
|
|
|
|
const selectorsArray = selector.split(',')
|
|
// const { selectorValue, hasSelector } = processSelector(selector)
|
|
const processedSelectors = selectorsArray.map((selector: string):ProcessSelectorResult => processSelector(selector))
|
|
const closestElements = this.elements.map((el) : UniElement | null => {
|
|
let closestElement : UniElement | null = el
|
|
while (closestElement !== null) {
|
|
// if (hasSelector(selectorValue, closestElement)) {
|
|
// break;
|
|
// }
|
|
const isMatchingSelector = processedSelectors.some(({selectorValue, hasSelector}):boolean => {
|
|
return hasSelector(selectorValue, closestElement!)
|
|
})
|
|
if(isMatchingSelector){
|
|
break;
|
|
}
|
|
closestElement = closestElement.parentElement;
|
|
}
|
|
return closestElement
|
|
})
|
|
this.elements = closestElements.filter((closest : UniElement | null) : boolean => isDef(closest))// as ElementArray
|
|
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* 从当前元素集合中过滤出匹配的元素
|
|
*/
|
|
filter() : Query {
|
|
|
|
return this;
|
|
}
|
|
/**
|
|
* 从当前元素集合中排除匹配的元素
|
|
*/
|
|
not() { }
|
|
/**
|
|
* 从当前元素集合中查找包含匹配元素的元素
|
|
*/
|
|
has() { }
|
|
/**
|
|
* 获取当前元素集合的第一个
|
|
*/
|
|
first() : Query {
|
|
if (this.elements.length > 0) {
|
|
// this.elements = [this.elements[0]];
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* 最后一个元素
|
|
*/
|
|
last() : Query {
|
|
if (this.elements.length > 0) {
|
|
// this.elements = [this.elements[this.elements.length - 1]];
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* 获取当前元素在其兄弟元素中的索引
|
|
*/
|
|
index() : number | null {
|
|
// if (this.elements.length > 0 && this.elements.length > 0 && this.elements[0].parentElement !== null) {
|
|
// return Array.from(this.elements[0].parentElement.children).indexOf(this.elements[0]);
|
|
// }
|
|
return null;
|
|
}
|
|
get(index : number) : UniElement | null {
|
|
if (this.elements.length > index) {
|
|
return this.elements[index] //as Element
|
|
}
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function selectElement(selector : string | null = null) : Query {
|
|
// if(typeof selector == 'string' || selector == null){
|
|
// return new Query(selector as string | null, null)
|
|
// }
|
|
// else if(selector instanceof ComponentPublicInstance){
|
|
// return new Query(null, selector)
|
|
// }
|
|
return new Query(selector, null)
|
|
}
|
|
|
|
// $('xxx').in(this).find('xxx')
|
|
// $('xxx').in(this).get()
|