tml2canvas是一個用于html截屏的js插件,在網站切圖項目中不太常見,以至于在遇到問題的時候,能夠被查閱到的有用信息很少,這次是一個很復雜的使用案例,進行了多次的截屏、拼接、再截屏,并且解決了截屏錯位空白問題,增加了保存圖片到本地的有效代碼方案。
其中關于截屏空白的問題(頁面有下拉的時候產生),先后查閱了國內外資料后找到了有效解決方案,頗為曲折。
/*第一次把圖標截圖放到模板里*/
html2canvas(document.querySelector(".tjqx-bars "),{
//height:850,
//y:window.pageYOffset,
}).then(canvas => {
$('#captureimg').html(canvas);
/*第二次把模板整個截圖*/
html2canvas(document.querySelector("#capturetmpl"),{
//height:1240,
//y:window.pageYOffset,
scrollX: 0,
scrollY: -window.scrollY,
}).then(canvas => {
//canvas.setAttribute('id','thecanvas');
$('#capture').html(canvas);
//圖片寫到body臨時存儲
var dataURL = canvas.toDataURL();
$(document.body).data('url', dataURL);
//Canvas2Image.saveAsPNG(canvas);
//var dataURL = canvas.toDataURL("image/png");
//console.log(dataURL);
//$(document.body).data('url', dataURL);
//var tmpUrl = "data:application/octet-stream;base64" + dataURL;
// $('.kzdialog-fz').attr('href', tmpUrl);
//關閉
layer.close(index);
});
//復制圖片提示
$('.kzdialog-fz').click(function(){
var url = $(document.body).data('url');
$("<a>", {
href: url,
download: "fileName"
})
.on("click", function() {$(this).remove()})
.appendTo("body")[0].click();
//var oCanvas = document.getElementById("thecanvas");
//Canvas2Image.saveAsPNG(oCanvas);
//layer.msg('復制成功');
//layer.msg('復制圖片失敗 請重試');
})
標簽:html2canvas
言:每當過節的時候,女朋友就抱怨我總是忘記給她買花,說程序不懂浪漫,這不我準備了幾款愛心動畫特效,打算當面向她表達一下。
寓意:告白無須多么華麗的語言,一顆顆小的愛心匯聚成一顆真心,讓你的另一半感受到濃濃的愛意。
代碼難度系數★★★
新建index.html,復制以下代碼保存在瀏覽器中打開即可。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>canvas 心</title>
<style>
html, body {
height: 100%;
padding: 0;
margin: 0;
background: #000;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
}</style>
</head>
<body>
<canvas id="pinkboard"></canvas>
<script>
/*
* Settings
*/
var settings = {
particles: {
length: 500, // maximum amount of particles
duration: 2, // particle duration in sec
velocity: 100, // particle velocity in pixels/sec
effect: -0.75, // play with this for a nice effect
size: 30, // particle size in pixels
},
};
/*
* RequestAnimationFrame polyfill by Erik M?ller
*/
(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelAnimationFrame=window[c[a]+"CancelAnimationFrame"]||window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());
/*
* Point class
*/
var Point = (function() {
function Point(x, y) {
this.x = (typeof x !== 'undefined') ? x : 0;
this.y = (typeof y !== 'undefined') ? y : 0;
}
Point.prototype.clone = function() {
return new Point(this.x, this.y);
};
Point.prototype.length = function(length) {
if (typeof length == 'undefined')
return Math.sqrt(this.x * this.x + this.y * this.y);
this.normalize();
this.x *= length;
this.y *= length;
return this;
};
Point.prototype.normalize = function() {
var length = this.length();
this.x /= length;
this.y /= length;
return this;
};
return Point;
})();
/*
* Particle class
*/
var Particle = (function() {
function Particle() {
this.position = new Point();
this.velocity = new Point();
this.acceleration = new Point();
this.age = 0;
}
Particle.prototype.initialize = function(x, y, dx, dy) {
this.position.x = x;
this.position.y = y;
this.velocity.x = dx;
this.velocity.y = dy;
this.acceleration.x = dx * settings.particles.effect;
this.acceleration.y = dy * settings.particles.effect;
this.age = 0;
};
Particle.prototype.update = function(deltaTime) {
this.position.x += this.velocity.x * deltaTime;
this.position.y += this.velocity.y * deltaTime;
this.velocity.x += this.acceleration.x * deltaTime;
this.velocity.y += this.acceleration.y * deltaTime;
this.age += deltaTime;
};
Particle.prototype.draw = function(context, image) {
function ease(t) {
return (--t) * t * t + 1;
}
var size = image.width * ease(this.age / settings.particles.duration);
context.globalAlpha = 1 - this.age / settings.particles.duration;
context.drawImage(image, this.position.x - size / 2, this.position.y - size / 2, size, size);
};
return Particle;
})();
/*
* ParticlePool class
*/
var ParticlePool = (function() {
var particles,
firstActive = 0,
firstFree = 0,
duration = settings.particles.duration;
function ParticlePool(length) {
// create and populate particle pool
particles = new Array(length);
for (var i = 0; i < particles.length; i++)
particles[i] = new Particle();
}
ParticlePool.prototype.add = function(x, y, dx, dy) {
particles[firstFree].initialize(x, y, dx, dy);
// handle circular queue
firstFree++;
if (firstFree == particles.length) firstFree = 0;
if (firstActive == firstFree ) firstActive++;
if (firstActive == particles.length) firstActive = 0;
};
ParticlePool.prototype.update = function(deltaTime) {
var i;
// update active particles
if (firstActive < firstFree) {
for (i = firstActive; i < firstFree; i++)
particles[i].update(deltaTime);
}
if (firstFree < firstActive) {
for (i = firstActive; i < particles.length; i++)
particles[i].update(deltaTime);
for (i = 0; i < firstFree; i++)
particles[i].update(deltaTime);
}
// remove inactive particles
while (particles[firstActive].age >= duration && firstActive != firstFree) {
firstActive++;
if (firstActive == particles.length) firstActive = 0;
}
};
ParticlePool.prototype.draw = function(context, image) {
// draw active particles
if (firstActive < firstFree) {
for (i = firstActive; i < firstFree; i++)
particles[i].draw(context, image);
}
if (firstFree < firstActive) {
for (i = firstActive; i < particles.length; i++)
particles[i].draw(context, image);
for (i = 0; i < firstFree; i++)
particles[i].draw(context, image);
}
};
return ParticlePool;
})();
/*
* Putting it all together
*/
(function(canvas) {
var context = canvas.getContext('2d'),
particles = new ParticlePool(settings.particles.length),
particleRate = settings.particles.length / settings.particles.duration, // particles/sec
time;
// get point on heart with -PI <= t <= PI
function pointOnHeart(t) {
return new Point(
160 * Math.pow(Math.sin(t), 3),
130 * Math.cos(t) - 50 * Math.cos(2 * t) - 20 * Math.cos(3 * t) - 10 * Math.cos(4 * t) + 25
);
}
// creating the particle image using a dummy canvas
var image = (function() {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
canvas.width = settings.particles.size;
canvas.height = settings.particles.size;
// helper function to create the path
function to(t) {
var point = pointOnHeart(t);
point.x = settings.particles.size / 2 + point.x * settings.particles.size / 350;
point.y = settings.particles.size / 2 - point.y * settings.particles.size / 350;
return point;
}
// create the path
context.beginPath();
var t = -Math.PI;
var point = to(t);
context.moveTo(point.x, point.y);
while (t < Math.PI) {
t += 0.01; // baby steps!
point = to(t);
context.lineTo(point.x, point.y);
}
context.closePath();
// create the fill
context.fillStyle = '#ea80b0';
context.fill();
// create the image
var image = new Image();
image.src = canvas.toDataURL();
return image;
})();
// render that thing!
function render() {
// next animation frame
requestAnimationFrame(render);
// update time
var newTime = new Date().getTime() / 1000,
deltaTime = newTime - (time || newTime);
time = newTime;
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// create new particles
var amount = particleRate * deltaTime;
for (var i = 0; i < amount; i++) {
var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random());
var dir = pos.clone().length(settings.particles.velocity);
particles.add(canvas.width / 2 + pos.x, canvas.height / 2 - pos.y, dir.x, -dir.y);
}
// update and draw particles
particles.update(deltaTime);
particles.draw(context, image);
}
// handle (re-)sizing of the canvas
function onResize() {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
window.onresize = onResize;
// delay rendering bootstrap
setTimeout(function() {
onResize();
render();
}, 10);
})(document.getElementById('pinkboard'));</script>
</body>
</html>
寓意:將想說的話打開一顆顆的愛心氣球上,隨著氣球不斷的升空,讓整個氛圍可更加地纏綿,看到此處可以有感動的淚水。
代碼難度系數★★★
新建index.html,復制以下代碼保存在瀏覽器中打開即可。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>情人節快樂:)</title>
<style>
canvas {
position: absolute;
top: 0;
left: 0;
}</style>
</head>
<body>
<canvas id=c></canvas>
<script>
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
phrases: [ "Don't die\nit's not hard", "You're the Best", "Every day,\nYou're beautiful", "Every occasion,\nYou're clever", "A world without You?\nNah", "Keep kicking ass", "You're better than them,\nwhoever they are", "You're just amazing", "You are,\ntherefore I am", "Nothing better than You \ncould have happened to the world" ],
balloons: 10,
baseVelY: -1,
addedVelY: -1,
baseVelX: -.25,
addedVelX: .5,
baseSize: 20,
addedSize: 10,
baseSizeAdder: 2,
addedSizeAdder: 2,
baseIncrementer: .01,
addedIncrementer: .03,
baseHue: -10,
addedHue: 30,
font: '15px Verdana'
},
cycle = 0,
balloons = [];
ctx.font = opts.font;
function Balloon(){
this.reset();
}
Balloon.prototype.reset = function(){
this.size = opts.baseSize + opts.addedSize * Math.random();
this.sizeAdder = opts.baseSizeAdder + opts.addedSizeAdder * Math.random();
this.incrementer = opts.baseIncrementer + opts.addedIncrementer * Math.random();
this.tick = 0;
this.x = Math.random() * w;
this.y = h + this.size;
this.vx = opts.baseVelX + opts.addedVelX * Math.random();
this.vy = opts.baseVelY + opts.addedVelY * Math.random();
this.color = 'hsla(hue,70%,60%,.8)'.replace( 'hue', opts.baseHue + opts.addedHue * Math.random() );
this.phrase = opts.phrases[ ++cycle % opts.phrases.length ].split( '\n' );
this.lengths = [];
for( var i = 0; i < this.phrase.length; ++i )
this.lengths.push( -ctx.measureText( this.phrase[ i ] ).width / 2 );
}
Balloon.prototype.step = function(){
this.tick += this.incrementer;
this.x += this.vx;
this.y += this.vy;
var size = this.size + this.sizeAdder * Math.sin( this.tick );
ctx.lineWidth = size / 40;
ctx.strokeStyle = '#eee';
ctx.beginPath();
ctx.moveTo( this.x, this.y - 2 );
ctx.lineTo( this.x, this.y + size );
ctx.stroke();
ctx.fillStyle = this.color;
ctx.translate( this.x, this.y );
ctx.rotate( Math.PI / 4 );
//ctx.fillRect( -size / 2, -size / 2, size / 2, size / 2 );
ctx.beginPath();
ctx.moveTo( 0, 0 );
ctx.arc( -size / 2, -size / 2 + size / 4, size / 4, Math.PI / 2, Math.PI * 3 / 2 );
ctx.arc( -size / 2 + size / 4, -size / 2, size / 4, Math.PI, Math.PI * 2 );
ctx.lineTo( 0, 0 );
ctx.fill();
ctx.rotate( -Math.PI / 4 );
ctx.translate( -this.x, -this.y );
ctx.translate( this.x, this.y + size + 15 );
ctx.scale( size / this.size, size / this.size );
ctx.fillStyle = '#eee';
for( var i = 0; i < this.phrase.length; ++i )
ctx.fillText( this.phrase[ i ], this.lengths[ i ], i * 15 );
ctx.scale( this.size / size, this.size / size );
ctx.translate( -this.x, -( this.y + size + 15 ) );
if( this.y < -size * 3 )
this.reset();
}
function anim(){
window.requestAnimationFrame( anim );
ctx.fillStyle = '#222';
ctx.fillRect( 0, 0, w, h );
if( balloons.length < opts.balloons && Math.random() < .01 )
balloons.push( new Balloon );
for( var i = 0; i < balloons.length; ++i )
balloons[ i ].step();
}
anim();</script>
</body>
</html>
寓意:天空中下起了愛心雨,襯托的房間變得溫暖,也讓整個場景都變得溫馨無比,想必此時可以有一個大大的擁抱。
代碼難度系數★★★
代碼有image、js和html,所以不好貼出來,有需要的朋友直接問我要吧。
總結:程序員的工作本身就很枯燥,特定找了幾個好看的特效拿出來和大家分享,希望大家能夠快樂每一天,上述代碼親測可用,歡迎點贊收藏。
《完》
大家如果喜歡的話麻煩點贊、關注、轉發,謝謝大家。
如果網頁只有一種顏色,那是非常可怕的,顏色的設置豐富了網頁,就如同多彩繽紛的世界。
在了解css顏色之前,我們回顧下計算機是如何顯示顏色的?計算機根據色光三原色的原理通過各種算法來顯示顏色。
網頁中使用顏色關鍵字、16進制字符、rgb、rgba等表示紅,綠,藍三種顏色混合色,如下示例,幾種寫法都是指同一個顏色(紅色):
color:red;
color: #ff0000;
color: rgb(255,0,0)
color: rgba(255,0,0,1)
對于16進制形式,每2位表示一個顏色,從左到右分別是紅、綠、藍,每種顏色取值從00 到 FF。
如下示例:
color: #000000; /*黑色*/
color: #ffffff; /*白色*/
color: #ff0000; /*紅色*/
color: #00ff00; /*綠色*/
color: #0000ff; /*藍色*/
對于rgb的表示法,由三個參數組成,分別是紅、綠、藍,每種顏色取值從0 到 255。
如下示例:
color: rgb(0,0,0); /*黑色*/
color: rgb(255,255,255); /*白色*/
color: rgb(255,0,0); /*紅色*/
color: rgb(0,255,0); /*綠色*/
color: rgb(0,0,255); /*藍色*/
紅,綠,藍值從0到255的結合,給出了總額超過1600多萬不同的顏色(256 × 256 ×256)。
但是現代大多數顯示器能夠顯示至少16384種顏色。所以在使用顏色時要格外注意,避免設置不能夠顯示的顏色,可以參考網頁安全色:https://www.w3school.com.cn/cssref/css_colors.asp。
顏色除了有三原色紅綠藍組成,還有亮度層級,如下圖:
rgba 中的a是指透明度,這個是css3新增加的屬性,通過rgba可以設置更加漂亮的顏色。
通過background屬性可以設置元素的背景色、背景圖片,語法如下:
background:bg-color bg-image position/bg-size bg-repeat bg-origin bg-clip bg-attachment initial|inherit;
background 在一個聲明中設置所有的背景屬性,可以在這里設置如下屬性:
各值之間用空格分隔,不分先后順序。可以只有其中的某些值,例如 background:#FF0000 url(img.png)是允許的,但至少有一個值。
建議使用background 簡寫屬性,這樣可以更好地兼容較老的瀏覽器,少寫很多代碼,當然你也可以分開使用,比如:
background-color: #ff0000;
background-image: url(img.png);
background-repeat: no-repeat;
background-size: 100% auto;
1、背景顏色 —— background-color
background-color 和之前講的的color 一樣,可以使用16進制、rgb、rgba等設置顏色。如下實例:
<html>
<head>
<style type="text/css">
body {background-color: yellow}
h1 {background-color: #00ff00}
h2 {background-color: transparent}
p {background-color: rgb(250,0,255)}
p.no2 {background-color: gray; padding: 20px;}
</style>
</head>
<body>
<h1>背景色1</h1>
<h2>背景色2</h2>
<p>背景色3</p>
<p class="no2">背景色4</p>
</body>
</html>
如下圖顯示:
注意:background-color: transparent; 指透明色,不顯示任何顏色。
2、背景圖片的使用——background-image
給html元素添加背景圖片,在早期網頁制作中被廣泛應用,如今已不建議大量使用。如下實例:
body {background-image:url(/static/bg.gif);}
這里使用了一個125*125大小的圖片,如下:
但是你會發現,整個網頁鋪滿了圖片,上面的代碼默認會鋪滿整個頁面從左到右,從上到下 。如果不想被平鋪,可以使用background-repeat 設置。
背景圖片同時可以設置多個背景圖片,如下:
background-image: url(/statics/bg1.gif), url(/statics/bg2.gif);
多個圖像以逗號隔開,在頁面中多個圖片會疊加顯示,第一張圖片顯示在最頂端。
如下效果:
3、背景重復方式 —— background-repeat
它有如下幾個屬性:
repeat | 默認。背景圖像將在垂直方向和水平方向重復。 |
repeat-x | 背景圖像將在水平方向重復。 |
repeat-y | 背景圖像將在垂直方向重復。 |
no-repeat | 背景圖像不重復。 |
inherit | 從父元素繼承 background-repeat 屬性的設置。 |
實例如下:
4、背景圖的位置 —— background-position
背景圖片默認顯示在左上角,語法如下:
background-position: x y; // x 距離左邊距離,y距離頂部距離
如果要改變它的位置,可以使用關鍵字:top、bottom、left、right 和 center;或者使用長度值,如 100px 或 5cm;也可以使用百分數值。
x 可以取值 百分比| 數值| left | center | right。
y 可以取值 百分比| 數值| top| center | bottom。
當只設置一個值的時候,另一個會缺省為 center。
使用關鍵字,將背景圖片水平居中,垂直居中:
background-image:url('/statics/images/course/smiley.gif');
background-repeat:no-repeat;
background-attachment:fixed;
background-position:center;
使用百分比%:
background-image:url('/statics/images/course/smiley.gif');
background-repeat:no-repeat;
background-attachment:fixed;
background-position: 50% 50%;
50% 50% 等同于 center center,顯示效果和上圖一樣。
還可以使用具體數值,比如 px、em、cm等。
background-image:url('/statics/images/course/smiley.gif');
background-repeat:no-repeat;
background-attachment:fixed;
background-position: 50px 50px;
顯示效果如下:
5、背景圖相對于容器的基準點 —— background-origin
就是設置背景圖片相對于html元素什么位置作為初始坐標點,語法:
background-origin: padding-box|border-box|content-box;
幾種值得含義:
padding-box | 背景圖像相對填充框的位置 |
border-box | 背景圖像相對邊界框的位置 |
content-box | 背景圖像相對內容框的位置 |
如下實例:
6、背景圖片大小 —— background-size
默認會顯示背景圖原始尺寸,可以通過此屬性設置背景圖片在元素上的大小,語法:
background-size: width height;
寬度和高度可以使用 數值、百分比%、cover 及 contain ;
數值:可以使用任何單位的數字,比如 px、em、cm等。如果設置一個值,第二個為"auto(自動)"。
百分比%:相對于其所在html原始寬度和高度,如果設置一個值,第二個為"auto(自動)"。
cover:把背景圖像擴展至足夠大,以使背景圖像完全覆蓋背景區域。背景圖像的某些部分也許無法顯示在背景定位區域中。
contain:把背景圖像擴展至最大尺寸,以使其寬度和高度完全適應內容區域。
如下示例:
7、背景圖像是否固定或者隨著頁面的其余部分滾動
background-attachment 屬性有以下幾個值:
scroll | 背景圖片隨頁面的其余部分滾動。這是默認 |
fixed | 背景圖像是固定的 |
inherit | 指定background-attachment的設置應該從父元素繼承 |
local | 背景圖片隨滾動元素滾動 |
如設置一個固定的背景圖片,不跟隨頁面滾動:
background-attachment:fixed;
滾動滾動條,會發下背景圖片始終固定在屏幕那個位置。
8、背景繪制區域 —— background-clip
語法如下:
background-clip: border-box|padding-box|content-box;
border-box | 默認值。背景繪制在邊框方框內(剪切成邊框方框)。 |
padding-box | 背景繪制在襯距方框內(剪切成襯距方框)。 |
content-box | 背景繪制在內容方框內(剪切成內容方框)。 |
這個屬性類似于 background-origin ,只不過它會裁剪背景圖片,如下示例:
9、背景層的混合模式 —— background-blend-mode
所謂混合模式就是將圖片與顏色或圖片與圖片進行混合,語法:
background-blend-mode: normal|multiply|screen|overlay|darken|lighten|color-dodge|saturation|color|luminosity;
屬性值:
示例如下:
正常模式
luminosity 亮度模式
color 顏色模式
其它模式可以自己試試,看下有什么區別。
到此,我們了解了顏色和背景的使用方法,尤其是背景的使用,由于它的屬性很多,可以簡寫也可以分開寫,要想完全掌握,還得多練習,每種屬性進行組合使用看看其效果。
一般建議使用 background 簡寫方式,主要是可以少寫很多代碼。以上介紹難免有誤,或不齊全,歡迎指出錯誤,并補充。
上篇:前端入門——css鏈接樣式
*請認真填寫需求信息,我們會在24小時內與您取得聯系。