1, 資料 函數程式 都定義在 執行個體化對象中
通過調用 執行個體化對象的函數方法
調用 執行個體化對象中 存儲的資料
執行程式 實作效果
2, this指向必須是執行個體化對象
匿名函數 --- 箭頭函數
回調函數 通過 bind() 文法修改設定 this指向
提前定義一個變量 存儲this指向
一個函數中 要是用 多個this指向
提前使用變量儲存不同的this
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
ul,ol,li{
list-style: none;
}
a,a:hover,a:active{
text-decoration: none;
}
img{
width: 100%;
height: 100%;
display: block;
}
.banner{
width: 600px;
height: 400px;
border: 5px solid #000;
position: relative;
margin: 50px auto;
/* overflow: hidden; */
}
.banner>ul{
width: 500%;
height: 100%;
position: absolute;
top:0;
left:0;
}
.banner>ul>li{
float: left;
width: 600px;
height: 400px;
}
.banner>ol{
height: 50px;
position: absolute;
bottom:50px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
}
.banner>ol>li{
width: 20px;
height:20px;
border-radius: 50%;
background: #fff;
margin: 0 15px;
cursor: pointer;
}
.banner>ol>li.active{
background: red;
}
.banner>div{
width: 100%;
height: 50px;
position: absolute;
left:0;
top: 50%;
transform: translateY(-50%);
display: flex;
justify-content: space-between;
align-items: center;
}
.banner>div>a{
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
font-size: 40px;
color: #fff;
}
</style>
</head>
<body>
<!-- 輪播圖div -->
<div class="banner">
<!-- 輪播圖内容 -->
<ul></ul>
<!-- 焦點按鈕 -->
<ol></ol>
<!-- 左右切換按鈕 -->
<div>
<a href="JavaScript:;" name="left"><</a>
<a href="JavaScript:;" name="right">></a>
</div>
</div>
<!-- 導入外部檔案加載move運動函數 -->
<script src="./move.js"></script>
<!-- 導入外部js檔案中的構造函數 -->
<script src="./banner.js"></script>
<script>
// 面向對象輪播圖
// 加載外部js檔案導入其中定義的構造函數
// 定義數組
const bannerArr = [
{id:1 , width:500 , height:333 , size:29.7 , name:'1.jpg'},
{id:2 , width:500 , height:333 , size:19.3 , name:'2.jpg'},
{id:3 , width:500 , height:333 , size:17.1 , name:'3.jpg'},
{id:4 , width:500 , height:333 , size:20.3 , name:'4.jpg'},
{id:5 , width:600 , height:400 , size:320 , name:'5.jpg'},
];
// 擷取 整個父級标簽對象 .banner
const oDivBanner = document.querySelector('.banner');
// 調用執行 構造函數 建立執行個體化對象
// 參數1: 标簽對象名稱
// 參數2: 需要的數組資料
const bannerObj = new CreateBanner( oDivBanner , bannerArr);
console.log( bannerObj );
// 隻需要調用一個入口函數就可以了
bannerObj.init();
</script>
</body>
</html>
banner.js
class CreateBanner{
// 構造器
constructor(element , imgArr){
// 定義屬性 存儲 參數資料
this.ele = element;
this.arr = imgArr;
// 屬性存儲資料
this.ul = element.querySelector('ul');
this.ol = element.querySelector('ol');
// 原始數組單元個數
this.length = imgArr.length ;
// 定義變量 存儲顯示li的索引下标
// 初始值 是 1
this.index = 1;
// 定義變量 存儲資料防止點選過快
this.bool = true;
// 隻定義不指派
this.ulLis ;
this.olLis ;
this.liWidth ;
this.time ;
}
// 定義一個入口函數
// 調用這個函數 函數中調用執行所有需要運作的函數
// 入口函數一般叫 init
init(){
this.setPage();
this.autoLoop();
this.setMouse();
this.setClick();
this.setHide();
}
// 定義函數方法
// 生成頁面
setPage(){
// 定義字元串
let ulStr = '' ;
let olStr = '' ;
// 循環周遊數組
// item 是 數組中存儲的資料對象
this.arr.forEach( (item , key)=>{
// 生成 ul>li 标簽内容
ulStr += `<li><img src="./images/${item.name}"></li>`;
olStr += key === 0 ? `<li class="active" name="focus" num="${key}"></li>` : `<li name="focus" num="${key}"></li>`;
});
// 寫入頁面
this.ul.innerHTML = ulStr;
this.ol.innerHTML = olStr;
// 擷取 所有的 ul>li ol>li
// 給已經定義的屬性指派
this.ulLis = this.ul.querySelectorAll('li');
this.olLis = this.ol.querySelectorAll('li');
// 擷取li标簽寬度指派給已經定義的屬性
this.liWidth = parseInt( window.getComputedStyle(this.ulLis[0]).width ) ;
// 克隆 ul>li 的第一個和最後一個
const cloneFirst = this.ulLis[0].cloneNode(true);
const cloneLast = this.ulLis[this.ulLis.length-1].cloneNode(true);
// 克隆第一個寫入 ul最後
// 克隆最後一個寫入 ul第一個
this.ul.appendChild( cloneFirst );
this.ul.insertBefore( cloneLast , this.ulLis[0] );
// 設定ul标簽寬度
// 原始數組單元個數+2 乘以 一個li寬度
this.ul.style.width = ( this.length + 2 ) * this.liWidth + 'px';
// 将 ul 向左定位一個li寬度
this.ul.style.left = -this.liWidth + 'px';
}
// 自動輪播
autoLoop(){
// 定義定時器
this.time = setInterval( ()=>{
// 變量累加1
this.index++;
// 在運動之前 先切換 焦點按鈕 css樣式
this.focusStyle();
// 調用move運動函數,改變ul定位
// 每次定位的資料是 顯示li索引下标*一個li寬度
// 回調函數的this執行也會改變 一般是 undefined 或者 window
// 使用 bind方法 修改this指向 為 目前this中存儲的指向 也就是 執行個體化對象
move( this.ul , {left:-this.index*this.liWidth} , this.loopEnd.bind(this) );
} , 4000 )
}
// 運動停止的回調函數
loopEnd(){
// 判斷index的數值
// 如果 index的數值是 所有li的最後一個
// index 指派 1
// 運動結束 從最後一個li 瞬間定位到 第二個li
if( this.index === this.length+1 ){
this.index = 1 ;
this.ul.style.left = -this.index*this.liWidth + 'px';
// index 是 0 瞬間定位到 倒數第二個li
}else if( this.index === 0 ){
this.index = this.length ;
this.ul.style.left = -this.index*this.liWidth + 'px';
}
// 當所有的運動結束
// 給 bool變量指派 true 可以再次觸發move()運動函數
this.bool = true ;
}
// 焦點樣式函數
focusStyle(){
// 提前定義一個變量 存儲this指向
const _this = this ;
// 給所有的ol>li清除class,active
this.olLis.forEach(function(item,key){
// item 是 每一個ol>li标簽
item.classList.remove('active');
// 如果 key索引下标 和 index-1 相同 添加class,active
// 使用 _this中 存儲的 指向 作為 調用資料
if( key === _this.index-1 ){
item.classList.add('active');
}
})
// 特殊情況:
// 最後一個ul>li 給 第一個ol>li添加樣式
// 第一個ul>li 給 最後一個 ol>li添加樣式
if( this.index === this.length+1 ){
this.olLis[0].classList.add('active');
}else if( this.index === 0 ){
this.olLis[this.olLis.length-1].classList.add('active');
}
}
// 滑鼠移入移出
setMouse(){
// 移入父級div标簽 清除 定時器
// 移出父級div标簽 調用 自動輪播函數
this.ele.addEventListener('mouseenter' , ()=>{
clearInterval( this.time );
})
this.ele.addEventListener('mouseleave' , ()=>{
this.autoLoop();
})
}
// 點選效果
setClick(){
// 給父級div添加點選事件 通過事件委托添加點選效果
this.ele.addEventListener('click' , e=>{
if( e.target.getAttribute('name') === 'left' ){
// 防止點選過快
if( this.bool ){
this.bool = false;
}else{
return ;
}
// 索引下标--
this.index--;
// 設定焦點樣式
this.focusStyle();
// 通過move運動函數切換顯示li
move( this.ul , { left : -this.index * this.liWidth } , this.loopEnd.bind(this) );
}else if( e.target.getAttribute('name') === 'right' ){
// 防止點選過快
if( this.bool ){
this.bool = false;
}else{
return ;
}
// 索引下标++
this.index++;
// 設定焦點樣式
this.focusStyle();
// 通過move運動函數切換顯示li
move( this.ul , { left : -this.index * this.liWidth } , this.loopEnd.bind(this) );
}else if( e.target.getAttribute('name') === 'focus' ){
// 防止點選過快
if( this.bool ){
this.bool = false;
}else{
return ;
}
// 索引下标指派 點選标簽索引下标+1
this.index = e.target.getAttribute('num')-0 + 1 ;
// 設定焦點樣式
this.focusStyle();
// 通過move運動函數切換顯示li
move( this.ul , { left : -this.index * this.liWidth } , this.loopEnd.bind(this) );
}
})
}
// 浏覽器最小化
setHide(){
document.addEventListener('visibilitychange' , ()=>{
if( document.visibilityState === 'hidden' ){
// 清除定時器,終止輪播圖自動運作
clearInterval(this.time);
}else if( document.visibilityState === 'visible' ){
// 再次調用自動輪播函數
this.autoLoop();
}
})
}
}
move.js
// 參數1: 運動的标簽對象
// 參數2: 對象形式 屬性是要運動的css屬性 屬性值是要運動的css樣式的最終值
// 參數3: 存儲要執行的函數程式 預設值是空函數
function move(element, object, callback = function () { }) {
// 定義一個變量 存儲 參數2 對象中 單元個數
let num = 0;
// 使用 for...in 循環周遊 參數2對象
// 定義的變量 存儲對象的鍵名 也就是 left,top.width,height,opacity...
// 對象[變量] 擷取對象鍵名存儲的鍵值 也就是 最終值 500 300 0.3....
// 目前變量必須要使用 let 關鍵詞來定義
for (let type in object) {
// 每次循環 給 變量累加1 表示對象參數有一個單元
num++;
// 之前的type參數是 現在 for..in循環 type變量
// 之前的最終值是 現在 對象[變量] 擷取的資料
// 擷取運動屬性的初始值
// 如果是 透明度 直接擷取結果 * 100
// 不是 透明度 結果 parseInt() 取整
let startVal = type === 'opacity' ? window.getComputedStyle(element)[type] * 100 : parseInt(window.getComputedStyle(element)[type]);
// 如果 是 透明度 最終值 * 100
// 如果 不是 透明度 最終值就是本身
// 之前的最終值 是 目前 對象參數中,屬性存儲的屬性值
let endVal = type === 'opacity' ? object[type] * 100 : object[type];
// 設定定時器
let time = setInterval(function () {
// 計算步長
let step = (endVal - startVal) / 10;
// 步長取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// 初始值累加步長值
startVal += step;
// 新的初始值 指派給标簽對象的css
// 如果是 透明度 指派 目前累加之後的初始值 除以 100
// 如果不是 透明度 指派 目前累加之後的初始值 拼接 px機關
element.style[type] = type === 'opacity' ? startVal / 100 : startVal + 'px';
// 判斷 如果初始值 等于 最終值
if (startVal === endVal) {
// 清除定時器
clearInterval(time);
// 給 變量 --
num--;
// 當num數值是 0 時
// 表示所有執行的定時器都被清除了
// 也就是所有css運動都執行結束了
if (num === 0) {
// 執行回調函數
callback();
}
}
}, 30)
}
}
注意:
- 将 匿名函數 function(){}/forEach/定時器/事件綁定 修改為 箭頭函數 ()=>{}
- 回調函數 使用 bind方法 設定this指向
this.loopEnd.bind(this)