글자가 하나하나 typing 되는 효과를 구현하기 위해서 3가지 과정을 생각을 해봤다.
- 앞으로 text가 채워진다
- 잠시 멈춘다
- 잠시 멈춘 뒤에 다시 text가 지워진다
단순 반복문을 사용하게되면 typing하는 효과처럼 보이지 않고 text가 한번에 나왔다가 줄었다가처럼 보일 것 같아서 interval 함수를 이용해서 약간의 간격을 주면서 하나씩 추가해야 typing 하는 효과가 주어질 것 같았다.
그래서 다음과 같이 작성을 했다.
const secondText = select('.second-text');
// text를 앞에서 부터 붙여 나간다.
function moveForward(text) {
let textIndex = 0;
return setInterval(() => {
if (textIndex >= text.length) return;
secondText.innerText += text[textIndex++];
}, 200);
}
// 현재 정해진 text를 지워 나간다
function moveBack() {
return setInterval(() => {
if (secondText.innerText.length < 0) return;
secondText.innerText = secondText.innerText.slice(0, -1);
}, 200);
}
// 끝이 나면 다음 텍스트에 대해서 해당 기능들을 수행한다
function changeText() {
const texts = ['개발자', '꿈나무', '칠칠맞조'];
let curIndex = 0;
// 시작 : toFlag == fales, 끝 플래그 : toFlag === true
return () => {
let backTimeout = null;
let forwardTimeout = null;
setInterval(() => {
// 특정 초 안에 아래 동작을 완수한다.
if (backTimeout) clearInterval(backTimeout);
if (forwardTimeout) clearInterval(forwardTimeout);
console.log('here');
forwardTimeout = moveForward(texts[curIndex++]);
curIndex %= texts.length;
setTimeout(() => {
backTimeout = moveBack();
}, 1000);
}, 2000);
};
}
changeText()();
function select(selector) {
return document.querySelector(selector);
}
처음에는 잘 작동하는 것처럼 보였지만 시간이 지난 후에 아래처럼 변하였다.
아마도 에러의 원인을 브라우저가 동작하면서 interval과 timeout 함수가 쌓이면서 그것들의 충돌로 인해서 제대로 출력이 안된다.
-> 처음에 좀 빡빡하게 typing 속도와 delay를 줬었는데 그 부분을 조금 더 변경을 해도 같은 문제가 발생하였다. 항상 켜놓으면 정상적으로 작동한다. 더 적은 시간이어도 다시보면 문제가 발생해있었다.
브라우저가 백그라운드에서 작동하면서 타이머 함수들을 조작하는게 아닌가 생각이 들어서 그 부분이 문제일 것 같다.
그래서 setTimeout과 setInterval에 대한 것을 조금 더 동기적으로 다루기 위해서 async, await을 도입을 하였다.
현재까지는 같은 증상을 보이고 있지 않아서... 아마도 수정에 성공한 것 같은데 나중에 시간을 내서 다시 한번 보면 좋을 것 같다.
const secondText = select('.second-text');
function wait(time) {
return new Promise((res) =>
setTimeout(() => {
res();
}, time),
);
}
function moveForward(speed, delay) {
return (element) => async (text) => {
let textIndex = 0;
const size = text.length;
while (textIndex < size) {
element.innerText += text[textIndex++];
await wait(speed);
}
await wait(delay);
moveBack(speed)(element);
};
}
function moveBack(speed) {
return async (element) => {
while (element.innerText) {
element.innerText = element.innerText.slice(0, -1);
await wait(speed);
}
};
}
const texts = ['개발자', '꿈나무', '칠칠맞조'];
let curIndex = 0;
const delay1000 = moveForward(100, 1000);
delay1000(secondText)(texts[curIndex++]);
curIndex %= texts.length;
setInterval(() => {
delay1000(secondText)(texts[curIndex++]);
curIndex %= texts.length;
}, 3000);
function select(selector) {
return document.querySelector(selector);
}