- 判断浏览器是否支持响应式。
(
function
(w) {
"use strict"
;
w.matchMedia = w.matchMedia ||
function
(doc,
undefined
) {
var
bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement(
"body"
), div = doc.createElement(
"div"
);
div.id =
"mq-test-1"
;
div.style.cssText =
"position:absolute;top:-100em"
;
fakeBody.style.background =
"none"
;
fakeBody.appendChild(div);
return
function
(q) {
//通过对元素加入media的样式,在判断元素是否因此而改变。
div.innerHTML = '';
docElem.insertBefore(fakeBody, refNode);
bool = div.offsetWidth === 42;
docElem.removeChild(fakeBody);
return
{
matches: bool,
media: q
};
};
}(w.document);
})(
this
);
- 收集所有css link 的 href。
ripCSS =
function
() {
//links在之前已经完成整理。 head = doc.getElementsByTagName( "head" )[0] || docElem;links = head.getElementsByTagName( "link" );
for (var i = 0; i < links.length; i++) {
var
sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() ===
"stylesheet"
;
if
(!!href && isCSS && !parsedSheets[href]) {
if
(sheet.styleSheet && sheet.styleSheet.rawCssText) {
translate(sheet.styleSheet.rawCssText, href, media);
parsedSheets[href] =
true
;
}
else
{
if
(!
/^([a-zA-Z:]*\/\/)/
.test(href) && !base || href.replace(RegExp.$1,
""
).split(
"/"
)[0] === w.location.host) {
if
(href.substring(0, 2) ===
"//"
) {
href = w.location.protocol + href;
}
requestQueue.push({
href: href,
media: media
});
}
}
}
}
makeRequests();
};
- 整理相关 @media 媒体查询脚本的元数据。
translate =
function
(styles, href, media) {
//styles是.css文件的文本。通过ajax发起请求获取得到。
//对styles替换掉无效部分,匹配其中@media部分到变量qs。
//对styles替换掉无效部分,匹配其中@media部分到变量qs。
var qs = styles.replace( respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
href = href.substring(0, href.lastIndexOf(
"/"
));
var
repUrls =
function
(css) {
return
css.replace( respond.regex.urls,
"$1"
+ href +
"$2$3"
);
}, useMedia = !ql && media;
if
(href.length) {
href +=
"/"
;
}
if
(useMedia) {
ql = 1;
}
//分析qs,得出mediastyles的各项参数。整理出下图的数据结构。
for ( var i = 0; i < ql; i++) {
var fullq, thisq, eachq, eql;
if (useMedia) {
fullq = media;
rules.push(repUrls(styles));
} else {
fullq = qs[i].match( respond.regex.findStyles) && RegExp.$1;
rules.push(RegExp.$2 && repUrls(RegExp.$2));
}
eachq = fullq.split( ",");
eql = eachq.length;
for ( var j = 0; j < eql; j++) {
thisq = eachq[j];
if (isUnsupportedMediaQuery(thisq)) {
continue;
}
mediastyles.push({
media: thisq.split( "(")[0].match(respond.regex.only) && RegExp.$2 || "all",
rules: rules.length - 1,
hasquery: thisq.indexOf( "(") > -1,
minw: thisq.match( respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || "" ),
maxw: thisq.match( respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "" )
});
}
}
applyMedia();
}
- 实现 @media 的相关功能。
applyMedia =
function
(fromResize) {
var
name =
"clientWidth"
, docElemProp = docElem[name], currWidth = doc.compatMode ===
"CSS1Compat"
&& docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now =
new
Date().getTime();
//之前已经定义resizeThrottle = 30;
//如果连续的resize在30ms内,延迟30ms后在触发一次resize job。
//如果连续的resize在30ms内,延迟30ms后在触发一次resize job。
//formResize表示经过Respond初始化resize后,手工改变屏幕大小。
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
w.clearTimeout( resizeDefer);
resizeDefer = w.setTimeout( applyMedia, resizeThrottle);
return;
} else {
lastCall = now;
}
//整理出不含@media的各种设备对应的样式。
for (var i in mediastyles) {
if (mediastyles.hasOwnProperty(i)) {
var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null , maxnull = max === null, em = "em";
if (!!min) {
min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
}
if (!!max) {
max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
}
//如果满足以下条件,将样式添加到该设备的样式集合styleBlocks中。
//1.如果不是媒体查询 !thisstyle.hasquery。
//2.如果存在媒体查询的min-width或者max-width配置。
//3.如果当前设备宽度在媒体查询的min-width、max-width之间。
//1.如果不是媒体查询 !thisstyle.hasquery。
//2.如果存在媒体查询的min-width或者max-width配置。
//3.如果当前设备宽度在媒体查询的min-width、max-width之间。
if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
if (!styleBlocks[thisstyle.media]) {
styleBlocks[thisstyle.media] = [];
}
styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
}
}
}
//初始appendedEls = [],head = doc.getElementsByTagName( "head" )[0] || docElem,是html head元素。。由于本方法是在window.setTimeout中执行,appendedEls作为全局变量,有记忆功能。用于删除中的,因为.css中的@media由Respond resize代替。
for ( var j in appendedEls) {
if (appendedEls.hasOwnProperty(j)) {
if (appendedEls[j] && appendedEls[j].parentNode === head) {
head.removeChild(appendedEls[j]);
}
}
}
appendedEls.length = 0;
//将同一设备的样式组合到一个