forked from evrone/postcss-px-to-viewport
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
executable file
·90 lines (83 loc) · 3.15 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
'use strict';
var postcss = require('postcss');
var objectAssign = require('object-assign');
// postcss-px2vw-exclude 添加排除文件夹配置
// excluding regex trick: http://www.rexegg.com/regex-best-trick.html
// Not anything inside double quotes
// Not anything inside single quotes
// Not anything inside url()
// Any digit followed by px
// !singlequotes|!doublequotes|!url()|pixelunit
var pxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)px/gi;
var defaults = {
viewportWidth: 720,
// viewportHeight: 568, // not now used; TODO: need for different units and math for different properties
unitPrecision: 5,
viewportUnit: 'vw',
selectorBlackList: [],
minPixelValue: 1,
propIgnoreList: [],
mediaQuery: false,
exclude: [],
multiple: 100, // 转换倍数
rules: { path: '', fn: () => { } },
};
module.exports = postcss.plugin('postcss-px-to-viewport-rxdey', function (options) {
var opts = objectAssign({}, defaults, options);
var pxReplace = createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, opts.viewportUnit, opts.rules, opts.multiple);
return function (css) {
var path = css.source.input.file;
var rulesPath = opts.rules.path ? blacklistedPath(opts.rules.path, path) : true; // 指定了路径 只对路径下生效
var r = pxReplace(rulesPath)
css.walkDecls(function (decl, i) {
if (decl.value.indexOf('px') === -1) return;
if (opts.propIgnoreList.indexOf(decl.prop) !== -1) return;
if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector))
return;
if (blacklistedPath(opts.exclude, path)) return;
decl.value = decl.value.replace(pxRegex, r);
});
if (opts.mediaQuery) {
css.walkAtRules('media', function (rule) {
if (rule.params.indexOf('px') === -1) return;
rule.params = rule.params.replace(pxRegex, r);
});
}
};
});
function createPxReplace (viewportSize, minPixelValue, unitPrecision, viewportUnit, rules, multiple) {
return function (rulesPath) {
return function (m, $1) {
if (!$1) return m;
var pixels = parseFloat($1);
if (pixels <= minPixelValue) return m;
var vm = toFixed((pixels / viewportSize) * multiple, unitPrecision);
if (JSON.stringify(rules.fn(pixels, vm)) && rulesPath) { // 是否自定义规则 自定义规则必须带有返回值
return rules.fn(pixels, vm);
}
return vm + viewportUnit;
};
}
}
function toFixed (number, precision) {
var multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return (Math.round(wholeNumber / 10) * 10) / multiplier;
}
function blacklistedSelector (blacklist, selector) {
if (typeof selector !== 'string') return;
return blacklist.some(function (regex) {
if (typeof regex === 'string') return selector.indexOf(regex) !== -1;
return selector.match(regex);
});
}
function blacklistedPath (blacklist, path) {
if (typeof blacklist === 'string') {
blacklist = [blacklist];
}
if (!blacklist.length || !path) return false;
var pathArray = path.split(/[\/|\\]/); // Get filepath
return blacklist.some(item => {
return pathArray.indexOf(item) !== -1;
});
}