漸現 Banner,也是輪播圖的一種。現在我們用 Vue.js 組件封裝它,而且是 TypeScipt 語法的。本組件不依賴其他庫或者函數。
用法如下:
<html>
<head>
<meta charset="utf-8" />
<title>DEMO</title>
<style type="text/css">
/* AJAXJS Base CSS */
body,dl,dt,dd,ul,li,pre,form,fieldset,input,p,blockquote,th,td,h1,h2,h3,h4,h5{margin:0;padding:0;}
h1,h2,h3,h4,h5{font-weight: normal;}img{border:0;}ul li{list-style-type:none}.hide{display:none}
body {-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing: grayscale;
font-family: "Lantinghei SC", "Open Sans", Arial, "Hiragino Sans GB", "Microsoft YaHei", "微軟雅黑", "STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif;}
a{text-decoration:none;color:#666;transition:color .4s ease-in-out;}
a:hover{color:#000;}
button{border:none;outline:0;cursor:pointer;letter-spacing:2px;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none}
input[type=password],input[type=text],select,textarea{outline:0;-moz-appearance:none;}
/* 手機端瀏覽器所顯示的網頁 CSS */
@media screen and (max-width:480px) {
* {
-webkit-tap-highlight-color: transparent; /* 很多 Android 瀏覽器的 a 鏈接有邊框,這裏取消它 */
-webkit-touch-callout: none; /* 在 iOS 瀏覽器裏面,假如用戶長按 a 標籤,都會出現默認的彈出菜單事件 */
/* -webkit-user-select:none; */
}
}
</style>
<link rel="stylesheet" type="text/css" href="../common/main.css" />
<script src="https://lib.baomitu.com/vue/2.6.11/vue.js"></script>
<script src="../../dist/carousel/opacity-banner.js"></script>
</head>
<body>
<div class="opacity-banner">
<aj-opacity-banner>
<li>
<a href="#"> <img src="images/1.jpg" /></a>
</li>
<li>
<a href="#"> <img src="images/2.jpg" /></a>
</li>
<li>
<a href="#"> <img src="images/3.jpg" /></a>
</li>
</aj-opacity-banner>
</div>
<script type="text/javascript">
new Vue({
el: '.opacity-banner'
});
</script>
</body>
</html>
<aj-opacity-banner>
包裹着的是含有圖片的 <li></li>
標籤。圖片是 100% 寬度自適應的,見下面所用到的樣式(基於 less.js)
.aj-opacity-banner{
position: relative;
li{
position:absolute;
top:0;
left:0;
opacity:0;
width: 100%;
}
img{
width: 100%;
}
}
組件的屬性如下。
屬性 | 含義 | 類型 | 是否必填 | 默認值 |
---|---|---|---|---|
delay | 延時 | Number | n | 3000 |
fps | 幀速 | Number | n | 25 |
用法如下:
<aj-opacity-banner delay="2000">
……
</aj-opacity-banner>
TypeScript 源碼如下:
/**
* 漸顯 banner
* 注意:定時器保存在 DOM 元素的屬性上,是否會內存泄漏呢?
*/
; (() => {
interface OpacityBanner extends Vue {
active: number;
timer: number;
delay: number;
fps: number;
/**
* 各幀
*/
list: NodeListOf<HTMLLIElement>;
states: [];
/**
* 內容淡出
*/
clear(): void;
animate(params: number): void;
run(): void;
}
Vue.component('aj-opacity-banner', {
template: '<ul class="aj-opacity-banner"><slot></slot></ul>',
props: {
delay: { default: 3000 }, // 延時
fps: { default: 25 } // 幀速
},
data() {
return {
active: 0, // 當前索引
}
},
mounted(this: OpacityBanner): void {
this.list = this.$el.querySelectorAll('li');
this.list[0].style.opacity = "1";
console.log(this.list.length);
this.run();
},
methods: {
/**
* 播放動畫
*
* @param this
*/
run(this: OpacityBanner): void {
this.timer = window.setInterval(() => {
var active: number = this.active;
this.clear();
active += 1;
this.active = active % this.list.length;
this.animate(100);
}, this.delay);
},
/**
* 下一幀
*
* @param this
*/
per(this: OpacityBanner): void {
var active = this.active;
this.clear();
active -= 1;
active = active % this.list.length;
if (active < 0)
active = this.list.length - 1;
this.active = active;
this.animate(100);
},
/**
* 內容淡出
*/
clear(this: OpacityBanner): void {
this.animate(0);
},
/**
*
* @param this
* @param params
*/
animate(this: OpacityBanner, params: number): void {
var el: HTMLLIElement = this.list[this.active], fps: number = 1000 / this.fps;
window.clearTimeout(el.timer);
window.setTimeout(function loop() {
var i: number = getOpacity(el);
var speed: number = (params - i) / 8, speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// console.log("i=" + i + "; speed="+ speed+"; s="+s+"; k="+k);
i += speed;
el.style.opacity = String(i / 100);
window.clearTimeout(el.timer);
// params.complete && params.complete.call(elem);
el.timer = window.setTimeout(loop, fps);
}, fps);
}
}
});
/**
* 獲取元首的透明度
*
* @param el
*/
function getOpacity(el: Element): number {
var v: number = Number(getComputedStyle(el)["opacity"]);
v *= 100;
return parseFloat(v + "") || 0;
}
})();
原理上講,就是爲每張圖片準備好定時器 timer,使其控制圖片的透明度。當圖片從透明度 0 到 100,就是漸現的過程;與此同時,另外一張圖片由透明度 100 下降到 0。這兩個過程是同時發生的,一個漸現一個漸隱,便會造成如此的目標效果。