@antv/f6-ui
Version:
UI system for @antv/f6
277 lines (222 loc) • 8.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
exports.StyleNode = void 0;
var _tslib = require("tslib");
var _attrParser = require("../parser/attr-parser");
var _index = require("../utils/index");
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
var StyleNode =
/** @class */
function () {
function StyleNode() {
this.dom = null;
this.style = null;
this.children = [];
this.originChildren = [];
}
return StyleNode;
}();
exports.StyleNode = StyleNode;
var defaultStyle = {
'font-family': 'serif'
};
var inheritAttr = ['font', 'fontFamily', 'fontWeight', 'fontSize', 'fontVariant', 'fontStretch', 'textIndent', 'textAlign', 'textShadow', 'lineHeight', 'color', 'direction', 'wordSpacing', 'letterSpacing', 'textTransform', 'captionSide', 'borderCollapse', 'emptyCells', 'listStyleType', 'listStyleImage', 'listStylePosition', 'listStyle', 'visibility', 'cursor'];
var StyleParser =
/** @class */
function () {
function StyleParser(domTree, cssTree) {
this.domTree = null;
this.cssTree = null;
this.rulesHash = {
ids: {},
classes: {},
tagNames: {}
};
this.domTree = domTree;
this.cssTree = cssTree;
}
StyleParser.prototype.parse = function () {
this.parseRulesHash(this.cssTree);
return this.genStyleTree(this.domTree);
};
StyleParser.prototype.parseRulesHash = function (rules) {
var rulesHash = this.rulesHash;
for (var _i = 0, _a = rules.stylesheet.rules; _i < _a.length; _i++) {
var rule = _a[_i]; // 处理keyframe等
if (rule.type !== 'rule') continue;
for (var _b = 0, _c = rule.selectors; _b < _c.length; _b++) {
var selector = _c[_b];
var keySeletor = this.genKeySelector(selector);
switch (keySeletor[0]) {
case '#':
var key = keySeletor.slice(1);
rulesHash.ids[key] = (0, _tslib.__spreadArray)((0, _tslib.__spreadArray)([], rulesHash.ids[key] || []), [{
selector: selector,
specificity: this.genSpecificity(selector),
style: this.genStyleFromRule(rule)
}]);
break;
case '.':
var classKey = keySeletor.slice(1);
rulesHash.classes[classKey] = (0, _tslib.__spreadArray)((0, _tslib.__spreadArray)([], rulesHash.classes[classKey] || []), [{
selector: selector,
specificity: this.genSpecificity(selector),
style: this.genStyleFromRule(rule)
}]);
break;
default:
rulesHash.tagNames[keySeletor] = (0, _tslib.__spreadArray)((0, _tslib.__spreadArray)([], rulesHash.tagNames[keySeletor] || []), [{
selector: selector,
specificity: this.genSpecificity(selector),
style: this.genStyleFromRule(rule)
}]);
break;
}
}
}
};
StyleParser.prototype.genStyleTree = function (root) {
var rootStyleNode = new StyleNode(); // 遍历doms
var stack = [[root, [], rootStyleNode]];
while (stack.length) {
var _a = stack.pop(),
node = _a[0],
path = _a[1],
rootStyleNode_1 = _a[2],
parentStyleNode = _a[3];
rootStyleNode_1.dom = node;
rootStyleNode_1.style = this.computeCSS(node, path, parentStyleNode === null || parentStyleNode === void 0 ? void 0 : parentStyleNode.style); // dom 查找样式并合并
for (var _i = 0, _b = node.children; _i < _b.length; _i++) {
var child = _b[_i];
var styleNode = new StyleNode();
rootStyleNode_1.originChildren.push(styleNode);
stack.push([child, (0, _tslib.__spreadArray)((0, _tslib.__spreadArray)([], path), [node]), styleNode, rootStyleNode_1]);
}
}
return rootStyleNode;
};
StyleParser.prototype.genSpecificity = function (selector) {
var _a, _b;
var idCount = ((_a = selector.match(/#\w+/g)) === null || _a === void 0 ? void 0 : _a.length) || 0;
var classCount = ((_b = selector.match(/\.\w+/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
var arr = selector.split(/\s+|#|\./).filter(function (s) {
return s !== '';
});
var tagCount = arr.length - idCount - classCount;
return idCount * 100 + classCount * 10 + tagCount;
};
StyleParser.prototype.genKeySelector = function (ruleSel) {
var selector = (0, _index.selectorToArr)(ruleSel, /\s/).pop();
var matchs = selector.match(/(#[^\.#]+)/);
if ((matchs === null || matchs === void 0 ? void 0 : matchs.length) > 0) return matchs[0];
matchs = selector.match(/\.[^\.#]+/);
if ((matchs === null || matchs === void 0 ? void 0 : matchs.length) > 0) return matchs[0];
return selector;
};
StyleParser.prototype.genStyleFromRule = function (rule) {
return this.genStyleFromDeclaration(rule.declarations);
};
StyleParser.prototype.genStyleFromDeclaration = function (declarations) {
var style = {};
declarations.forEach(function (dn) {
var value = dn.value;
style[dn.property] = value;
});
return style;
};
StyleParser.prototype.computeCSS = function (dom, path, parentStyle) {
var _this = this; // 从hash表中拿到匹配的rules
var filteredRules = [];
(0, _index.walkDomSelector)(dom, function (keyName, selector) {
switch (keyName) {
case 'id':
filteredRules.push.apply(filteredRules, _this.rulesHash.ids[selector] || []);
break;
case 'class':
filteredRules.push.apply(filteredRules, _this.rulesHash.classes[selector] || []);
break;
case 'tagName':
filteredRules.push.apply(filteredRules, _this.rulesHash.tagNames[selector] || []);
default:
break;
}
}); // 再根据路径筛选一次, 每条rule和dom的path去对比
var finaleRules = filteredRules.filter(function (rule) {
// 判断selector是否和路径匹配,
var ruleSelectors = (0, _index.selectorToArr)(rule.selector, /\s+/g); // 逆序判断每个子选择器
var lastSelMatch = ruleSelectors.length - 2;
var lastDomMatch = path.length - 1;
var result = true;
for (; lastSelMatch > -1; lastSelMatch--) {
var isMatch = false;
for (; lastDomMatch > -1; lastDomMatch--) {
// 不断取节点去匹配选择器
var dom_1 = path[lastDomMatch]; // 路径中该节点匹配命中,准备匹配下个
if ((0, _index.isSelectorMatchDom)(dom_1, ruleSelectors[lastSelMatch])) {
isMatch = true;
break;
}
}
if (!isMatch) {
result = false;
break;
}
}
return result;
}); // 根据优先级排序
finaleRules.sort(function (a, b) {
return a.specificity - b.specificity;
}); // 按顺序合并style,高优先级覆盖
var finalStyle = finaleRules.reduce(function (prev, cur) {
return Object.assign(prev, cur.style);
}, (0, _tslib.__assign)({}, defaultStyle)); // 解析属性值/属性转驼峰
var jsStyle = {};
for (var _i = 0, _a = Object.entries(finalStyle); _i < _a.length; _i++) {
var _b = _a[_i],
key = _b[0],
value = _b[1];
var camel = key.split('-').map(function (s, index) {
if (index > 0) {
return "" + s[0].toUpperCase() + s.slice(1);
}
return s;
}).join('');
var parsedValue = (0, _attrParser.parseAttr)(key, value);
if (_typeof(parsedValue) === 'object') {
jsStyle = (0, _tslib.__assign)((0, _tslib.__assign)({}, jsStyle), parsedValue);
} else {
jsStyle[camel] = parsedValue;
}
}
if (parentStyle) {
// 处理继承属性
for (var _c = 0, _d = Object.entries(jsStyle); _c < _d.length; _c++) {
var _e = _d[_c],
key = _e[0],
value = _e[1];
if (value === 'inherit' && inheritAttr.includes(key)) {
delete jsStyle[key];
if (parentStyle[key] !== undefined) {
jsStyle[key] = parentStyle[key];
}
}
}
for (var _f = 0, _g = Object.entries(parentStyle); _f < _g.length; _f++) {
var _h = _g[_f],
key = _h[0],
value = _h[1];
if (inheritAttr.includes(key) && !jsStyle[key]) {
jsStyle[key] = value;
}
}
}
return jsStyle;
};
return StyleParser;
}();
function _default(dom, css) {
return new StyleParser(dom, css).parse();
}