-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpx2scalability.js
156 lines (127 loc) · 4.56 KB
/
px2scalability.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
'use strict'
const fs = require('fs')
const css = require('css')
const defaultConfig = {
pageWidth: 750, // design draft width
precision: 6, // 精度,默认是6位
keepComment: 'no'
}
const TYPE_PX2REM = 'px2rem'
const TYPE_PX2VW = 'px2vw'
const TYPE_VW2REM = 'vw2rem'
const TYPE_REM2VW = 'rem2vw'
const UNIT_VW = 'vw'
const UNIT_REM = 'rem'
const pxRegExp = /\b(\d+(\.\d+)?)px\b/
const remRegExp = /\b(\d+(\.\d+)?)rem\b/
const vwRegExp = /\b(\d+(\.\d+)?)vw\b/
class Px2scalability {
constructor(options) {
this.config = {}
Object.assign(this.config, defaultConfig, options)
}
init (cssText, type) {
switch (type) {
case TYPE_PX2VW:
return this.px2vw(cssText)
case TYPE_PX2REM:
return this.px2rem(cssText)
case TYPE_VW2REM:
return this.vw2rem(cssText)
case TYPE_REM2VW:
return this.rem2vw(cssText)
default:
console.error(`Unknown type: ${type}`)
break
}
}
processRules (rules, type) {
const config = this.config
for (let i = 0, len = rules.length; i < len; i++) {
let rule = rules[i]
if (rule.type === 'media') {
this.processRules(rule.rules, type)
continue
} else if (rule.type === 'keyframes') {
this.processRules(rule.keyframes, type)
continue
} else if (rule.type !== 'rule' && rule.type !== 'keyframe'){
continue
}
let declarations = rule.declarations
for (let j = 0, dlen = declarations.length; j < dlen; j ++ ) {
let declaration = declarations[j]
if (declaration.type === 'declaration' && pxRegExp.test(declaration.value)) {
let nextDeclaration = rule.declarations[j+1]
if (nextDeclaration && nextDeclaration.type === 'comment') {
let pureComment = nextDeclaration.comment.trim()
if (pureComment === config.keepComment) {
declarations.slice(j+1, 1)
continue
}
}
}
declaration.value = this.unitConversion(type, declaration.value)
}
}
}
px2vw (cssText) {
const AST = css.parse(cssText)
const rules = AST.stylesheet.rules
this.processRules(rules, TYPE_PX2VW)
return css.stringify(AST)
}
px2rem (cssText) {
const AST = css.parse(cssText)
const rules = AST.stylesheet.rules
this.processRules(rules, TYPE_PX2REM)
return css.stringify(AST)
}
vw2rem (cssText) {
const AST = css.parse(cssText)
const rules = AST.stylesheet.rules
this.processRules(rules, TYPE_VW2REM)
return css.stringify(AST)
}
rem2vw (cssText) {
const AST = css.parse(cssText)
const rules = AST.stylesheet.rules
this.processRules(rules, TYPE_REM2VW)
return css.stringify(AST)
}
unitConversion (type, value) {
if (!value) {
return ""
}
const config = this.config
const pxGlobalRegExp = new RegExp(pxRegExp.source, 'g')
const vwGlobalRegExp = new RegExp(vwRegExp.source, 'g')
const remGlobalRegExp = new RegExp(remRegExp.source, 'g')
let fitGlobalRegExp = pxGlobalRegExp
if (type === TYPE_VW2REM) {
fitGlobalRegExp = vwGlobalRegExp
} else if (type === TYPE_REM2VW) {
fitGlobalRegExp = remGlobalRegExp
}
function computeValue (value, unit) {
value = parseFloat(value.toFixed(config.precision))
return value == 0 ? value : value + unit
}
return value.replace(fitGlobalRegExp, ($0, $1) => {
switch (type) {
case TYPE_PX2VW:
return computeValue($1 * 100 / config.pageWidth, UNIT_VW)
case TYPE_PX2REM:
return computeValue($1 * 10 / config.pageWidth, UNIT_REM)
case TYPE_VW2REM:
return computeValue($1 / 10, UNIT_REM)
case TYPE_REM2VW:
return computeValue($1 * 10, UNIT_VW)
default:
console.error(`Unknown type: ${type}`)
break
}
})
}
}
module.exports = Px2scalability