效果图:

描述说明:
这是一款基于SVG和Segment.js制作的Loading加载按钮特效。
在这个特效中,为了制作线条动画,使用了Segment.js插件。Segment.js是一个可以制作SVG路径片段动画的js库。
要制作出这个特效,首先是要了解线条如何动画。所有的线条必须手动画出来。下面是第一个loading效果的SVG线条。
<svg width="120px" height="120px"> <path class="outer-path" stroke="#fff" d="M 60 60 m 0 -50 a 50 50 0 1 1 0 100 a 50 50 0 1 1 0 -100"></path> <path class="inner-path" stroke="rgba(255, 255, 255, 0.5)" d="M 60 60 m 0 -30 a 30 30 0 1 1 0 60 a 30 30 0 1 1 0 -60"></path> <path class="success-path" stroke="#fff" d="M 60 10 A 50 50 0 0 1 91 21 L 75 45 L 55 75 L 45 65"></path> <path class="error-path" stroke="#fff" d="M 60 10 A 50 50 0 0 1 95 25 L 45 75"></path> <path class="error-path2" stroke="#fff" d="M 60 30 A 30 30 0 0 1 81 81 L 45 45"></path> </svg>
为它添加一些CSS样式:
body {
background:#354458;
}
svg path {
stroke-linecap:round;
stroke-linejoin:round;
stroke-width:4;
fill:none;
}Segment.js 是创建这个loading动画的关键js代码。
var outer = document.querySelector('.outer-path'),
inner = document.querySelector('.inner-path'),
outerSegment = new Segment(outer, 0, 0.1),
innerSegment = new Segment(inner, 0, 0.1);
function outerAnimation() {
outerSegment.draw('15%', '25%', 0.2, {
callback: function() {
outerSegment.draw('75%', '150%', 0.3, {
circular: true,
callback: function() {
outerSegment.draw('70%', '75%', 0.3, {
circular: true,
callback: function() {
outerSegment.draw('100%', '100% + 0.1', 0.4, {
circular: true,
callback: function() {
outerAnimation();
innerAnimation();
}
});
}
});
}
});
}
});
}
function innerAnimation() {
innerSegment.draw('20%', '80%', 0.6, {
callback: function() {
innerSegment.draw('100%', '100% + 0.1', 0.6, {
circular: true
});
}
});
}
outerAnimation();
innerAnimation();通过上面的代码我们已经可以进行loading加载线条动画了。但是我们还没有处理loading成功和失败时的状态。另外如果想添加新的loader该如何做呢?最好的方法是创建一个通用的js库或插件来处理这些问题。下面就是这个通用库的js代码:
function LoadingButton(el, options) {
this.el = el;
this.options = options;
this.init();
}
LoadingButton.prototype = {
// Initialize everything
init: function() {
this.infinite = true;
this.succeed = false;
this.initDOM();
this.initSegments();
this.initEvents();
},
// Create an span element with inner text of the button and insert the corresponding SVG beside it
initDOM: function() {
this.el.innerHTML = '' + this.el.innerHTML + '';
this.span = this.el.querySelector('span');
var div = document.createElement('div');
div.innerHTML = document.querySelector(this.options.svg).innerHTML;
this.svg = div.querySelector('svg');
this.el.appendChild(this.svg);
},
// Initialize the segments for all the paths of the loader itself, and for the success and error animations
initSegments: function() {
for (var i = 0, paths = this.options.paths, len = paths.length; i < len; i++) {
paths[i].el = this.svg.querySelector(paths[i].selector);
paths[i].begin = paths[i].begin ? paths[i].begin : 0;
paths[i].end = paths[i].end ? paths[i].end : 0.1;
paths[i].segment = new Segment(paths[i].el, paths[i].begin, paths[i].end);
}
this.success = this.el.querySelector('.success-path');
this.error = this.el.querySelector('.error-path');
this.error2 = this.el.querySelector('.error-path2');
this.successSegment = new Segment(this.success, 0, 0.1);
this.errorSegment = new Segment(this.error, 0, 0.1);
this.errorSegment2 = new Segment(this.error2, 0, 0.1);
},
// Initialize the click event in loading buttons, that trigger the animation
initEvents: function() {
var self = this;
self.el.addEventListener('click', function() {
self.el.disabled = 'disabled';
classie.add(self.el, 'open-loading');
self.span.innerHTML = 'Sending';
for (var i = 0, paths = self.options.paths, len = paths.length; i < len; i++) {
paths[i].animation.call(self, paths[i].segment);
}
}, false);
},
// Make it fail
triggerFail: function() {
this.infinite = false;
this.succeed = false;
},
// Make it succeed
triggerSuccess: function() {
this.infinite = false;
this.succeed = true;
},
// When each animation cycle is completed, check whether any feedback has triggered and call the feedback
// handler, otherwise it restarts again
completed: function(reset) {
if (this.infinite) {
for (var i = 0, paths = this.options.paths, len = paths.length; i < len; i++) {
if (reset) {
paths[i].segment.draw(0, 0.1);
}
paths[i].animation.call(this, paths[i].segment);
}
} else {
this.handleResponse();
}
},
// Handle the feedback request, and perform the success or error animation
handleResponse: function() {
for (var i = 0, paths = this.options.paths, len = paths.length; i < len; i++) {
paths[i].el.style.visibility = 'hidden';
}
if (this.succeed) {
this.success.style.visibility = 'visible';
this.successAnimation();
} else {
this.error.style.visibility = 'visible';
this.error2.style.visibility = 'visible';
this.errorAnimation();
}
},
// Success animation
successAnimation: function() {
var self = this;
self.successSegment.draw('100% - 50', '100%', 0.4, {
callback: function() {
self.span.innerHTML = 'Succeed';
classie.add(self.el, 'succeed');
setTimeout(function() {
self.reset();
}, 2000);
}
});
},
// Error animation
errorAnimation: function() {
var self = this;
self.errorSegment.draw('100% - 42.5', '100%', 0.4);
self.errorSegment2.draw('100% - 42.5', '100%', 0.4, {
callback: function() {
self.span.innerHTML = 'Failed';
classie.add(self.el, 'failed');
setTimeout(function() {
self.reset();
}, 2000);
}
});
},
// Reset the entire loading button to the initial state
reset: function() {
this.el.removeAttribute('disabled');
classie.remove(this.el, 'open-loading');
this.span.innerHTML = 'Send';
classie.remove(this.el, 'succeed');
classie.remove(this.el, 'failed');
this.resetSegments();
this.infinite = true;
for (var i = 0, paths = this.options.paths, len = paths.length; i < len; i++) {
paths[i].el.style.visibility = 'visible';
}
this.success.style.visibility = 'hidden';
this.error.style.visibility = 'hidden';
this.error2.style.visibility = 'hidden';
},
// Reset the segments to the initial state
resetSegments: function() {
for (var i = 0, paths = this.options.paths, len = paths.length; i < len; i++) {
paths[i].segment.draw(paths[i].begin, paths[i].end);
}
this.successSegment.draw(0, 0.1);
this.errorSegment.draw(0, 0.1);
this.errorSegment2.draw(0, 0.1);
}
};当然还应该为动画添加一些必要的CSS样式,下面使用的是SCSS代码:
// Loading button
.loading-button{
// When loading button is open
&.open-loading{
color: rgba(255, 255, 255, 0.8);
&.infinity{
padding-top: 80px;
}
svg{
display: inline-block;
visibility: visible;
opacity: 1;
transition: 1s opacity;
transform: translateX(-50%);
}
}
// Loading failed
&.failed{
background-color: #EB7260;
}
// Loading succeed
&.succeed{
background-color: #29ABA4;
}
// Remove transition when changing demo position
&.no-transition{
transition: 0s;
*{
transition: 0s;
}
}
// SVG element, centered and hidden initially
svg{
visibility: hidden;
position: absolute;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: 0s;
path{
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 4;
fill: none;
// To hide success and error paths
&.success-path, &.error-path, &.error-path2{
visibility: hidden;
}
}
}
}
// Handle positions
.loading-button {
&.top {
svg{
top: 10px;
}
}
&.bottom {
svg{
bottom: 10px;
}
}
&.left {
svg {
top: 50%;
transform: scale(0.25) translateY(-50%);
transform-origin: 0 0 0;
left: 20px;
}
}
&.right {
svg {
top: 50%;
transform: scale(0.25) translateY(-50%);
transform-origin: 100% 0 0;
left: auto;
right: 20px;
}
}
&.open-loading {
&.left {
padding-left: 60px;
}
&.right {
padding-right: 60px;
}
&.top, &.bottom {
svg{
transition-delay: 0.2s;
}
}
&.circular-loading, &.circle-loading {
&.top {
padding-top: 140px;
}
&.bottom {
padding-bottom: 140px;
}
}
&.infinity-loading {
&.top {
padding-top: 80px;
}
&.bottom {
padding-bottom: 80px;
}
}
}
}如果要使用新的SVG loading加载效果,可以像下面这样将SVG代码放置在一个模板中:
<script type="text/template" id="circle-loading"> <svg width="120px" height="120px"> <circle r="50" cx="60" cy="60" fill="none" stroke="rgba(255, 255, 255, 0.3)"></circle> <circle r="30" cx="60" cy="60" fill="none" stroke="rgba(255, 255, 255, 0.3)"></circle> <path class="outer-path" stroke="#fff" d="M 60 60 m 0 -50 a 50 50 0 1 1 0 100 a 50 50 0 1 1 0 -100"></path> <path class="inner-path" stroke="#fff" d="M 60 60 m 0 -30 a 30 30 0 1 1 0 60 a 30 30 0 1 1 0 -60"></path> <path class="success-path" stroke="#fff" d="M 60 10 A 50 50 0 0 0 16 36 L 45 65 L 55 75 L 75 45"></path> <path class="error-path" stroke="#fff" d="M 60 10 A 50 50 0 0 0 25 95 L 75 45"></path> <path class="error-path2" stroke="#fff" d="M 60 30 A 30 30 0 0 1 81 81 L 45 45"></path> </svg> </script>
然后使用下面的代码来驱动新的loading动画。
function circularLoading() {
var button = document.querySelector('.loading-button'),
options = {
svg: '#circular-loading',
paths: [{
selector: '.outer-path',
animation: outerAnimation
}, {
selector: '.inner-path',
animation: innerAnimation
}]
},
loading = new LoadingButton(button, options);
function outerAnimation(segment) {
var self = this;
segment.draw('15%', '25%', 0.2, {
callback: function() {
segment.draw('75%', '150%', 0.3, {
circular: true,
callback: function() {
segment.draw('70%', '75%', 0.3, {
circular: true,
callback: function() {
segment.draw('100%', '100% + 0.1', 0.4, {
circular: true,
callback: function() {
self.completed(true);
}
});
}
});
}
});
}
});
}
function innerAnimation(segment) {
segment.draw('20%', '80%', 0.6, {
callback: function() {
segment.draw('100%', '100% + 0.1', 0.6, {
circular: true
});
}
});
}
return loading;
}转载请注明来源地址:小川编程 » https://www.youhutong.com/index.php/article/index/576.html
1、本站发布的内容仅限用于学习和研究目的.请勿用于商业或非法用途,下载后请24小时内删除。
2、本站所有内容均不能保证其完整性,不能接受请勿购买或下载,如需完整程序,请去其官方购买正版使用
3、本站联系方式Email:admin@youhutong.com ,收到邮件会第一时间处理。
4、如侵犯到任何版权问题,请立即告知本站(立即在线告知),本站将及时删除并致以最深的歉意

