HTML, CSS, JS로 전자상거래 웹사이트를 만드는 방법 - 02

HTML, CSS, JS로 전자상거래 웹사이트를 만드는 방법 - 02

안녕, 잘 지내길 바래. 오늘은 풀스택 e-com 웹 사이트 시리즈의 두 번째 부분에 대해 알아보겠습니다. 이 부분에서는 노드 서버를 만들어 localhost에서 웹 사이트를 실행한 다음 양식 유효성 검사 및 사용자 저장 방법을 배우게 됩니다. 이 비디오에서는 전체적으로 등록 페이지/로그인 페이지, 로그아웃 기능 및 판매자 대시보드를 만듭니다.

이전 부분을 보지 않았다면요. 지금 보세요

데모를 보거나 이해를 돕기 위해 전체 코딩 튜토리얼 비디오를 원합니다. 아래 튜토리얼을 볼 수 있습니다.

비디오 튜토리얼

코드

아래는 저희 프로젝트의 폴더 구조입니다. 우리는 전편에 있던 것과 비교해 새로운 파일 몇 개를 가지고 있다.

이미지 다운로드, 소스 코드 가져오기

그럼 코드쓰기를 시작하겠습니다.

NPM Init

서버부터 시작하여 터미널 또는 cmd 프롬프트에서 이전 코드 폴더를 엽니다. 그리고 npm init을 실행합니다. 이렇게 하면 프로젝트에 대한 NPM이 초기화됩니다. 그런 다음 이 명령을 실행하여 일부 패키지를 설치합니다.

npm i express.js nodemon firebase-admin bcrypt

설치가 완료되면, 꾸러미가 보일 겁니다.전화번호부에 json을 입력하세요. 파일 및 스크립트 개체의 변경 사항을 엽니다.

"scripts": { "start": "nodemon server.js" }

이렇게 하면 NPM과 함께 사용할 수 있는 시작 명령이 생성됩니다. server.js 파일을 만들지 않은 경우. 하나 만들어. 서버를 만들어 봅시다.

서버

server.js 파일을 엽니다. 먼저 방금 설치한 패키지를 가져오십시오.

// importing packages const express = require('express'); const admin = require('firebase-admin'); const bcrypt = require('bcrypt'); const path = require('path');

// declare static path let staticPath = path.join(__dirname, "public");

공용 폴더의 경로를 정적 경로로 만듭니다. 정적 경로란? 정적 경로는 서버에서 파일을 찾아야 하는 위치를 알려주는 경로일 뿐입니다.

//intializing express.js const app = express(); //middlewares app.use(express.static(staticPath)); app.listen(3000, () => { console.log('listening on port 3000.......'); })

위의 코드에서 나는 고속 서버를 만들고 포트 3000의 요청을 수신하고 있다.

/ , /404개의 경로를 만듭니다.

//routes //home route app.get("/", (req, res) => { res.sendFile(path.join(staticPath, "index.html")); })

터미널에서 npm start를 실행하여 지금 서버를 시작하십시오. 페이지를 보려면 크롬에서 localhost:3000을 엽니다. 서버가 작동 중인 경우 index.html 페이지가 나타납니다.

404번 노선입니다. 미들웨어를 쓰겠습니다. 서버 맨 아래에 이 중간 제품을 추가해야 합니다. 그렇지 않으면 정의된 경로에 있더라도 404 페이지가 표시됩니다.

// 404 route app.get('/404', (req, res) => { res.sendFile(path.join(staticPath, "404.html")); }) app.use((req, res) => { res.redirect('/404'); })

제가 404 페이지를 따로 만들어서 알 수 없는 경로로 요청을 할 때 사용자를 리디렉션한 것을 알 수 있습니다. 내가 왜 그랬지? 제가 그렇게 한 이유는 404페이지를 미들웨어로 전달하면 됩니다. 분명히 페이지를 가져오겠지만, 중첩된 경로로 가면 스타일이 없는 페이지를 가져오게 될 거예요. 아래 그림을 참조하십시오.

현재 서버 작업은 거의 완료되었으므로 등록 페이지를 전송하기 위한 /등록 경로만 생성하면 됩니다.

//signup route app.get('/signup', (req, res) => { res.sendFile(path.join(staticPath, "signup.html")); })

등록 페이지

signup.html 파일을 엽니다. HTML5 템플릿부터 시작합니다. 적절한 제목과 링크 양식.css 파일을 지정합니다.

먼저 페이지에 대한 로더를 만듭니다.

*{ margin: 0; padding: 0; box-sizing: border-box; } body{ width: 100%; min-height: 100vh; display: flex; justify-content: center; align-items: center; background: #f5f5f5; font-family: 'roboto', sans-serif; } .loader{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100px; }

이제 양식을 만드세요.

agree to our terms and conditions recieve upcoming offers and events mails create account already have an account? Log in here

위의 코드를 보시면 양식 태그 대신 div를 사용하고 있습니다. 왜죠? 왜냐하면 HTML 양식을 사용하면 서버에 POST 요청을 보낼 수 있지만 응답을 잡을 수 없기 때문에 성공 여부를 확인하기 위해 서버에서 응답을 받고자 합니다.

.logo{ height: 80px; display: block; margin: 0 auto 50px; } input[type="text"], input[type="password"], input[type="email"], textarea{ display: block; width: 300px; height: 40px; padding: 20px; border-radius: 5px; background: #fff; border: none; outline: none; margin: 20px 0; text-transform: capitalize; color: #383838; font-size: 14px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.01); font-family: 'roboto', sans-serif; } ::placeholder{ color: #383838; } .submit-btn{ width: 300px; height: 40px; text-align: center; line-height: 40px; background: #383838; color: #fff; border-radius: 2px; text-transform: capitalize; border: none; cursor: pointer; display: block; margin: 30px 0; } /* checkbox styles */ .checkbox{ -webkit-appearance: none; position: relative; width: 15px; height: 15px; border-radius: 2px; background: #fff; border: 1px solid #383838; cursor: pointer; } .checkbox:checked{ background: #383838; } .checkbox::after{ content: ''; position: absolute; top: 60%; left: 50%; transform: translate(-50%, -50%); width: 80%; height: 100%; pointer-events: none; background-image: url(../img/check.png); background-size: contain; background-repeat: no-repeat; display: none; } .checkbox:checked::after{ display: block; } label{ text-transform: capitalize; display: inline-block; margin-bottom: 10px; font-size: 14px; color: #383838; } label a{ color: #383838; } .link{ color: #383838; text-transform: capitalize; text-align: center; display: block; }

위에는 많은 CSS가 있다, 그렇지 않은가? 위의 CSS 속성을 모르면 언제든지 코멘트로 물어보십시오.

이제, 경고 상자를 만드세요.

Error message

/* alert */ .alert-box{ width: 300px; min-height: 150px; background: #fff; border-radius: 10px; box-shadow: 0 5px 100px rgba(0, 0, 0, 0.05); position: absolute; top: 60%; left: 50%; transform: translate(-50%, -50%); padding: 20px; opacity: 0; pointer-events: none; transition: 1s; } .alert-box.show{ opacity: 1; pointer-events: all; top: 50%; } .alert-img{ display: block; margin: 10px auto 20px; height: 60px; } .alert-msg{ color: #e24c4b; font-size: 20px; text-transform: capitalize; text-align: center; line-height: 30px; font-weight: 500; }

좋아요! 가입 페이지가 끝났습니다. 이제 제대로 작동하게 해봅시다. 양식.js를 등록.html 페이지에 추가합니다.

폼.js

필요한 모든 요소를 선택합니다.

const loader = document.querySelector('.loader'); // select inputs const submitBtn = document.querySelector('.submit-btn'); const name = document.querySelector('#name'); const email = document.querySelector('#email'); const password = document.querySelector('#password'); const number = document.querySelector('#number'); const tac = document.querySelector('#terms-and-cond'); const notification = document.querySelector('#notification');

모든 요소를 선택한 후 클릭 이벤트를 추가하여 Btn을 제출하고 다른 경우 를 사용하여 양식을 검증합니다.

submitBtn.addEventListener('click', () => { if(name.value.length < 3){ showAlert('name must be 3 letters long'); } else if(!email.value.length){ showAlert('enter your email'); } else if(password.value.length < 8){ showAlert('password should be 8 letters long'); } else if(!number.value.length){ showAlert('enter your phone number'); } else if(!Number(number.value) || number.value.length < 10){ showAlert('invalid number, please enter valid one'); } else if(!tac.checked){ showAlert('you must agree to our terms and conditions'); } else{ // submit form } })

위의 코드에서는 검증 작업을 어떻게 수행하고 있습니까? 음, 기본적으로 이것이 참이면 다음 코드를 실행하고, 그렇지 않으면 다른 코드를 실행합니다.

이름 확인을 이해합시다.

if(name.value.length < 3){ showAlert('name must be 3 letters long'); }

는 (조건 )에 기록된 조건을 확인합니다.

name은 파일 상단에 우리가 선언한 우리의 이름 요소입니다.

value - 이름은 입력 필드이므로. 값이 있어야 합니다. 물론 비어 있을 수도 있습니다. name.value는 입력 필드의 값을 반환하는 것입니다.

길이는 문자열 안에 있는 문자 수 또는 배열 안에 있는 요소 수를 세는 데 사용됩니다. 기본적으로 name.value.length를 사용하여 당연히 정수인 이름의 값 길이를 확인합니다.

일단 숫자인 길이를 구하면, 3보다 작은지 아닌지 확인해 보세요.

그래서 만약 조건이 참이라면, JS는 if 블록 안에 쓰여진 코드를 실행할 것입니다, 그것은

showAlert('name must be 3 letters long');

이것이 우리가 다른 분야에서도 검증하는 방법입니다.

그래서 지금 showAlert(msg) 함수를 만들어야 합니다.

// alert function const showAlert = (msg) => { let alertBox = document.querySelector('.alert-box'); let alertMsg = document.querySelector('.alert-msg'); alertMsg.innerHTML = msg; alertBox.classList.add('show'); setTimeout(() => { alertBox.classList.remove('show'); }, 3000); }

위의 기능에서 먼저 경고 상자 관련 요소를 선택합니다. 그 후 msg 파라미터를 inner로 설정하고 있습니다.alertMsg의 HTML, 물론 alert-box의 p 요소이다. 그런 다음 show 클래스를 alertBox에 추가합니다. 그리고 setTimeout을 사용하여 3000ms 또는 3초 후에 쇼 클래스를 제거합니다.

등록 확인은 완료되었으니 지금 양식을 제출해 보겠습니다. 양식을 제출하려면 경로와 데이터를 인수로 사용할 다른 함수를 만드십시오. 그러면 등록 페이지와 로그인 페이지 모두에 이 기능을 사용할 수 있기 때문에 별도의 기능을 만들 필요가 없습니다.

// send data function const sendData = (path, data) => { fetch(path, { method: 'post', headers: new Headers({'Content-Type': 'application/json'}), body: JSON.stringify(data) }).then((res) => res.json()) .then(response => { processData(response); }) }

그래서 위의 코드에서는 간단한 가져오기 방법을 사용하여 요청을 하고 있습니다. 기본적으로 가져오기 템플릿입니다. 프로세스데이터 기능은 나중에 만들겠습니다.

지금 양식 데이터를 백엔드로 보냅니다.

else{ // submit form loader.style.display = 'block'; sendData('/signup', { name: name.value, email: email.value, password: password.value, number: number.value, tac: tac.checked, notification: notification.checked, seller: false }) }

양식 제출을 처리하기 위해 server.js 내부에 등록 경로를 작성합니다.

등록 - POST

경로를 만들기 전에 맨 위에 이 라인을 추가합니다. 양식 공유를 사용합니다. 그렇지 않으면 양식 데이터를 받을 수 없습니다.

app.use(express.json());

app.post('/signup', (req, res) => { let { name, email, password, number, tac, notification } = req.body; // form validations if(name.length < 3){ return res.json({'alert': 'name must be 3 letters long'}); } else if(!email.length){ return res.json({'alert': 'enter your email'}); } else if(password.length < 8){ return res.json({'alert': 'password should be 8 letters long'}); } else if(!number.length){ return res.json({'alert': 'enter your phone number'}); } else if(!Number(number) || number.length < 10){ return res.json({'alert': 'invalid number, please enter valid one'}); } else if(!tac){ return res.json({'alert': 'you must agree to our terms and conditions'}); } })

여기서 먼저 요청에서 데이터를 추출합니다. 그래서 우리는 프런트 엔드에서 양식 데이터를 보내고 있다. 백엔드에서도 동일한 이름을 사용하고 있는 것을 볼 수 있습니다.

let { name, email, password, number, tac, notification } = req.body;

그리고 나서, 저는 형식 검증을 수행하고 있습니다. 물론 프런트 엔드에서 실시했지만, 프런트 엔드는 쉽게 통과될 수 있기 때문에 백 엔드에 대해서도 검증을 하는 것이 좋습니다.

if(name.length < 3){ return res.json({'alert': 'name must be 3 letters long'}); } else if .....

여기서는 값을 사용하지 않습니다. 여기 이름은 입력이 아닙니다. 앞끝에서 얻은 문자열입니다. 그리고 답장으로 JSON 데이터를 보냅니다. 이렇게 생겼죠.

JSON = { 'key': 'value' }

JS 개체와 유사하지만 웹을 통해 데이터를 전송하는 데 사용됩니다.

좋습니다. 이제 JSON 데이터를 처리하세요.

const processData = (data) => { loader.style.display = null; if(data.alert){ showAlert(data.alert); } }

물론 먼저 로더를 숨깁니다. 그런 다음 수신된 데이터에 경보 키가 포함되어 있는지 여부를 확인합니다. 포함된 경우 showAlert 기능을 사용하여 사용자에게 경고합니다. 간단하지 않아요?

이제 사용자를 데이터베이스 또는 파이어스토어에 저장해 보겠습니다.

화재 저장소에 사용자 저장

코드를 더 작성하기 전에 파이어베이스 프로젝트를 수행하고 대시보드에서 비밀 키 파일을 다운로드해야 합니다. 이 정보를 참조하여 키를 다운로드할 수 있습니다.

일단 키 파일을 얻으면. 공용 폴더 외부의 프로젝트 폴더로 이동합니다.

그런 다음 server.js 내부의 화재기지를 시작합니다.

// firebase admin setup let serviceAccount = require("path of key file"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); let db = admin.firestore();

파이어베이스 초기화 후 내부 등록 POST 경로. 유효성 검사 후 사용자를 데이터베이스에 저장합니다.

// store user in db db.collection('users').doc(email).get() .then(user => { if(user.exists){ return res.json({'alert': 'email already exists'}); } else{ // encrypt the password before storing it. bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(password, salt, (err, hash) => { req.body.password = hash; db.collection('users').doc(email).set(req.body) .then(data => { res.json({ name: req.body.name, email: req.body.email, seller: req.body.seller, }) }) }) }) } })

파이어베이스에는 동일한 데이터 그룹을 저장하는 컬렉션이 있습니다. 이 경우 사용자 컬렉션을 firstore에 가지고 있습니다. db.collection은 컬렉션에 액세스하는 데 사용됩니다. 그리고 일단 수집되면 doc(docname)에 전화를 걸어 문서를 가져올 수 있으며, 문서를 찾은 후에는 get() 메서드를 호출하여 문서를 가져올 수 있습니다. 문서를 받은 후 다음 을 사용하여 액세스할 수 있습니다. 이것이 이 전체 선의 평균입니다.

js db.collection('users').doc(email).get() .then(...)

확인하려고 실행 중인 위의 코드는 이메일이 이미 데이터베이스에 존재하는지 여부를 나타냅니다. 만약 그렇다면 우리는 경고를 보낸다. 그렇지 않은 경우 사용자를 데이터베이스에 저장합니다. ```js if(user.exists){ return res.json({'alert': 'email already exists'}); } else{ // encrypt the password before storing it. bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(password, salt, (err, hash) => { req.body.password = hash; db.collection('users').doc(email).set(req.body) .then(data => { res.json({ name: req.body.name, email: req.body.email, seller: req.body.seller, }) }) }) }) } ``` bycrypt는 암호화 패키지로, 원하는 경우 해당 설명서를 읽을 수 있습니다. 하지만 암호를 해시하려면, 코드화만 하면 됩니다. gensalt는 텍스트에 얼마나 많은 염색을 수행하고자 하는가를 나타냅니다. 그리고 해시는 텍스트를 해시로 은닉하는 것입니다. 그리고 다시, 모든 것은 문서까지는 동일하지만, 이번에는 우리가 ()를 설정할 필요가 없습니다. 우리는 () 꽤 자기 설명적인 것을 설정해야 합니다. 마지막으로 사용자 이름, 이메일, 판매자 현황을 프런트 엔드로 보냅니다. 이제 그것을 앞쪽에 보관합시다. ```js const processData = (data) => { loader.style.display = null; if(data.alert){ showAlert(data.alert); } else if(data.name){ // create authToken data.authToken = generateToken(data.email); sessionStorage.user = JSON.stringify(data); location.replace('/'); } } ``` 세션 저장소를 사용하여 세션 내에 사용자 데이터를 저장합니다. 그러나 사용자 이메일을 사용하여 신뢰성을 검증할 수는 없습니다. 최소한 검증할 수 있는 것이 필요합니다. 이를 위해 사용자에 대한 인증 토큰을 생성합니다. 이것은 진전은 아니지만, 그래, 나는 진전으로 만들 생각이었어. 먼저 token.js 파일을 등록.html에 추가합니다. ```js ``` 생성 후토큰 함수. ```js let char = `123abcde.fmnopqlABCDE@FJKLMNOPQRSTUVWXYZ456789stuvwxyz0!#$%&ijkrgh;'*+-/=?^_${'`'}{|}~`; const generateToken = (key) => { let token = ''; for(let i = 0; i < key.length; i++){ let index = char.indexOf(key[i]) || char.length / 2; let randomIndex = Math.floor(Math.random() * index); token += char[randomIndex] + char[index - randomIndex]; } return token; } ``` 위의 이 코드는 문자 문자열에서 원본 텍스트 색인을 제공하기 위해 추가된 2글자 색인 번호의 텍스트를 생성할 뿐이다. 그것은 간단하지만 또한 복잡하다. 괜찮아요, 복사하고 싶으면 하세요. 토큰을 검증하는 기능도 원합니다. ```js const compareToken = (token, key) => { let string = ''; for(let i = 0; i < token.length; i=i+2){ let index1 = char.indexOf(token[i]); let index2 = char.indexOf(token[i+1]); string += char[index1 + index2]; } if(string === key){ return true; } return false; } ``` 좋아! 우리는 페이지를 거의 끝냈어. 지금까지 세션에 사용된 내용을 성공적으로 저장했으므로 이를 검증해 보겠습니다. ```js // redirect to home page if user logged in window.onload = () => { if(sessionStorage.user){ user = JSON.parse(sessionStorage.user); if(compareToken(user.authToken, user.email)){ location.replace('/'); } } } ``` 세션에 사용자인지 아닌지를 확인하는 로드 이벤트를 창에 추가하고 있습니다. 세션 중인 경우 인증 토큰의 유효성을 검사하는 중입니다. 그리고 그것은 정당하다. 사용자를 홈 페이지로 리디렉션합니다. 그/그녀는 정말 가입할 필요가 없기 때문에. 좋아요! 회원가입 페이지가 끝났습니다. 블로그가 너무 길어서요. 오늘은 이것으로 충분하다고 생각합니다. 하지만 두 번째 파트에서는 로그인 페이지와 셀러의 대시보드를 만들었습니다. 튜토리얼에서 만들었죠. 물론 모든 기능을 만들고 싶다면, 원하는 것입니다. 튜토리얼 보기 모두 이해하셨기를 바랍니다. 의심스럽거나 제가 놓친 것이 있으면 댓글로 알려주세요. # 유용하게 사용할 수 있는 항목 - 최상의 CSS 효과 - 무한 CSS 로더 - 디즈니+ 복제 - Youtube API - Youtube 복제 - TMDB - Netflix 복제 제 유튜브 채널을 구독해 주시면 정말 감사하겠습니다. 저는 멋진 웹 콘텐츠를 만듭니다. ![](https://res.cloudinary.com/practicaldev/image/fetch/s--5gs5zBA7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jeitpawvax07cx7r9yoa.png) 소스 코드, 페이팔에 기부해 주세요. 당신의 기부는 제가 이렇게 더 놀라운 튜토리얼을 하게끔 정말 동기부여기에요. 파티론에서 나를 응원해줘, 커피 사줘, 페이팔에서 나를 기부해줘. 읽어주셔서 감사합니다.

from http://gong-tech.tistory.com/49 by ccl(A) rewrite - 2021-09-25 03:01:07