SPA Framework가 뭔가요?
Angular, React, 그리고 Vue로 대표되는 SPA 프레임워크들!
웹개발에 관심이 있다면 들어보셨을거에요.
MVC 프레임워크
영상으로 동적 프로그래밍에 대한 보다 깊은 이해를 다지셨다면
이제 Single Page Application으로, 프론트엔드와 백엔드를 분리한
보다 현대적인 웹 개발 방식을 알아가보기로 해요.
프레임워크 | 링크 |
---|---|
Angular | 바로가기 |
React | 바로가기 |
Vue | 바로가기 |
🎬 영상 주요 포인트
😎 SPA의 등장 배경
...
웹에서도 그게 가능하다면, 즉 서버에서 데이터만 보내줘도
이걸 브라우저에서 HTML, CSS, 자바스크립트로 랜더링해낼 수 있다면
이제 서버는 어디서 정보를 요청하든
동일한 작업을 수행해서 데이터를 전송하면 될 거에요.
서버 개발자가 이 일에만 집중할 수 있게 되는거죠.
웹사이트 개발을 이렇게
사용자 컴퓨터의 브라우저에서 돌아가는 프론트엔드와
서버에서 돌아가는 백엔드로 분리하는거에요.
브라우저에서도 동작하는 이 자바스크립트란 언어로
강력한 라이브러리나 프레임워크를 만들면 가능하지 않을까요?
바로 그게 Angular, React, Vue 같은 SPA 프레임워크에요.
🥓 SPA의 개념
SPA, Single Page Application은
종업원들이 고기와 쌈재료를 가져다주면
손님이 직접 불판에 구워먹는 고기집이라고 생각하시면 돼요.
사용자가 사이트에 접속하면
서버는 정적 웹처럼, HTML, CSS, 자바스크립트로 된
코드들을 브라우저에 전송해요.
여기 포함된 자바스크립트 코드는 Git똥찬 기능을 수행하는데요
주어진 데이터에 따라 HTML 웹페이지를 랜더링해내는거에요.
기존의 동적 웹에서 서버가 하던 일을
이제는 사용자의 컴퓨터에서 브라우저가 해내는거죠.
SPA는 서버에서 데이터를 받아와야 할 때마다
요청을 보내서 반환된 데이터로 사이트 내용을 갱신해요.
이렇게 되면 사이트에서 뭘 할 때마다 새로 접속하지 않고
한번 로드된 화면에서 많은 기능을 사용할 수 있겠죠.
그래서 Single Page Application이라 불리는거에요.
⌨️ 영상에 사용된 예제 코드
index.html
<!DOCTYPE html>
<html lang="ko">
<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">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>spa-front</title>
</head>
<body>
<noscript>
<strong>We're sorry but spa-front doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<!-- 아래 div 안에 Vue 코드가 만들어낸 요소들이 들어갑니다. -->
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
LectureList.vue
<template>
<div class="list">
<!-- data 내 pageTitle의 값이 아래 h2에 들어갑니다. -->
<h2>{{pageTitle}}</h2>
<table class="lectures">
<!-- data 내 lectueList 배열의 요소 하나하나가 아래 tr로 만들어집니다. -->
<!-- 각 요소 하나하나를 lecture로, 그 번호를 lecIdx로(여기서는 사용되지 않음) 부릅니다. -->
<tr v-for="(lecture, lecIdx) in lectureList" :key="lecIdx"
@click="toDetail(lecture.idx)">
<td class="thumbnail">
<img v-bind:src="lecture.lec_thumb"/>
</td>
<td class="title">
<span>
{{lecture.lec_date}}
</span>
<br>
{{lecture.lec_title}}
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'lecture-list',
// 데이터가 들어가는 곳입니다.
data: function() {
return {
pageTitle: '두꺼운 코딩사전 강좌 리스트',
lectureList: []
}
},
// 함수들을 지정하는 곳입니다.
methods: {
toDetail: function (idx) {
this.$router.push(`detail/${idx}`)
}
},
// 페이지가 열리면 실행되는 명령어입니다.
mounted () {
let _this = this
// 아래의 임시 주소에서 정보를 받아옵니다.
_this.$axios.get('http://127.0.0.1:8000/api/lectures')
.then((response) => {
response.data.map((item) => {
// 받아온 정보를 lectureList에 넣어줍니다.
_this.lectureList.push(item)
})
})
}
}
</script>
<style lang="scss" scoped>
@import '../assets/scss/lecture.scss'
</style>
LectureDetail.vue
<template>
<!-- data 내 lecture에 값이 들어와야(null이 아니도록) 아래 요소가 나타납니다. -->
<div v-if="lecture !== null" class="detail">
<h3>
{{lecture.lec_title}}
</h3>
<table class="lecture">
<tr>
<td>
<span>영상번호:</span>
{{lecture.idx}}
</td>
<td>
<span>카테고리:</span>
{{lecture.lec_category}}
</td>
<td>
<span>영상길이:</span>
{{lecture.lec_length}}
</td>
</tr>
<tr>
<td colspan="3" class="lec-pic">
<iframe width="560" height="315"
v-bind:src="'https://www.youtube.com/embed/' + lecture.lec_code"
frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</td>
</tr>
</table>
<div class="commentCount">
<span>
댓글: {{commentList.length}}
</span>
</div>
<table class="comments">
<!-- data 내 commentList 배열의 요소 하나하나가 아래 tr로 만들어집니다. -->
<!-- 각 요소 하나하나를 comment로, 그 번호를 cmtIdx로(여기서는 사용되지 않음) 부릅니다. -->
<tr v-for="(comment, cmtIdx) in commentList" :key="cmtIdx">
<td>
{{comment.lc_name}}
</td>
<td>
{{comment.lc_comment}}
</td>
</tr>
<tr>
<td>
<!-- 이 input은 data의 inputName와 연결됩니다. -->
<input v-model="inputName" placeholder="이름"/>
</td>
<td>
<!-- 이 input은 data의 inputComment와 연결됩니다. -->
<input v-model="inputComment" placeholder="댓글을 입력하세요."
v-on:keyup.enter="submitComment"/>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'lecture-detail',
// 데이터가 들어가는 곳입니다.
data: function() {
return {
idx: null,
lecture: null,
commentList: [],
inputName: '',
inputComment: '',
submitting: false
}
},
// 함수들을 지정하는 곳입니다.
methods: {
// 댓글들을 받아오는 함수입니다.
getComments: function () {
let _this = this
// 아래 주소에서 댓글들을 받아와서
_this.$axios.get(`http://127.0.0.1:8000/api/lec_comments/${this.idx}/`)
.then((response) => {
// 기존 commentList를 비우고
_this.commentList.splice(0, _this.commentList.length)
// 받아온 댓글들로 채웁니다.
_this.commentList = _this.commentList.concat(response.data)
})
},
// 댓글을 올리는 함수입니다.
submitComment: function () {
let _this = this
// 이미 댓글을 올리는 중이거나 입력된 이름이나 댓글이 비어있으면 중단합니다
if (_this.submitting
|| _this.inputName.trim().length === 0
|| _this.inputComment.trim().length === 0) return
_this.submitting = true
// 서버에 보낼 내용입니다.
let toSend = {
lec_idx: _this.idx,
lc_name: _this.inputName,
lc_comment: _this.inputComment
}
// 아래 주소로 서버에 댓글 입력내용을 보냅니다
_this.$axios.post(`http://127.0.0.1:8000/api/lec_comments/${this.idx}/`,
_this.$qs.stringify(toSend), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
// 보내졌다는 응답이 오면
}).then((response) => {
// 댓글들을 새로 받아오고
_this.getComments()
// 이름과 댓글 입력칸을 비워주고
_this.inputName = ''
_this.inputComment = ''
// '보내는 중'을 해지합니다
_this.submitting = false
})
}
},
// 페이지가 열리면 실행되는 명령어입니다.
mounted () {
let _this = this
_this.idx = _this.$route.params.idx
// 페이지에 주어진 idx 번호에 해당하는 강의를 받아옵니다.
_this.$axios.get(`http://127.0.0.1:8000/api/lectures/${this.idx}/`)
.then((response) => {
_this.lecture = response.data
})
_this.getComments()
}
}
</script>
<style lang="scss" scoped>
@import '../assets/scss/lecture.scss'
</style>
🍿 더 자세한 내용은 영상에서 보실 수 있습니다.
유튜브에서 영상 보기