Eighteen Blog

前两篇文介绍了css3的过滤器filter用来实现图片的高斯模糊效果,还有js拖拽的功能。
要实现局部模糊就要把两者结合起来,计算位移就可以了。

实现原理

原理其实很简单,就是两张图的叠加。底部一张清晰的图,上面一个高斯模糊过的图,将高斯模糊的图当作上层元素的背景,利用背景定位使其只显示一部分,然后把这个高斯模糊的窗口放置在高清图的上层,背景图片的位置与下面的图片位置一致,这样看起来就像一张高清的图片打上了马赛克一样。讲起来不是很清楚,大家可以看一下代码。

基础版本

HTML

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
<style type="text/css">
#css_box {
position: relative;
width: 100%;
height: 500px;
background: url('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567844929804&di=75928af77a3db7ff54cd4eab49361bc0&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201307%2F19%2F20130719082039_k2NHG.jpeg') no-repeat;
}

#css_target {
position: absolute;
left: 0px;
top: 0px;
width: 200px;
height: 200px;
background: inherit;
filter: blur(10px);
/* 继承父元素的background属性 */
}
</style>
<div class="demo post white-box article-type-post">
<div id="css_box">
<div id="css_target">

</div>
</div>
</div>

<script>
var bar = document.getElementById("css_box");
var target = document.getElementById("css_target");

startDrag(bar, target, function(x, y) {
target.style.backgroundPosition = (-1 * x) + "px " + (-1 * y) + "px";
});
</script>

JS (当作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
var getCss = function(o, key) {
return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, false)[key];
};
// 拖拽
var startDrag = function(bar, target, callback) {
maxX = parseInt(getCss(bar, "width")) - parseInt(getCss(target, "width"));
maxY = parseInt(getCss(bar, "height")) - parseInt(getCss(target, "height"));
var resX = 0,
resY = 0;
var params = {
left: 0,
top: 0,
currentX: 0,
currentY: 0,
flag: false
};

if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}

if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}

target.onmousedown = function(event) {
params.flag = true;
if (!event) {
event = window.event;
bar.onselectstart = function() {
return false;
}
}
var e = event;
params.currentX = e.clientX;
params.currentY = e.clientY;
};

document.onmouseup = function() {
params.flag = false;
if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}
if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}
};

document.onmousemove = function(event) {
var e = event ? event : window.event;
if (params.flag) {
var nowX = e.clientX,
nowY = e.clientY;

var disX = nowX - params.currentX,
disY = nowY - params.currentY;
if ((parseInt(params.left) + disX) > maxX) {
resX = maxX;
} else if ((parseInt(params.left) + disX) < 0) {
resX = 0;
} else {
resX = parseInt(params.left) + disX;
}

if ((parseInt(params.top) + disY) > maxY) {
resY = maxY;
} else if ((parseInt(params.top) + disY) < 0) {
resY = 0;
} else {
resY = parseInt(params.top) + disY;
}

target.style.left = resX + 'px'

target.style.top = resY + 'px'

if (typeof callback == "function") {
callback(resX, resY);
}
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
}
};

兼容移动端优化版本

HTML

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
<style type="text/css">
#css_box {
position: relative;
touch-action: none;
width: 100%;
height: 500px;
background: url('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567844929804&di=75928af77a3db7ff54cd4eab49361bc0&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201307%2F19%2F20130719082039_k2NHG.jpeg') no-repeat;
background-size: contain;
}

#css_target {
position: absolute;
left: 0px;
top: 0px;
background: inherit;
filter: blur(10px);
touch-action: none;
/* 继承父元素的background属性 */
}
</style>
<div class="demo post white-box article-type-post">
<h2 class="title">mosaic Demo <a style="color: #bd4117;" href="https://www.zsfmyz.top/Css/Css3%20+%20Js%EF%BC%9A%E5%9B%BE%E7%89%87%E7%9A%84%E5%B1%80%E9%83%A8%E6%A8%A1%E7%B3%8A%EF%BC%88%E9%A9%AC%E8%B5%9B%E5%85%8B%EF%BC%89/">传送门</a></h2>

<div id="css_box">
<div id="css_target">

</div>
</div>
<p id="position_img">X: 0 px Y: 0 px</p>
</div>
<script>
$(document).ready(function() {
var bar = document.getElementById("css_box");
var target = document.getElementById("css_target");
var p_img = document.getElementById("position_img");

// 兼容分辨率
bar.style.height = (parseInt(getCss(bar, "width")) * 636 / 900) + 'px';
target.style.backgroundSize = parseInt(getCss(bar, "width")) + 'px ' + (parseInt(getCss(bar, "width")) * 636 / 900) + 'px';

startDrag(bar, target, function(x, y) {
target.style.backgroundPosition = (-1 * x) + "px " + (-1 * y) + "px";
p_img.innerText = "X: " + target.style.left + " Y: " + target.style.top;
});
})
</script>

JS (当作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
<script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
<script>
// 拖拽
var startDrag = function(bar, target, callback) {
var getCss = function(o, key) {
return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, false)[key];
};

var down = function(event) {
// 兼容分辨率
bar.style.height = (parseInt(getCss(bar, "width")) * 636 / 900) + 'px';
target.style.backgroundSize = parseInt(getCss(bar, "width")) + 'px ' + (parseInt(getCss(bar, "width")) * 636 / 900) + 'px';

params.flag = true;
if (!event) {
event = window.event;
bar.onselectstart = function() {
return false;
}
}
var e = event;
params.currentX = e.clientX || e.changedTouches[0].clientX;
params.currentY = e.clientY || e.changedTouches[0].clientY;
};

var up = function() {
params.flag = false;
if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}
if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}
};

var move = function(event) {
var e = event ? event : window.event;
if (params.flag) {
var nowX = e.clientX || e.changedTouches[0].clientX,
nowY = e.clientY || e.changedTouches[0].clientY;
var disX = nowX - params.currentX,
disY = nowY - params.currentY;
if ((parseInt(params.left) + disX) > maxX) {
resX = maxX;
} else if ((parseInt(params.left) + disX) < 0) {
resX = 0;
} else {
resX = parseInt(params.left) + disX;
}

if ((parseInt(params.top) + disY) > maxY) {
resY = maxY;
} else if ((parseInt(params.top) + disY) < 0) {
resY = 0;
} else {
resY = parseInt(params.top) + disY;
}

target.style.left = resX + 'px'

target.style.top = resY + 'px'

if (typeof callback == "function") {
callback(resX, resY);
}
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
}

var resX = 0,
resY = 0;
var params = {
left: 0,
top: 0,
currentX: 0,
currentY: 0,
flag: false
};

if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}

if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}

if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
console.log("mobile");
target.style.width = '100px';
target.style.height = '100px';
maxX = parseInt(getCss(bar, "width")) - parseInt(getCss(target, "width"));
maxY = parseInt(getCss(bar, "height")) - parseInt(getCss(target, "height"));

target.ontouchstart = down

document.ontouchend = up

document.ontouchmove = move
} else {
console.log("pc");
target.style.width = '150px';
target.style.height = '150px';
maxX = parseInt(getCss(bar, "width")) - parseInt(getCss(target, "width"));
maxY = parseInt(getCss(bar, "height")) - parseInt(getCss(target, "height"));

target.onmousedown = down

document.onmouseup = up

document.onmousemove = move
}

};
</script>

以上就是局部模糊的实现方法。可以直接套用。将JS部分当作文件引入。否则要把初始化函数放在函数声明的后面。

最后可查看实际效果:demo演示地址

借鉴于张大神

 评论