이번에는 캐릭터의 공격대 진행 상황을 나타내는 컴포넌트를 만들것이다.
우선 캐릭터의 던전 진척도를 api를 통해 가져온다.
export function getDungeonProgress(store) { | |
this.$axios.$get(`https://kr.api.blizzard.com/profile/wow/character/${store.state.realmSlug}/${store.state.characterName}/encounters/raids`, | |
{ | |
params:{ | |
region:'kr', | |
namespace:'profile-kr', | |
locale:'ko-KR', | |
access_token: store.state.accessToken, | |
} | |
}) | |
.then(function (result) { | |
store.commit('setRawData', result) | |
store.commit('setRaidProgressData', progressData.getRaidProgress(result)) | |
}) | |
.catch(function (error) { | |
console.log(error) | |
}) | |
} | |
let progressData = { | |
raidProgress: [], | |
getRaidProgress: function (rawData) { | |
this.raidProgress = this.getRaidProgressData(rawData) | |
return this.raidProgress | |
}, | |
getInstanceData: function (data, dungeonName, dungeonId) { | |
if(data.difficulty.type ==='LEGACY_10_MAN_HEROIC'){ | |
data.difficulty.type = 'HEROIC' | |
} | |
else if(data.difficulty.type === 'LEGACY_25_MAN_HEROIC'){ | |
data.difficulty.type = 'HEROIC' | |
} | |
else if(data.difficulty.type ==='LEGACY_10_MAN'){ | |
data.difficulty.type = 'NORMAL' | |
} | |
else if(data.difficulty.type ==='LEGACY_25_MAN'){ | |
data.difficulty.type = 'NORMAL' | |
} | |
let instanceData = { | |
name: dungeonName, | |
id: dungeonId, | |
difficulty: data.difficulty.type, | |
status: data.status.type, | |
completedCount: data.progress.completed_count, | |
totalCount: data.progress.total_count, | |
bossData: [] | |
} | |
// 키가 있는지 확인 key:{} | |
// 데이터가 있는지 확인 없으면 밑에꺼 스킵 | |
data.progress.encounters.forEach(boss => { | |
instanceData.bossData.push(boss) | |
}) | |
return instanceData | |
}, | |
getDungeonData: function (data) {//여기 data는 현재 가리키고 있는 던전 rawData.expansions[].instances[]) | |
let data_sorted_by_difficulty = [] | |
let dungeonName = data.instance.name | |
let dungeonId = data.instance.id | |
data.modes.forEach(difficulty => { | |
data_sorted_by_difficulty.push(this.getInstanceData(difficulty, dungeonName, dungeonId)) | |
}) | |
return data_sorted_by_difficulty | |
}, | |
getExpansionData: function (data) {//rawData.expansions[] | |
let expansionData = { | |
expansionName: data.expansion.name, | |
dungeonData: [] | |
} | |
data.instances.forEach(dungeon => { | |
expansionData.dungeonData.push(this.getDungeonData(dungeon)) | |
}) | |
return expansionData | |
}, | |
getRaidProgressData: function (data) { | |
let RaidProgress = [] | |
//console.log(data.expansions) | |
if(data.hasOwnProperty('expansions')){ | |
data.expansions.forEach(expansion => { | |
RaidProgress.push(this.getExpansionData(expansion)) | |
}) | |
} | |
return RaidProgress | |
} | |
} | |
// 코드를 좔좔좔 데이터 가공 코드 |
데이터를 가져오면서 내가 쓰기 편한 형태로 가공해주었다.
비교적 최근 확장팩의 레이드와 그 이전의 확장팩 레이드가 난이도가 다르게 표기되는 부분이 있었다.
현재는 LFR(공격대 찾기), NORMAL(일반), HEROIC(영웅), MYTHIC(신화)로 구분되는데, 이전 일부 확장팩에서는 LEGACY_10_MAN 이런식으로 표기되어있어 이부분은 현재 확장팩의 난이도에 맞게 바꾸어주었다.
진척도 카드에 들어갈 이미지도 같이 불러올것이다.
export function getDungeonImage(store, payload) { | |
this.$axios.$get(`https://kr.api.blizzard.com/data/wow/media/journal-instance/${payload.id}`, { | |
params: { | |
namespace: 'static-kr', | |
locale: 'ko_KR', | |
access_token: store.state.accessToken | |
}//region은 kr.api us.api 처럼 앞에 어느 국가 서버에서 받아올지 결정. locale은 어느 언어로 표기할지 결정 | |
}) | |
.then(function (response) { | |
let imageData = { | |
id: payload.id, | |
url: response.assets[0].value | |
} | |
store.commit('setImgUrl', imageData) | |
}) | |
.catch(function (error) { | |
console.log(error) | |
}) | |
} |
이제 v-card를 이용해 공격대 진행도를 나타내는 카드를 만들것이다
<template> | |
<v-card | |
class="mx-auto" | |
max-width="300" | |
style="background-color: #273239; !important;" | |
> | |
<v-img | |
class="white--text align-end" | |
gradient="to top, rgba(0,5,10,0.95), rgba(255,255,255,0)" | |
:height="imgHeight" | |
:src="stateData" | |
> | |
<v-card-title | |
class="justify-end" | |
style="font-size: 15px" | |
>{{dungeon[0].name}} | |
</v-card-title> | |
</v-img> | |
<v-card-text | |
class="text--primary" | |
style="font-size: 12px" | |
> | |
<v-row | |
v-for="(item, index) in difficultyList" | |
:key="index" | |
class="my-4" | |
no-gutters | |
> | |
<v-col | |
cols="4" | |
align="start" | |
class="align-self-center pl-1" | |
> | |
{{item}} | |
</v-col> | |
<v-col | |
class="pr-1" | |
cols="8" | |
> | |
<v-progress-linear | |
:value="(levelClear[item].clear/levelClear[item].total *100)" | |
:color="levelClear[item].percent === 100 ? clearedColor:defaultColor" | |
:height="height" | |
background-color="grey darken-4" | |
> | |
<template v-slot> | |
{{levelClear[item].clear}}/{{levelClear[item].total}} | |
</template> | |
</v-progress-linear> | |
</v-col> | |
</v-row> | |
</v-card-text> | |
</v-card> | |
</template> | |
<script> | |
export default { | |
name: "RaidProgressCard", | |
data() { | |
return { | |
progress: 0, | |
height: 28, | |
imgHeight: "200px", | |
clearedColor: 'green darken-2', | |
defaultColor: 'orange darken-2', | |
barColor: 'orange', | |
name: 'no name', | |
SRC: '', | |
difficultyList: ['LFR', 'NORMAL', 'HEROIC', 'MYTHIC'] | |
} | |
}, | |
computed: { | |
stateData() { | |
return this.$store.state.dungeonImageData[this.dungeon[0].id] | |
}, | |
levelClear() { | |
let obj = {} | |
this.difficultyList.forEach(level => { | |
obj[level] = {} | |
obj[level].total = this.dungeon[0].totalCount | |
obj[level].clear = 0 | |
obj[level].percent = 0 | |
}) | |
this.dungeon.forEach(dungeonObj => { | |
if (this.difficultyList.includes(dungeonObj['difficulty'])) { | |
obj[dungeonObj['difficulty']].clear = dungeonObj['completedCount'] | |
obj[dungeonObj['difficulty']].total = dungeonObj['totalCount'] | |
obj[dungeonObj['difficulty']].percent = dungeonObj['completedCount'] / dungeonObj['totalCount'] * 100 | |
} | |
}) | |
return obj | |
} | |
}, | |
props: { | |
dungeon: { | |
type: Array, | |
required: true | |
} | |
} | |
} | |
</script> | |
<style scoped> | |
.custom-gradient { | |
height: 28px; | |
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0)); /* Standard syntax (must be last) */ | |
} | |
</style> |
<template> | |
<v-row> | |
<v-col | |
style="max-width: 400px; min-width: 300px" | |
:items="dungeons" | |
v-for="item in dungeons" | |
:key="item.name" | |
cols="12" | |
sm="6" | |
md="3" | |
lg="2" | |
> | |
<raid-process-card :dungeon="item"></raid-process-card> | |
</v-col> | |
</v-row> | |
</template> | |
<script> | |
import RaidProcessCard from "./RaidProcessCard"; | |
export default { | |
name: "ExpansionSort" | |
, | |
components:{ | |
RaidProcessCard | |
}, | |
computed:{ | |
dungeons(){ | |
return this.expansion['dungeonData'] | |
} | |
}, | |
props: { | |
expansion:{ | |
type: Object, | |
required: true | |
} | |
} | |
} | |
</script> | |
<style scoped> | |
</style> |
<template> | |
<v-container fluid> | |
<v-row | |
v-for="expansion in reversedExpansions" | |
> | |
<v-col> | |
<v-row>{{expansion['expansionName']}}</v-row> | |
<v-row> | |
<expansion-sort :expansion="expansion"></expansion-sort> | |
</v-row> | |
</v-col> | |
</v-row> | |
</v-container> | |
</template> | |
<script> | |
import RaidProcessCard from "./RaidProcessCard"; | |
import ExpansionSort from "./ExpansionSort"; | |
export default { | |
components: { | |
RaidProcessCard, | |
ExpansionSort | |
}, | |
data() { | |
return {} | |
}, | |
computed: { | |
reversedExpansions(){ | |
return this.$store.state.raidProgressData.slice().reverse() | |
}, | |
expansions() { | |
return this.$store.state.raidProgressData | |
}, | |
dungeons() { | |
let dungeons = [] | |
let data = this.$store.state.raidProgressData | |
data.forEach(expansion => { | |
expansion.dungeonData.forEach(dungeon => { | |
dungeons.push(dungeon) | |
}) | |
}) | |
return dungeons | |
} | |
} | |
} | |
</script> | |
<style scoped> | |
</style> |
RaidProgressCard 컴포넌트로 v-card 틀을 만들고, ExpansionSort 컴포넌트로 확장팩별로 정리를 해주고, RaidProgressIter 컴포넌트로 확장팩별로 카드들을 출력했다. 결과는 다음과 같다.
각 컴포넌트간에 데이터를 넘겨줄때는 props를 이용하면 된다.

이 부분을 작업하면서 신경쓰였던 부분이 이미지가 전부 불러와지기 전에 컴포넌트가 구성되어서 그런지 이미지가 누락되는 문제가 있었다. 그래서 페이지가 구성될 때 미리 이미지를 불러오는 식으로 순서를 바꾸어주었다.
import auto from 'async/auto.js' | |
export function initPage(store,callback) { | |
auto({ | |
get_token: getToken, | |
get_realm_data: ['get_token', getRealmData], | |
get_dungeon_image: ['get_token',getDungeonImg] | |
}, function (err, results) { | |
console.log('err = ', err) | |
console.log('results = ', results) | |
}) | |
function getToken(callback){ | |
console.log('token start') | |
store.dispatch('getAccessToken') | |
.then((result)=>{ | |
if(result){ | |
console.log('token pass') | |
callback(null) | |
}else{ | |
callback('get access function err') | |
} | |
}) | |
} | |
function getRealmData(nonUseArg, callback) { | |
console.log('realm call') | |
store.dispatch('getRealmSlug') | |
callback(null) | |
} | |
function getDungeonImg(nonUseArg, callback){ | |
console.log('img call') | |
for(let i=0; i<store.state.dungeonIdList.length; i++){ | |
store.dispatch('getDungeonImage', {id: store.state.dungeonIdList[i]}) | |
} | |
callback(null) | |
} | |
} |
async 모듈의 auto를 이용해 교통정리를 좀 해줬다.
auto를 사용하면서 잘 안돼서 골머리를 좀 썩혔는데, 알고보니 action에서 사용된 IO함수때문에 문제가 발생했던것이다. 떄문에 accessToken을 dispatch할떄 promise를 리턴하게 하고 .then()을 붙여주었다.
'blizzard open api & nuxt 튜토리얼 프로젝트' 카테고리의 다른 글
캐릭터 장비 컴포넌트 제작 - 2 (6/6) (0) | 2021.01.05 |
---|---|
캐릭터 장비 컴포넌트 제작 - 1 (5/6) (0) | 2020.12.30 |
캐릭터 이미지 받아오기 (3/6) (0) | 2020.12.15 |
계정 정보 받아오기 (2/6) (1) | 2020.12.01 |
블리자드 오픈 api 토큰 생성 (1/6) (0) | 2020.11.19 |