のビデオを見て感動したので記事を書いています。
githubページが載っているので、誰のためでもなくただ自分のために書きます。vueのロジックだけです。
src/componentsの中だけの説明です。
まず、Pokemon.vueには
<template>
<div class="container">
<h1>Pokemon's</h1>
<PokemonSearch
:apiUrl="apiUrl"
@setPokemonUrl="setPokemonUrl" />
<PokemonList
:imageUrl="imageUrl"
:apiUrl="apiUrl"
@setPokemonUrl="setPokemonUrl" />
<PokemonDetail
v-if="showDetail"
:pokemonUrl="pokemonUrl"
:imageUrl="imageUrl"
@closeDetail="closeDetail" />
</div>
</template>
<script>
import PokemonSearch from './PokemonSearch.vue';
import PokemonList from './PokemonList.vue';
import PokemonDetail from './PokemonDetail.vue';
export default {
data: () => {
return {
imageUrl: 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/',
apiUrl: 'https://pokeapi.co/api/v2/pokemon/',
pokemonUrl: '',
showDetail: false
}
},
components: {
PokemonSearch,
PokemonList,
PokemonDetail
},
methods: {
setPokemonUrl(url) {
this.pokemonUrl = url;
this.showDetail = true;
},
closeDetail() {
this.pokemonUrl = '';
this.showDetail = false;
}
}
}
</script>
見てわかる通り。
<template>
<div class="detail">
<div class="detail-view" v-if="show">
<div v-if="pokemon" class="image">
<img :src="imageUrl + pokemon.id + '.png'" alt="">
</div>
<div v-if="pokemon" class="data">
<h2>{{ pokemon.name }}</h2>
<div class="property">
<div class="left">Base Experience</div>
<div class="right">{{ pokemon.base_experience }} XP</div>
</div>
<div class="property">
<div class="left">Height</div>
<div class="right">{{ pokemon.height / 10 }} m</div>
</div>
<div class="property">
<div class="left">Weight</div>
<div class="right">{{ pokemon.weight / 10 }} kg</div>
</div>
<h3>Pokemon Types</h3>
<div class="types">
<div class="type"
v-for="(value, index) in pokemon.types"
:key="'value'+index">
{{ value.type.name }}
</div>
</div>
<h3>Abilities</h3>
<div class="abilities">
<div class="ability"
v-for="(value, index) in pokemon.abilities"
:key="'value'+index">
{{ value.ability.name }}
</div>
</div>
</div>
<h2 v-else>The pokemon was not found</h2>
<button class="close" @click="closeDetail">close</button>
</div>
<i v-else class="fas fa-spinner fa-spin"></i>
</div>
</template>
<script>
export default {
props: [
'pokemonUrl',
'imageUrl'
],
data: () => {
return {
show: false,
pokemon: {}
}
},
methods: {
fetchData() {
let req = new Request(this.pokemonUrl);
fetch(req)
.then((resp) => {
if(resp.status === 200)
return resp.json();
})
.then((data) => {
this.pokemon = data;
this.show = true;
})
.catch((error) => {
console.log(error);
})
},
closeDetail() {
this.$emit('closeDetail');
}
},
created() {
this.fetchData();
}
}
</script>
このプログラムはポケモンのイラストをリスト状に展開してそれをクリックすると
そのポケモンのデータが表示されているモーダルが
表示されるというプログラムになっています。
つまり、このプログラムは後述するcomponents/PokemonList.vueからデータを渡されて
そのままそのデータを表示する流れとなっています。
methods: {
fetchData() {
let req = new Request(this.pokemonUrl);
fetch(req)
.then((resp) => {
if(resp.status === 200)
return resp.json();
})
.then((data) => {
this.pokemon = data;
this.show = true;
})
.catch((error) => {
console.log(error);
})
},
methodsのfetchData()でデータを取得していることが解ると思います。
PokemonList.vue
<template>
<div class="list">
<article v-for="(pokemon, index) in pokemons"
:key="'poke'+index"
@click="setPokemonUrl(pokemon.url)">
<img :src="imageUrl + pokemon.id + '.png'" width="96" height="96" alt="">
<h3>{{ pokemon.name }}</h3>
</article>
<div id="scroll-trigger" ref="infinitescrolltrigger">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
</template>
<script>
export default {
props: [
'imageUrl',
'apiUrl'
],
data: () => {
return {
pokemons: [],
nextUrl: '',
currentUrl: ''
}
},
methods: {
fetchData() {
let req = new Request(this.currentUrl);
fetch(req)
.then((resp) => {
if(resp.status === 200)
return resp.json();
})
.then((data) => {
this.nextUrl = data.next;
data.results.forEach(pokemon => {
pokemon.id = pokemon.url.split('/')
.filter(function(part) { return !!part }).pop();
this.pokemons.push(pokemon);
});
})
.catch((error) => {
console.log(error);
})
},
scrollTrigger() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.intersectionRatio > 0 && this.nextUrl) {
this.next();
}
});
});
observer.observe(this.$refs.infinitescrolltrigger);
},
next() {
this.currentUrl = this.nextUrl;
this.fetchData();
},
setPokemonUrl(url) {
this.$emit('setPokemonUrl', url);
}
},
created() {
this.currentUrl = this.apiUrl;
this.fetchData();
},
mounted() {
this.scrollTrigger();
}
}
</script>
まずポケモンのデータをぶん回しているところから
<div class="list">
<article v-for="(pokemon, index) in pokemons"
:key="'poke'+index"
@click="setPokemonUrl(pokemon.url)">
<img :src="imageUrl + pokemon.id + '.png'" width="96" height="96" alt="">
<h3>{{ pokemon.name }}</h3>
</article>
<div id="scroll-trigger" ref="infinitescrolltrigger">
<i class="fas fa-spinner fa-spin"></i>
</div>
methods: {
fetchData() {
let req = new Request(this.currentUrl);
fetch(req)
.then((resp) => {
if(resp.status === 200)
return resp.json();
})
.then((data) => {
this.nextUrl = data.next;
data.results.forEach(pokemon => {
pokemon.id = pokemon.url.split('/')
.filter(function(part) { return !!part }).pop();
this.pokemons.push(pokemon);
});
})
.catch((error) => {
console.log(error);
})
},
の中fetchData()が面白いので説明すると
```fetch(req)
.then((resp) => {
if(resp.status === 200)
return resp.json();
})
.then((data) => {
this.nextUrl = data.next;
data.results.forEach(pokemon => {
pokemon.id = pokemon.url.split('/')
.filter(function(part) { return !!part }).pop();
this.pokemons.push(pokemon);
});
})
ポケモンのurlごとのデータを分割して最後の要素を取得しています。
MDNのサイトを参照のこと
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/pop
以上です。
お疲れ様でした。