在移动端web中有很多应用的场景就是上下滑动页面顶部的 header 会随着滑动的高度而变换透明度,为了让页面内容进来有更多的展示,在这种情况下还是很多见的。
下面来分析一下这里做这效果的简单思路,我们首先要取到 header 的背景色,注意最好是要 rgba 格式的 background ,不然还得要多做一个不必要的颜色转换,然后再通过 getComputedStyle()
方法获取 dom 的样式,获取样式找到 backgroundColor 的 rgba,通过正则匹配找到最后的那个数字 0 ,再就是计算滑动高度和透明度值得函数计算的到新的数值,最后在 touchmove 的时候实时添加给 header 的rgba 上,大致就是这样的。
具体代码如下,本代码参考mui框架做了小的改动处理。
(function (window) {
"use strict";
var ZYTransparent = function(params) {
this.extend(this.params, params);
this.scrollByElem = window;
if (!this.scrollByElem) {
throw new Error("监听滚动的元素不存在");
}
this.isNativeScroll = false;
if (this.scrollByElem === window) {
this.isNativeScroll = true;
}
this._style = this.params.element.style;
this._bgColor = this._style.backgroundColor;
var color = this.getColor(this.getStyles(this.params.element, 'backgroundColor'));
if (color.length) {
this._R = color[0];
this._G = color[1];
this._B = color[2];
this._A = parseFloat(color[3]);
this.lastOpacity = this._A;
this._bufferFn = this.buffer(this.handleScroll, this.params.duration, this);
this.init();
} else {
throw new Error("元素背景颜色必须为RGBA");
}
};
ZYTransparent.prototype = {
params: {
element: false,
top: 0, // 距离顶部高度(到达该高度即触发)
offset: 150, // 滚动透明距离档设定top值后offset也会随着top向下延伸
duration: 16, // 过渡时间
},
init: function() {
var self = this;
if(!self.params.element){
return;
}
this.scrollByElem.addEventListener('scroll', this._bufferFn);
if (this.isNativeScroll) { //原生scroll
this.scrollByElem.addEventListener('touchmove', this._bufferFn);
}
},
handleScroll: function(e) {
var y = window.scrollY;
if (!this.isNativeScroll && e && e.detail) {
y = -e.detail.y;
}
var opacity = (y - this.params.top) / this.params.offset + this._A;
opacity = Math.min(Math.max(this._A, opacity), 1);
this._style.backgroundColor = 'rgba(' + this._R + ',' + this._G + ',' + this._B + ',' + opacity + ')';
if (this.lastOpacity !== opacity) {
this.trigger(this.params.element, 'alpha', {
alpha: opacity
});
this.lastOpacity = opacity;
}
},
trigger: function(element, eventType, eventData) {
element.dispatchEvent(new CustomEvent(eventType, {
detail: eventData,
bubbles: true,
cancelable: true
}));
return this;
},
buffer: function(fn, ms, context) {
var timer;
var lastStart = 0;
var lastEnd = 0;
var ms = ms || 150;
var that = this;
function run() {
if (timer) {
timer.cancel();
timer = 0;
}
lastStart = +new Date();
fn.apply(context || this, arguments);
lastEnd = +new Date();
}
return this.extend(function() {
if (
(!lastStart) || // 从未运行过
(lastEnd >= lastStart && +new Date() - lastEnd > ms) || // 上次运行成功后已经超过ms毫秒
(lastEnd < lastStart && +new Date() - lastStart > ms * 8) // 上次运行或未完成,后8*ms毫秒
) {
run();
} else {
if (timer) {
timer.cancel();
}
timer = that.later(run, ms, null, arguments);
}
}, {
stop: function() {
if (timer) {
timer.cancel();
timer = 0;
}
}
});
},
later: function(fn, when, context, data) {
var that = this;
when = when || 0;
var m = fn;
var d = data;
var f;
var r;
if (typeof fn === 'string') {
m = context[fn];
}
f = function() {
m.apply(context, d instanceof Array ? d : [d]);
};
r = setTimeout(f, when);
return {
id: r,
cancel: function() {
clearTimeout(r);
}
};
},
getStyles: function(element, property) {
var styles = element.ownerDocument.defaultView.getComputedStyle(element, null);
if (property) {
return styles.getPropertyValue(property) || styles[property];
}
return styles;
},
getColor: function(colorStr) {
var rgbaRegex = /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*(?:\.\d+)?)\)$/;
var matches = colorStr.match(rgbaRegex);
if (matches && matches.length === 5) {
return [
matches[1],
matches[2],
matches[3],
matches[4]
];
}
return [];
},
extend: function (a, b) { // a 代表默认参数, b 代表传的参数
for (var key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
return a;
}
};
window.ZYTransparent = ZYTransparent;
})(window);
整体代码为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
<title>Title</title>
<style>
body,html{
background: #dddddd;
}
*{
margin: 0;
padding: 0;
}
.bar{
position: fixed;
z-index: 10;
right: 0;
left: 0;
height: 44px;
padding-right: 10px;
padding-left: 10px;
border-bottom: 0;
background-color: rgba(255, 255, 255, 0);
}
p{
height: 40px;
}
</style>
</head>
<body>
<header class="bar transparent">
<div class="title">标题</div>
</header>
<div>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
<p>212</p>
</div>
</body>
<script src="transparent.js"></script>
<script>
new ZYTransparent({
element: document.querySelector('.transparent'),
top: 0, // 距离顶部高度(到达该高度即触发)
offset: 150, // 滚动透明距离档设定top值后offset也会随着top向下延伸
duration: 15 // 过渡时间
})
</script>
</html>
在线预览:猛戳这里