|
@@ -0,0 +1,619 @@
|
|
|
+class CssPriority {
|
|
|
+ static _TOKEN_ID = /(#[\w-]+)/g
|
|
|
+ static _TOKEN_CLASS = /(\.[\w-]+)/g
|
|
|
+ static _TOKEN_ATTR = /(\[[^[\]]+])/g
|
|
|
+ static _TOKEN_PSEUDO_CLASS = /(:[\w-]+)/g
|
|
|
+ static _TOKEN_PSEUDO_ELEM = /(::[\w-]+)/g
|
|
|
+ static _TOKEN_ELEM = /([\w-]+)/g
|
|
|
+
|
|
|
+ static _PSEUDO_ELEMS = [
|
|
|
+ 'first-letter',
|
|
|
+ 'last-letter',
|
|
|
+ 'first-line',
|
|
|
+ 'last-line',
|
|
|
+ 'first-child',
|
|
|
+ 'last-child',
|
|
|
+ 'before',
|
|
|
+ 'after'
|
|
|
+ ]
|
|
|
+
|
|
|
+ static _SYMBOL_B = '\x02'
|
|
|
+ static _SYMBOL_C = '\x03'
|
|
|
+ static _SYMBOL_D = '\x04'
|
|
|
+
|
|
|
+ static compare(a, b) {
|
|
|
+ //在sort应用中,返回<0,则a在b之前,>0则a在b之后
|
|
|
+ for (let i = 0; i < a.length; i++) {
|
|
|
+ if (a[i] !== b[i]) {
|
|
|
+ //return a[i] - b[i]
|
|
|
+ return b[i] - a[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * parse then priority of selector (CSS Rule)
|
|
|
+ * @param {String} selector css selector
|
|
|
+ * @param {Object} opts
|
|
|
+ * - {Boolean} opts.important is current rule important
|
|
|
+ * - {Number} opts.line line number of css rule
|
|
|
+ * @return {Array} array that contains 6 priority number
|
|
|
+ */
|
|
|
+ static parse(selector, opts) {
|
|
|
+ opts = opts || {}
|
|
|
+
|
|
|
+ // priority: [ important, style, R1, R2, R3, line ]
|
|
|
+ let important = opts.important ? 1 : 0
|
|
|
+ let line = opts.line || 0
|
|
|
+ let priority = [important, 0, 0, 0, 0, line]
|
|
|
+
|
|
|
+ selector = selector.replace(/(::?)([\w-]+)/g, (total, left, elem) => {
|
|
|
+ if (CssPriority._PSEUDO_ELEMS.indexOf(elem) >= 0) {
|
|
|
+ if (left === ':') {
|
|
|
+ return '::' + elem
|
|
|
+ } else {
|
|
|
+ return total
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return total
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // replace with symbols
|
|
|
+ selector = selector
|
|
|
+ .replace(CssPriority._TOKEN_ATTR, CssPriority._SYMBOL_C)
|
|
|
+ .replace(CssPriority._TOKEN_PSEUDO_ELEM, CssPriority._SYMBOL_D)
|
|
|
+ .replace(CssPriority._TOKEN_PSEUDO_CLASS, CssPriority._SYMBOL_C)
|
|
|
+ .replace(CssPriority._TOKEN_ID, CssPriority._SYMBOL_B)
|
|
|
+ .replace(CssPriority._TOKEN_CLASS, CssPriority._SYMBOL_C)
|
|
|
+ .replace(CssPriority._TOKEN_ELEM, CssPriority._SYMBOL_D)
|
|
|
+
|
|
|
+ // count
|
|
|
+ selector = selector.replace(/[\2\3\4]/g, (symbol) => {
|
|
|
+ let idx = symbol.charCodeAt(0)
|
|
|
+
|
|
|
+ priority[idx]++
|
|
|
+
|
|
|
+ return '<' + idx + '>'
|
|
|
+ })
|
|
|
+
|
|
|
+ return priority
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class Lock {
|
|
|
+ constructor() {
|
|
|
+ this.promise = new Promise((resolve, reject) => {
|
|
|
+ this.resolve = resolve;
|
|
|
+ this.reject = reject;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ async wait() {
|
|
|
+ try {
|
|
|
+ let result = await this.promise;
|
|
|
+ return result;
|
|
|
+ } catch (error) {
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class CssKind {
|
|
|
+ static inline = 1;
|
|
|
+ static match = 2;
|
|
|
+ static parent = 3;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class CssRefers {
|
|
|
+ _document;
|
|
|
+ _cssTree;
|
|
|
+ _cssAst = [];
|
|
|
+
|
|
|
+ _inheritStyles = new Map([["color", null], ["font", null], ["font-family", null], ["font-size", null], ["font-style", null], ["font-weight", null], ["font-height", null], ["font-variant", null], ["font-stretch", null], ["font-size-adjust", null],
|
|
|
+ ["letter-spacing", null], ["word-spacing", null], ["text-align", null], ["text-indent", null], ["text-decoration", null], ["white-space", null], ["text-shadow", null], ["text-transform", null], ["direction", null],
|
|
|
+ ["caption-side", null], ["empty-cells", null], ["border-collapse", null],
|
|
|
+ ["unicode-bidi", null], ["visibility", null], ["cursor", null], ["user-select", null], ["list-style", null], ["list-style-type", null], ["list-style-position", null], ["list-style-image", null], ["display", null], ["columns", null], ["column-count", null], ["column-gap", null], ["column-rule", null], ["column-span", null], ["column-width", null],
|
|
|
+ ["break-before", null], ["break-after", null], ["break-inside", null], ["line-height", null], ["cursor", null], ["quotes", null]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ _cssCount = 0;
|
|
|
+ constructor(doc, cssTree) {
|
|
|
+ this._document = doc;
|
|
|
+ this._cssTree = cssTree;
|
|
|
+ }
|
|
|
+
|
|
|
+ async #initCssAst() {
|
|
|
+ if (this._cssTree) {
|
|
|
+ if (this._cssAst.length > 0) return;
|
|
|
+
|
|
|
+ for (let i = 0; i < this._document.styleSheets.length; i++) {
|
|
|
+ let styleSheet = this._document.styleSheets[i];
|
|
|
+
|
|
|
+ if (styleSheet.href) {
|
|
|
+ let cssCode = await this.#getCssData(styleSheet.href);
|
|
|
+
|
|
|
+ if (cssCode) {
|
|
|
+ let ast = this.#cssCodeToAST(cssCode);
|
|
|
+
|
|
|
+ this._cssAst.push({
|
|
|
+ file: styleSheet.href,
|
|
|
+ ast: ast,
|
|
|
+ code:cssCode,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async #getCssData(file) {
|
|
|
+ let response = await fetch(file);
|
|
|
+ return await response.text();
|
|
|
+ }
|
|
|
+
|
|
|
+ #cssCodeToAST(cssCode) {
|
|
|
+ let curAst = this._cssTree.parse(cssCode, {
|
|
|
+ parseAtrulePrelude: false,
|
|
|
+ parseRulePrelude: false,
|
|
|
+ parseValue: false,
|
|
|
+ positions: true,
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ let selectors = [];
|
|
|
+
|
|
|
+ //https://github.com/csstree/csstree/blob/master/docs/parsing.md#parsesource-options
|
|
|
+ csstree.walk(curAst, (node) => {
|
|
|
+ if (node.type === 'Rule')//node.type === 'Declaration'
|
|
|
+ {
|
|
|
+ let curSelector;
|
|
|
+ if (node.prelude.children) {
|
|
|
+ curSelector = node.prelude.children.map(child => child.raw);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ curSelector = node.prelude.value;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (curSelector) selectors.push({
|
|
|
+ name: curSelector.replaceAll("\r\n", " ") ,//curSelector,
|
|
|
+ loc: node.prelude.loc,
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return selectors;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取元素内联样式定义
|
|
|
+ #getInlineStyle(ele) {
|
|
|
+ let ret = [];
|
|
|
+
|
|
|
+ for (let i = 0; i < ele.style.length; i++) {
|
|
|
+ let sn = ele.style[i];
|
|
|
+
|
|
|
+ let isImportant = false;
|
|
|
+
|
|
|
+ if ((ele.style.cssText.split(sn)[1] + ";").split(";")[0].indexOf("!important") > 0) {
|
|
|
+ isImportant = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret.push({
|
|
|
+ name: sn,
|
|
|
+ cssText: ele.style[sn],
|
|
|
+ isImportant: isImportant,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret.length <= 0) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ this._cssCount = _cssCount + 1;
|
|
|
+ return [{
|
|
|
+ selectorName: "",
|
|
|
+ declarations: "",
|
|
|
+ href: "",
|
|
|
+ style: ret,
|
|
|
+ id: `c_${this._cssCount}`,
|
|
|
+ fileIndex: null,
|
|
|
+ posIndex:null,
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算选择器的权重级别
|
|
|
+ #getSelectorPriority(selector,opts) {
|
|
|
+ //github.com/yibn2008/css-priority
|
|
|
+ return CssPriority.parse(selector,opts);
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取当前元素的匹配样式
|
|
|
+ #getMatchStyle(ele) {
|
|
|
+ if (!ele) return [];
|
|
|
+
|
|
|
+ const matchedCSSRules = [];
|
|
|
+
|
|
|
+ // 获取所有样式表
|
|
|
+ for (let i = 0; i < this._document.styleSheets.length; i++) {
|
|
|
+ const styleSheet = this._document.styleSheets[i];
|
|
|
+ try {
|
|
|
+ // 遍历每个样式表的规则
|
|
|
+ for (let j = 0; j < styleSheet.cssRules.length; j++) {
|
|
|
+ const rule = styleSheet.cssRules[j];
|
|
|
+
|
|
|
+ let isMatch = false;
|
|
|
+ if (rule.selectorText == ":root") {
|
|
|
+ if (ele.tagName == "HTML") isMatch = true;
|
|
|
+ }
|
|
|
+ else if (rule.selectorText == ":link" || rule.selectorText == ":visited") {
|
|
|
+ if (ele.tagName == "A") isMatch = true;
|
|
|
+ }
|
|
|
+ else if (rule.selectorText == ":disabled" || rule.selectorText == ":enabled") {
|
|
|
+ if (["INPUT", "TEXTAREA","SELECT","BUTTON","FIELDSET"].indexOf(ele.tagName) >= 0) isMatch = true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (ele.matches(rule.selectorText)) {
|
|
|
+ isMatch = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isMatch) {
|
|
|
+
|
|
|
+ let styles = [];
|
|
|
+ if (rule.style) {
|
|
|
+ let sn = "";
|
|
|
+ for (let i = 0; i < rule.style.length; i++) {
|
|
|
+ sn = rule.style[i];
|
|
|
+
|
|
|
+ let isImportant = false;
|
|
|
+
|
|
|
+ if ((rule.style.cssText.split(sn)[1] + ";").split(";")[0].indexOf("!important") > 0) {
|
|
|
+ isImportant = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ styles.push({
|
|
|
+ name: sn,
|
|
|
+ cssText: rule.style[sn],
|
|
|
+ isImportant: isImportant,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this._cssCount = this._cssCount + 1;
|
|
|
+ let loc = null;
|
|
|
+
|
|
|
+ if (this._cssAst.length > 0) {
|
|
|
+ let fileAst = this._cssAst.find((x) => x.file == styleSheet.href);
|
|
|
+ if (fileAst) {
|
|
|
+ let selectorAst = fileAst.ast.find((x) => x.name == rule.selectorText);
|
|
|
+ if (selectorAst) loc = selectorAst.loc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ matchedCSSRules.push({
|
|
|
+ selectorName: rule.selectorText,
|
|
|
+ declarations: rule.style,
|
|
|
+ href: styleSheet.href || '',
|
|
|
+ style: styles,
|
|
|
+ id: `c_${this._cssCount}`,
|
|
|
+ //priority: this.#getSelectorPriority(rule.selectorText, {line:1000000-(i * 1000000 + j)}),
|
|
|
+ priority: this.#getSelectorPriority(rule.selectorText, { line: i * 1000000 + j}),
|
|
|
+ fileIndex: i,
|
|
|
+ posIndex: j,
|
|
|
+ loc:loc,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('无法访问样式表', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //根据优先级排序
|
|
|
+ return matchedCSSRules.sort((a, b) => {
|
|
|
+ return CssPriority.compare(a.priority, b.priority);
|
|
|
+ });;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取父级样式
|
|
|
+ #getParentStyle(ele) {
|
|
|
+ let styleList = [];
|
|
|
+ let level = 0;
|
|
|
+
|
|
|
+ let pEle = ele.parentElement;
|
|
|
+ while (pEle) {
|
|
|
+ let inlineStyle = this.#getInlineStyle(pEle);
|
|
|
+ if (inlineStyle.length > 0) {
|
|
|
+ styleList.push({
|
|
|
+ relationEle: pEle,
|
|
|
+ relationTag: pEle.tagName,
|
|
|
+ nodeLevel: level,
|
|
|
+ kind: CssKind.inline,
|
|
|
+ selector: inlineStyle,
|
|
|
+ });
|
|
|
+
|
|
|
+ level = level + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ let matchStyle = this.#getMatchStyle(pEle);
|
|
|
+ if (matchStyle.length > 0) {
|
|
|
+ styleList.push({
|
|
|
+ relationEle: pEle,
|
|
|
+ relationTag: pEle.tagName,
|
|
|
+ nodeLevel: level,
|
|
|
+ kind: CssKind.match,
|
|
|
+ selector: matchStyle,
|
|
|
+ });
|
|
|
+
|
|
|
+ level = level + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pEle = pEle.parentElement;
|
|
|
+ /*
|
|
|
+ if (pEle.tagName == "HTML") {
|
|
|
+ pEle = null;
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+
|
|
|
+ return styleList;
|
|
|
+ }
|
|
|
+
|
|
|
+ #getTopSelector(ele, selector,selectorName,line) {
|
|
|
+ let find = null;
|
|
|
+ for (let gItem of selectorName.split(",")) {
|
|
|
+ if (!ele.matches(gItem)) continue;
|
|
|
+
|
|
|
+ if (!find) {
|
|
|
+ find = {
|
|
|
+ selector: selector,
|
|
|
+ key: gItem,
|
|
|
+ priority: this.#getSelectorPriority(gItem, {line:line}),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ let curPriority = this.#getSelectorPriority(gItem, { line: line });
|
|
|
+ let ret = CssPriority.compare(find.priority, curPriority);
|
|
|
+ if (ret > 0) {
|
|
|
+ find.selector = selector;
|
|
|
+ find.key = gItem;
|
|
|
+ find.priority = curPriority;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return find;
|
|
|
+ }
|
|
|
+
|
|
|
+ async #getDefaultStyle(eleTag) {
|
|
|
+ let tmpF = this._document.tmpF;
|
|
|
+ let w = new Lock();
|
|
|
+ let tmpFStyle = null;
|
|
|
+
|
|
|
+ if (!tmpF) {
|
|
|
+ tmpF = this._document.createElement("iframe");
|
|
|
+ tmpF.style.display = "none";
|
|
|
+ tmpF.setAttribute("srcDoc", `<${eleTag} id="tmpf"></${eleTag}>`);
|
|
|
+
|
|
|
+ this._document.body.appendChild(tmpF);
|
|
|
+
|
|
|
+ this._document.tmpF = tmpF;
|
|
|
+
|
|
|
+ tmpF.onload = function () {
|
|
|
+ tmpFStyle = getComputedStyle(tmpF.contentWindow.document.getElementById("tmpf"));
|
|
|
+ w.resolve(tmpFStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tmpF.setAttribute("srcDoc", `<${eleTag} id="tmpf"></${eleTag}>`);
|
|
|
+
|
|
|
+ tmpF.onload = function () {
|
|
|
+ tmpFStyle = getComputedStyle(tmpF.contentWindow.document.getElementById("tmpf"));
|
|
|
+ w.resolve(tmpFStyle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return await w.wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取非默认样式
|
|
|
+ async #getComputedStyleProp(ele) {
|
|
|
+ let ret = [];
|
|
|
+
|
|
|
+ //获取默认样式
|
|
|
+ let defaultStyle = await this.#getDefaultStyle(ele.tagName);
|
|
|
+
|
|
|
+ //获取应用样式
|
|
|
+ let computeStyle = getComputedStyle(ele);
|
|
|
+
|
|
|
+ for (let i = 0; i < computeStyle.length - 1; i++) {
|
|
|
+ let sn = computeStyle[i];
|
|
|
+ if (computeStyle[sn] == defaultStyle[sn]) continue;
|
|
|
+
|
|
|
+ ret.push({
|
|
|
+ name: sn,
|
|
|
+ cssText: computeStyle[sn],
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取css的ast
|
|
|
+ async getAst() {
|
|
|
+ await this.#initCssAst();
|
|
|
+
|
|
|
+ return this._cssAst();
|
|
|
+ }
|
|
|
+
|
|
|
+ async refers(ele, propName) {
|
|
|
+ let ret = [];
|
|
|
+
|
|
|
+ //初始化css的ast
|
|
|
+ this.#initCssAst();
|
|
|
+
|
|
|
+ let inlineStyle = this.#getInlineStyle(ele);//获取自身的样式配置
|
|
|
+ let matchStyle = this.#getMatchStyle(ele);//获取匹配的样式配置
|
|
|
+ let parentStyle = this.#getParentStyle(ele);//获取所有父级的样式配置
|
|
|
+
|
|
|
+ let computeStyleProps = await this.#getComputedStyleProp(ele);//获取浏览器的非默认样式属性
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //插入内联样式
|
|
|
+ if (inlineStyle.length > 0) {
|
|
|
+ ret.push({
|
|
|
+ kind: CssKind.inline,
|
|
|
+ selector: inlineStyle.selector,
|
|
|
+ parent: null,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ //插入匹配样式
|
|
|
+ for (let matchItem of matchStyle) {
|
|
|
+ ret.push({
|
|
|
+ kind: CssKind.match,
|
|
|
+ selector: matchItem,
|
|
|
+ parent:null,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ let inheritedRelation = [];
|
|
|
+ //分析继承样式
|
|
|
+ for (let sty of computeStyleProps) {
|
|
|
+ if (!this._inheritStyles.has(sty.name)) continue;//非继承属性,则不需要判断父级
|
|
|
+ if (propName && sty.name != propName) continue;
|
|
|
+
|
|
|
+ //遍历多级父级
|
|
|
+ for (let psty of parentStyle) {
|
|
|
+ if (psty.selector?.length <= 0) continue;
|
|
|
+ //遍历父级中的选择器
|
|
|
+ for (let selectorItem of psty.selector) {
|
|
|
+ if (selectorItem.style.length <= 0) continue;
|
|
|
+ let findProp = false;
|
|
|
+ //遍历选择器的样式属性
|
|
|
+ for (let pro of selectorItem.style) {
|
|
|
+ if (pro.name == sty.name) {
|
|
|
+ findProp = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //找到了对应属性
|
|
|
+ if (findProp) {
|
|
|
+ let findSelector = inheritedRelation.find((x) => x.selector.id == selectorItem.id);
|
|
|
+ if (!findSelector) {
|
|
|
+ //选择器不存在,则插入
|
|
|
+ inheritedRelation.push({
|
|
|
+ kind: CssKind.parent,
|
|
|
+ selector: selectorItem,
|
|
|
+ inheritedInfo: psty,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算继承的优先顺序
|
|
|
+ inheritedRelation = inheritedRelation.sort((a, b) => {
|
|
|
+ if (a.inheritedInfo.nodeLevel < b.inheritedInfo.nodeLevel) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ else if (a.inheritedInfo.nodeLevel > b.inheritedInfo.nodeLevel) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ ret = ret.concat(inheritedRelation);
|
|
|
+
|
|
|
+ let propApplyRelation = [];
|
|
|
+
|
|
|
+ //计算属性的匹配位置
|
|
|
+ for (let prop of computeStyleProps) {
|
|
|
+ if (propName && prop.name != propName) continue;
|
|
|
+
|
|
|
+ let findSelector = null;
|
|
|
+ let isImportant = false;
|
|
|
+
|
|
|
+ //遍历关联的选择器
|
|
|
+ for (let selector of ret) {
|
|
|
+ //{kind:"",selector:{},parent:null }
|
|
|
+
|
|
|
+ let isFindProp = false;
|
|
|
+ //遍历样式属性
|
|
|
+ for (let sty of selector.selector.style) {
|
|
|
+ if (prop.name == sty.name) {
|
|
|
+ isFindProp = true;
|
|
|
+ //判断是否配置了important申明
|
|
|
+ if (sty.isImportant) {
|
|
|
+ isImportant = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //找到了对应的属性
|
|
|
+ if (isFindProp) {
|
|
|
+ if (!findSelector) {
|
|
|
+ findSelector = selector;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (selector.kind != CssKind.parent) {
|
|
|
+ //important>inline>match -parent继承类中的important不会应用到子级元素
|
|
|
+ if (isImportant) {
|
|
|
+ //发现important定义则结束当前属性所在选择器的遍历
|
|
|
+ findSelector = selector;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //优先级inline>match>parent
|
|
|
+ if (findSelector.kind < selector.kind) continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //处理kind相等的情况
|
|
|
+ if (findSelector.selector.selectorName.indexOf(",") > 0 || selector.selector.selectorName.indexOf(",") > 0) {
|
|
|
+ //判断逗号之间的选择器的优先级
|
|
|
+ let findSelectorTop = this.#getTopSelector(ele, findSelector.selector, findSelector.selector.selectorName, findSelector.selector.priority[5]);
|
|
|
+ let backupSelectorTop = this.#getTopSelector(ele, selector.selector, selector.selector.selectorName, selector.selector.priority[5]);
|
|
|
+
|
|
|
+ let curCompare = CssPriority.compare(findSelectorTop.priority, backupSelectorTop.priority);
|
|
|
+ if (curCompare > 0) {
|
|
|
+ findSelector = selector;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (findSelector) {
|
|
|
+ propApplyRelation.push({
|
|
|
+ name: prop.name,
|
|
|
+ cssText: prop.cssText,
|
|
|
+ selector: findSelector,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ applyRelation: propApplyRelation,
|
|
|
+ applySelectors: ret,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+}
|