又到了一年一度躁動不安的季節,跳槽升職加薪當然需要一份很nice的簡歷啦,作為一位在本圈剛出道的前端小白,當然需要一份很nice的簡歷啦!
圖片展示
設計粗糙,原諒一個理科生(理科都還沒學好)的審美
介紹頁
技能清單頁
經歷頁
作品頁
聯絡方式頁
核心動畫延遲函式
js檔案目錄
│ jqExt.js // 擴充套件一些jq外掛
│ main.js // 主函式
│ pageFirst.js // 第一屏動畫
│ pageSecond.js // 第二屏動畫
│ pageThird.js // 第三屏動畫
│ pageFourth.js // 第四屏動畫
| pageFifth.js // 第五屏動畫
│ startAni.js // 頁面初始化動畫
│ utils.js // 工具函式
複製程式碼
核心延遲函式
網站一共分為五屏,每翻到一屏都會執行當前頁面的動畫,由於動畫為延遲逐個進行的方式,一開始非常簡單粗暴的使用setTimeout巢狀,醬紫:
setTimeout(() => {
/* 需要執行的動畫內容 */
setTimeout(() => {
/* 需要執行的動畫內容 */
setTimeout(() => {
/* 需要執行的動畫內容 */
}, delay);
}, delay);
}, delay);
複製程式碼
臭名遠揚的回撥函式,其實我是沒問題的,可是我們得考慮到開源呀,這整出去不是打自個臉嗎,所以自個封裝了一個非常簡易還有點low的延遲庫,醬紫:
class Timeout {
constructor() {
this.timer = null; // 定時器
this.fns = []; // 儲存所有運動函式
this.index = 0; // 索引
}
to(fn = () => { }, time = 0) {
// 儲存所有執行函式以及對應的延遲時間
this.fns.push({
fn,
time
});
return this;
}
start() {
const _this = this;
/* 通過索引判斷當前動畫是否執行完畢,不需要繼續執行 */
if (_this.index === _this.fns.length) return;
// 清除定時器
_this.pause();
_this.timer = setTimeout(() => {
//執行當前階段函式
requestAnimationFrame(_this.fns[_this.index].fn);
// 索引+1
_this.index++;
if (_this.index === _this.fns.length) _this.pause();
else _this.start();
// 時間遞增
}, _this.fns[_this.index].time);
}
// 暫停
pause() {
clearTimeout(this.timer);
}
};
複製程式碼
呼叫方式如下:
const t = new Timeout();
t.to(() => {
/* 動畫函式 */
}, delay)
.to(() => {
/* 動畫函式 */
}, delay)
......
// 執行當前動畫組
t.start();
複製程式碼
這就好多了
每個屏最終都會匯出當前屏動畫的開始和暫停開關
module.exports = {
start() {
t.start();
/* 當前屏其他動畫開始函式 */
},
pause() {
t.pause();
/* 當前屏其他動畫暫停函式 */
}
};
複製程式碼
當頁面滾動到當前屏,執行start開始方法,離開之後執行pause暫停,尤其是需要canvas和setInterval的屏,暫停能節約效能開銷呢
首屏隨機行駛的小車原理
預覽
首先準備若干量小車div,蜷縮在螢幕外邊隨時準備待命,開一個定時器,隨機抓出一輛小車放生共有三個要素決定小車的運動形式(行駛方向、上下位置、運動速度)
行駛方向
車從左到右行駛 或 從右到左行駛
.car {
// 小車向右邊行駛
&.left {
animation-name: moveL;
@keyframes moveL {
0% {
transform: translateX(-300px) rotateY(0);
} 100% {
transform: translateX(140vw) rotateY(0);
}
}
}
// 小車向左邊行駛
&.right {
animation-name: moveR;
@keyframes moveR {
0% {
transform: translateX(140vw) rotateY(180deg);
} 100% {
transform: translateX(-300px) rotateY(180deg);
}
}
}
// 滑鼠移動到小車上停止
&:hover {
animation-play-state: paused;
}
}
複製程式碼
上下位置
列舉出所有小車可能出現的最佳位置,方便js隨機動態生成class
.car {
/* 列舉出左右車道小車位置,方便js隨機動態生成class */
// 左車道
&.bl1 {
bottom: 91%;
z-index: 8;
}
&.bl2 {
bottom: 92%;
z-index: 7;
}
// ......
// 右車道
&.br1 {
bottom: 71%;
z-index: 18;
}
&.br2 {
bottom: 72%;
z-index: 17;
}
// ......
}
複製程式碼
行駛時間
.car {
// 時間
&.t1 {
animation-duration: 1s;
}
&.t2 {
animation-duration: 2s;
}
// ......
}
複製程式碼
核心js程式碼如下:
// 需要用到的運動類
const moveStyle = {
dir: ['left', 'right'],
time: ['t1', 't2', 't3', 't4', 't5', 't6', 't7', 't8'],
pos: [['bl1', 'bl2', 'bl3', 'bl4', 'bl5', 'bl6', 'bl7', 'bl8'], ['br1', 'br2', 'br3', 'br4', 'br5', 'br6', 'br7', 'br8']]
}
const move = () => {
/* moveArr為需要運動的小車集合 */
/* 隨機取出一輛小車 len為小車個數 */
moveObj = moveArr[Math.floor(Math.random() * len)];
// 選出一輛不處於運動狀態的小車
while (moveObj.prop('isAnimated')) {
moveObj = moveArr[Math.floor(Math.random() * len)];
};
// 將即將運動的小車的加上運動標識
moveObj.prop('isAnimated', true);
/* 這裡來一個55開,決定當前小車行駛方向 */
const dirNum = Math.round(Math.random()); // 0或1
// 生成運動類名
const className = `${moveStyle.dir[dirNum]} ${moveStyle.time[Math.ceil(Math.random() * 8)]} ${moveStyle.pos[dirNum][Math.ceil(Math.random() * 7)]}`;
// 給小車加上class,並將類名儲存到自定義資料中,方便後期清空
moveObj.addClass(className).prop('csName', className);
// 每隔四秒走一次
timer = setTimeout(() => {
requestAnimationFrame(move);
}, 4000);
}
複製程式碼
當然,我們需要監聽當前小車車是否運動完畢,以此來取消它的運動狀態,所以需要搞一個監聽:
// 當animate完成,會觸發當前事件
car.bind("animationEnd webkitAnimationEnd", animateComplete);
function animateComplete() {
// 清空剛剛隨機生成的class運動類,並且將當前的運動狀態設定為false
$(this).removeClass($(this).prop('csName')).prop('isAnimated', false);
};
複製程式碼
ok,差不多完成了,但是還有一個很重要的效能問題,假如瀏覽者離開了當前螢幕,我們就需要清空當前小車的運動定時器,最終我們依然匯出了一個start(開始)和pause(暫停)函式
return {
// 小車開始運動
start: move,
pause() {
// 清除小車的定時器
clearTimeout(timer);
// 遍歷所有小車,清空他們的運動狀態
cars.each(moveEl => {
// 把運動中的車全部清除
if ($(moveEl).prop('isAnimated')) $(moveEl).removeClass($(moveEl).prop('csName')).prop('isAnimated', false);
});
}
};
// 然後放到對應的頁面中去
// 比如首屏最終的匯出函式就成了醬紫:
module.exports = {
start() {
t.start();
/* 小車開始 */
carAniFn.start();
},
pause() {
t.pause();
/* 離開當前屏,小車暫停 */
carAniFn.pause();
}
};
複製程式碼
頁面切換效果
所有頁面都包裝在一個div裡面,通過切換css類名來實現上下運動,css如下
/* vh是css3的一個相對單位,100vh相當於瀏覽器可視區域的高度 */
#swiper-box {
.ts(.4s linear);
&.page0 {
.tf(translateY(0));
}
&.page1 {
.tf(translateY(-100vh));
}
&.page2 {
.tf(translateY(-200vh));
}
&.page3 {
.tf(translateY(-300vh));
}
&.page4 {
.tf(translateY(-400vh));
}
}
複製程式碼
監聽滑鼠滾輪,在這裡需要注意下chrome和firefox滾動方向需要做一下相容:
/* 擴充套件jq函式 */
$.fn.extend({
onscroll(fn) {
let dir = null;
let gg, ff;
$(this).bind('mousewheel || DOMMouseScroll', function (e) {
gg = e.originalEvent.wheelDelta;
ff = e.originalEvent.detail;
dir = gg ? (gg < 0 ? true : false) : (ff < 0 ? false : true);
fn && fn(dir, e);
});
return $(this);
}
});
複製程式碼
給需要滾動的父級元素加上滑鼠滾輪事件
swiperBox.onscroll(function (dir) {
/**/
if (dir) index++;
else index--;
// 判斷index是否超出範圍,len為螢幕個數
if (index >= len) index = 0;
if (index < 0) index = len - 1;
if (index === prev) return;
// 暫停上一屏的動畫
arr[prev].pause();
// 3d導航切換效果
navA.eq(prev).removeClass('hover');
navA.eq(index).addClass('hover');
// 給父級加上已經寫好的class類名
swiperBox[0].className = 'page' + index;
});
複製程式碼
當滾動到當前屏之後,需要執行當前屏的動畫,在這裡我們監聽父級頁面是否運動完成,運動完成之後就按需載入當前頁面對應的動畫:
/* 將對應的頁面儲存到陣列當中,用於判斷是否已經require過 */
const partArr = [];
swiperBox.bind('transitionend webkitTransitionend', function (e) {
/* 考慮到子元素會重複觸發當前事件,判斷下子 */
if (e.target === this) {
if (!partArr[index]) partArr[index] = requirePart(index); // 如果沒有匯入,進行匯入
prev = index; // 記錄上一屏
partArr[index].start(); // 執行當前屏的動畫
}
});
// 用於匯入各個頁面的函式
function requirePart(index) {
switch (index) {
case 0:
return require('./pageFirst');
case 1:
return require('./pageSecond');
case 2:
return require('./pageThird');
case 3:
return require('./pageFourth');
case 4:
return require('./pageFifth');
}
}
複製程式碼
總結
由於技術原因頁面可能存在諸多潛在問題,歡迎感興趣的大佬可以通過簡歷的聯絡方式來指導下我,最後再不要臉的附上地址: