página :) </title> </head> <body> <div id="my-element" class="main-section container" data-main> <img src="http://fakeurl.com/img.jpg" /> </div> </body> </html> tipo do documento abertura de tag atributos self-closing tag fechamento de tag } <head> = configuração da página } <body> = conteúdo da página
console do navegador na aba Console # Atualize a página # Verifique o nome dos pokémons printados Iniciando o projeto ▣ Criar a estrutura de pastas ▣ Editar arquivo index.html ▣ Editar arquivo js/index.js ▢ Verificar no navegador
> js/pokemons.js ▢ Importar js/pokemons.js no index.html? ▢ Gerar build/bundle.js ▣ Instalar ferramenta de bundling: Browserify ▣ Configurar script que gera o build/bundle.js ▢ Transformar js/index.js e js/pokemons.js em módulos var pokemons = require('./pokemons'); pokemons.forEach(function(pokemon) { console.log(pokemon.name); }); js/index.js import o array de pokémons de js/pokemons.js agora js/pokemons.js está na árvore de dependências
> js/pokemons.js ▢ Importar js/pokemons.js no index.html? ▢ Gerar build/bundle.js ▣ Instalar ferramenta de bundling: Browserify ▣ Configurar script que gera o build/bundle.js ▣ Transformar js/index.js e js/pokemons.js em módulos ▢ Criar pasta build front-unifal js index.html index.js pokemons.js build
> js/pokemons.js ▢ Importar js/pokemons.js no index.html? ▢ Gerar build/bundle.js ▣ Instalar ferramenta de bundling: Browserify ▣ Configurar script que gera o build/bundle.js ▣ Transformar js/index.js e js/pokemons.js em módulos ▣ Criar pasta build ▢ Gerar build/bundle.js > npm run build:js # verificar aquivo build/bundle.js criado # executar index.html novamente no browser # verificar console do browser
Pokemon { constructor(info) { this.name = info.name; } } module.exports = Pokemon; js/models/Pokemon.js cria classe chamada Pokemon quando um objeto da classe for criado, salva o nome do Pokémon exporta a classe Pokemon
Criar arquivo js/models/PokemonList.js var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray) { this.items = []; for(var i = 0; i < infoArray.length; i++) { var pokemon = new Pokemon(infoArray[i]); this.items.push(pokemon); } } } module.exports = PokemonList; js/models/PokemonList.js importa classe Pokemon recebe array de informações de pokemons para cada item do array de informações, cria uma instância de Pokemon e salva na lista
Criar arquivo js/models/PokemonList.js ▢ Usar classe PokemonList em js/pokemons.js var PokemonList = require('./models/PokemonList'); var pokemonsInfo = [ { name: 'pikachu' }, { name: 'blaziken' }, { name: 'lucario' } ]; var pokemons = new PokemonList(pokemonsInfo); module.exports = pokemons; js/pokemons.js cada um destes items será usado para criar um objeto da classe Pokemon
Criar arquivo js/models/PokemonList.js ▣ Usar classe PokemonList em js/pokemons.js ▢ Usar nossa nova lista em js/index.js var pokemons = require('./pokemons'); pokemons.items.forEach(function(pokemon) { console.log(pokemon.name); }); js/index.js usa campo items da lista de pokémons
Criar arquivo js/models/PokemonList.js ▣ Usar classe PokemonList em js/pokemons.js ▣ Usar nossa nova lista em js/index.js ▢ Verificar no navegador > npm run build:js # verificar aquivo build/bundle.js criado # executar index.html novamente no browser # verificar console do browser
Criar arquivo js/models/PokemonList.js ▣ Usar classe PokemonList em js/pokemons.js ▣ Usar nossa nova lista em js/index.js ▣ Verificar no navegador ▢ Erro de sintaxe?! ?
do código ▣ Documentação ▢ Melhor design e confiança no código Código ruim Poucos testes Medo de refatorar Baixa testabilidade Código novo Testes Refatoração Código bom
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▢ Criar pasta test front-unifal js build test
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▢ Criar arquivo test/Pokemon.test.js var chai = require('chai'); var expect = chai.expect; var Pokemon = require(../js/models/Pokemon'); describe('Pokemon', function() { }); test/Pokemon.test.js o nome da classe que vamos testar classe que vamos testar nossos testes para a classe Pokemon ficarão aqui
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▢ Criar arquivo test/Pokemon.test.js var chai = require('chai'); var expect = chai.expect; var Pokemon = require(../js/models/Pokemon'); describe('Pokemon', function() { it('should save the pokemon name', function() { }); }); test/Pokemon.test.js descrição do nosso teste o corpo do nosso teste ficará aqui
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▢ Criar arquivo test/Pokemon.test.js var chai = require('chai'); var expect = chai.expect; var Pokemon = require(../js/models/Pokemon'); describe('Pokemon', function() { it('should save the pokemon name', function() { var pokemon = new Pokemon({ name: 'growlithe' }); }); }); test/Pokemon.test.js testaremos se a variável pokemon salvará o nome growlighte dentro dela
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▢ Criar arquivo test/Pokemon.test.js var chai = require('chai'); var expect = chai.expect; var Pokemon = require(../js/models/Pokemon'); describe('Pokemon', function() { it('should save the pokemon name', function() { var pokemon = new Pokemon({ name: 'growlithe' }); expect(pokemon.name).to.equal('growlithe'); }); }); test/Pokemon.test.js leia “espera-se que pokemon.name seja igual a growlithe”
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▣ Criar arquivo test/Pokemon.test.js ▢ Executar teste > npm run test # verificar saída do teste no terminal test/Pokemon.test.js
do código ▣ Documentação ▣ Melhor design e confiança no código ▣ Como? ▣ Metodologia ▣ Ferramentas ▣ NPM script ▢ Escrevendo o primeiro teste ▣ Criar pasta test ▣ Criar arquivo test/Pokemon.test.js ▣ Executar teste ▢ Forçar falha de teste # modifique o código do teste para que ele falhe > npm run test # verificar saída do teste no terminal test/Pokemon.test.js
jQuery ▢ Usar jQuery em js/views/PokemonListView.js var $ = require('jquery'); class PokemonListView { constructor(attrs) { this.pokemonList = attrs.pokemons; this.$element = $('<div/>'); this.$element.addClass('pokemon-list'); } render() { this.pokemonList.items.forEach((pokemon) => { this.$element.append(`<div>${pokemon.name}</div>`); }); } } module.exports = PokemonListView; js/views/PokemonListViews.js adiciona o nome de cada pokémon no HTML no elemento função que usa this internamente (não aprofundaremos aqui no porque de usar => e não function) Views
jQuery ▣ Usar jQuery em js/views/PokemonListView.js ▣ Adicionar elemento da aplicação em index.html ▢ Usar nova view em js/index.js var $ = require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); pokemonListView.render(); $pokedex.append(pokemonListView.$element); js/index.js pega o elemento que criamos em index.html. O jQuery usa seletores igual o CSS :) renderiza a lista de pokémons adiciona elemento da lista no HTML da página Views
jQuery ▣ Usar jQuery em js/views/PokemonListView.js ▣ Adicionar elemento da aplicação em index.html ▣ Usar nova view em js/index.js ▢ Conferir no navegador pega o elemento que criamos em index.html. O jQuery usa seletores igual o CSS :) renderiza a lista de pokémons adiciona elemento da lista no HTML da página > npm run build:js # executar index.html no browser Views
jQuery ▣ Usar jQuery em js/views/PokemonListView.js ▣ Adicionar elemento da aplicação em index.html ▣ Usar nova view em js/index.js ▣ Conferir no navegador ▢ Mover pokemon para uma view ▣ Criar arquivo js/views/PokemonView.js ▣ Usar view em PokemonListView ▢ Conferir no navegador > npm run build:js # executar index.html no browser Views
css/style.css * { box-sizing: border-box; } .pokedex { height: 400px; width: 350px; background-color: #FF0000; color: #FFFFFF; } css/style.css ativa o modo border-box para todos os elementos = espessura da borda é subtraíra da largura/altura seletor para todos os elementos altura de 400px e largura de 350px fundo vermelho seletor para elemento com classe pokedex fonte branca
css/style.css ▣ Adicionar css/style.css em index.html e verificar no navegador ▣ Se decepcione ▢ Estilizar lista de pokémons importar a folha de estilo * { box-sizing: border-box; } .pokedex { height: 400px; width: 350px; background-color: #FF0000; padding: 15px; } .pokemon-list { height: 100%; width: 100%; background-color: #61C93E; border: 1px solid #bb2929; color: #FFFFFF; padding: 10px; } css/style.css espaçamento interno de 15px cor de fundo verde borda vermelha de 1px movido do seletor de cima por especificidade espaçamento interno de 10px seletor para lista de pokémons
▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css index.html <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Pokédex</title> <link rel="stylesheet" href="./build/style.css"> </head> <body> <div class="pokedex"></div> <script src="./build/bundle.js"></script> </body> </html> arquivo com o conteúdo de css/style.css, css/pokedex.css e css/pokemonList.css
▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css ▢ Instalar pré-compilador de CSS: SASS > npm install --save-dev node-sass # verificar que node-sass foi adicionado ao package.json
▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css ▣ Instalar pré-compilador de CSS: SASS ▢ Renomear arquivos de .css para .scss front-unifal js build css style.scss _pokedex.scss _pokemonList.scss Começam com _ porque serão importados por style.scss
} ▣ Estilos para elementos diferentes no mesmo arquivo ▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css ▣ Instalar pré-compilador de CSS: SASS ▣ Renomear arquivos de .css para .scss ▢ Importar arquivos css/style.scss caminho dos arquivos sem o _ no começo do nome
"index.js", "scripts": { "test": "mocha", "build:js": "browserify js/index.js -o build/bundle.js", "build:css": "node-sass css -o build" }, "author": "", "license": "ISC", "devDependencies": { "babel-preset-es2015": "^6.13.2", "babelify": "^7.3.0", "browserify": "^13.1.0", "chai": "^3.5.0", "mocha": "^3.0.2", "node-sass": "^3.8.0" }, "browserify": { "transform": ["babelify"] } } ▣ Estilos para elementos diferentes no mesmo arquivo ▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css ▣ Instalar pré-compilador de CSS: SASS ▣ Renomear arquivos de .css para .scss ▣ Importar arquivos ▢ Configurar npm script package.json pega todos arquivos sem _ da pasta css, compila e coloca resultado na pasta build
build/style.css # executar no navegador e verificar que continua funcionando ▣ Estilos para elementos diferentes no mesmo arquivo ▣ Criar arquivos css/pokedex.css e css/pokemonList.css ▣ Mover cada estilo para seu arquivo ▢ Adicionar folhas de estilo ao index.html? ▢ Gerar build/style.css ▣ Instalar pré-compilador de CSS: SASS ▣ Renomear arquivos de .css para .scss ▣ Importar arquivos ▣ Configurar npm script ▢ Executar npm script e verificar no navegador
apenar um concatenador de CSS ▢ Variáveis ▣ Criar arquivo css/_variables.scss ▢ Extrair cores para o novo arquivo em variáveis $pokedex-color: #FF0000; $pokedex-shadow-color: #bb2929; $white-color: #FFFFFF; $screen-color: #61C93E; css/_variables.scss
apenar um concatenador de CSS ▢ Variáveis ▣ Criar arquivo css/_variables.scss ▢ Extrair cores para o novo arquivo em variáveis $pokedex-color: #FF0000; $pokedex-shadow-color: #bb2929; $white-color: #FFFFFF; $screen-color: #61C93E; css/_variables.scss nome da variável padrão de notação: hífen atribuição com dois-pontos em vez de símbolo de igual valor pode ser qualquer valor de propriedade CSS
apenar um concatenador de CSS ▢ Variáveis ▣ Criar arquivo css/_variables.scss ▣ Extrair cores para o novo arquivo em variáveis ▢ Importar arquivo em css/style.scss @import 'variables'; @import 'pokedex'; @import 'pokemonList'; * { box-sizing: border-box; } css/style.scss primeiro arquivo a ser importado
browser ▣ Se decepcionar novamente ▢ Adicionar metatag de viewport index.html <!doctype html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"> <title>Pokédex</title> <link rel="stylesheet" href="./build/style.css"> </head> <body> <div class="pokedex"></div> <script src="./build/bundle.js"></script> </body> </html> informa ao navegador a largura da tela do celular, a escala inicial a a máxima
browser ▣ Se decepcionar novamente ▣ Adicionar metatag de viewport ▢ Tornar CSS responsivo ▢ Criar variável para largura tela de celular css/_variables.scss $pokedex-color: #FF0000; $pokedex-shadow-color: #bb2929; $white-color: #FFFFFF; $screen-color: #61C93E; $mobile-screen: 480px; consideraremos que toda tela de 480px de largura, ou menos, é um celular
browser ▣ Se decepcionar novamente ▣ Adicionar metatag de viewport ▢ Tornar CSS responsivo ▣ Criar variável para largura tela de celular ▢ Utilizar variável em css/_pokedex.scss css/_pokedex.scss .pokedex { height: 100%; width: 100%; background-color: $pokedex-color; padding: 15px; @media(min-width: $mobile-screen + 1) { height: 400px; width: 350px; } } estilos para todo tamanho de tela } estilo para telas maiores que uma tela de celular } diretiva para aplicar estilos para um determinado tamanho de tela
apenas em desktop ▢ Estilo 3D apenas em desktop ▢ Adicionar profundidade css/_pokedex.scss .pokedex { height: 100%; width: 100%; background-color: $pokedex-color; padding: 15px; @media(min-width: $mobile-screen + 1) { height: 400px; width: 350px; border-radius: 5px; box-shadow: 0 10px 0 darken($pokedex-color, 10%); } } deslocamento no eixo X deslocamento no eixo Y desfoque 10% mais escuro que a pokédex
apenas em desktop ▢ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▢ Tornar profundidade mais perceptível css/_pokedex.scss .pokedex { height: 100%; width: 100%; background-color: $pokedex-color; padding: 15px; @media(min-width: $mobile-screen + 1) { height: 400px; width: 350px; border-radius: 5px; box-shadow: 0 10px 0 darken($pokedex-color, 10%); border: 3px solid lighten($pokedex-color, 10%); } } borda de 3px, contínua, 10% mais clara que a cor da pokédex
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▢ Google Fonts fonts.google.com
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▢ Google Fonts
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▣ Google Fonts ▢ Importar fonte Copiar
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▣ Google Fonts ▣ Importar fonte ▢ Usar fonte no CSS Copiar
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▣ Google Fonts ▣ Importar fonte ▢ Usar fonte no CSS css/_pokemon.scss .pokemon { background-color: $screen-color; font-family: 'Press Start 2P', cursive; &:hover { background-color: lighten($screen-color, 5%); } } Colar
apenas em desktop ▣ Estilo 3D apenas em desktop ▣ Adicionar profundidade ▣ Tornar profundidade mais perceptível ▣ Finalizar efeito 3D ▢ Fonte com visual 8-bit ▣ Google Fonts ▣ Importar fonte ▣ Usar fonte no CSS ▢ Ajustar tamanho css/_pokemon.scss .pokemon { background-color: $screen-color; font-family: 'Press Start 2P', cursive; font-size: 14px; &:hover { background-color: lighten($screen-color, 5%); } }
require('jquery'); class PokemonView { constructor(attrs) { this.pokemon = attrs.pokemon; this.$element = $('<div/>'); this.$element.addClass('pokemon'); } render() { var url = 'https://img.pokemondb.net/sprites/black-white/normal/blaziken.png'; var $pokemonImage = $('<img/>'); $pokemonImage.addClass('pokemon-image'); $pokemonImage.attr('src', url); var $pokemonName = $('<div/>'); $pokemonName.addClass('pokemon-name'); $pokemonName.append(this.pokemon.name); this.$element.append($pokemonImage); this.$element.append($pokemonName); } } module.exports = PokemonView; js/views/PokemonViews.js cria uma tag de imagem mostrando a imagem da URL } cria uma tag div com o nome do Pokémon dentro } adiciona a imagem e o nome ao elemento da view }
de rolagem ▢ Regular tamanho da imagem adiciona barra de rolagem caso ouver overflow/vazamento css/_pokemon.scss .pokemon { background-color: $screen-color; font-family: 'Press Start 2P', cursive; font-size: 14px; height: 80px; padding: 5px; &:hover { background-color: lighten($screen-color, 5%); } .pokemon-image { height: 100%; } } deixa a altura de cada linha fixa em 80px deixa a altura da imagem igual a do elemento pai. No caso, a linha seletor de elemento com class pokemon-image dentro de pokemon
de rolagem ▣ Regular tamanho da imagem ▢ Deixar imagem e nome do Pokémon lado a lado adiciona barra de rolagem caso ouver overflow/vazamento css/_pokemon.scss .pokemon { background-color: $screen-color; font-family: 'Press Start 2P', cursive; font-size: 14px; height: 80px; padding: 5px; &:hover { background-color: lighten($screen-color, 5%); } .pokemon-image { float: left; height: 100%; } .pokemon-name { float: left; } } a imagem flutua para a esquerda para que caiba o nome ao lado nome flutua para o lado da imagem
de rolagem ▣ Regular tamanho da imagem ▣ Deixar imagem e nome do Pokémon lado a lado ▢ Ajustar posicionamento do nome do Pokémon adiciona barra de rolagem caso ouver overflow/vazamento css/_pokemon.scss .pokemon { background-color: $screen-color; font-family: 'Press Start 2P', cursive; font-size: 14px; height: 80px; padding: 5px; &:hover { background-color: lighten($screen-color, 5%); } .pokemon-image { float: left; height: 100%; } .pokemon-name { float: left; margin-left: 10px; margin-top: 25px; } } cria um espaço de 10px do lado esquerdo e de 25px acima, empurrando para direita e para baixo }
de rolagem ▣ Regular tamanho da imagem ▣ Deixar imagem e nome do Pokémon lado a lado ▣ Ajustar posicionamento do nome do Pokémon ▢ Usar a imagem correta para cada Pokémon var $ = require('jquery'); class PokemonView { constructor(attrs) { this.pokemon = attrs.pokemon; this.$element = $('<div/>'); this.$element.addClass('pokemon'); } render() { var url = 'https://img.pokemondb.net/sprites/black-white/normal/blaziken.png'; var $pokemonImage = $('<img/>'); $pokemonImage.addClass('pokemon-image'); $pokemonImage.attr('src', url); var $pokemonName = $('<div/>'); $pokemonName.addClass('pokemon-name'); $pokemonName.append(this.pokemon.name); this.$element.append($pokemonImage); this.$element.append($pokemonName); } } module.exports = PokemonView; js/views/PokemonViews.js repare que esta imagem tem o nome do Pokémon na URL :)
de rolagem ▣ Regular tamanho da imagem ▣ Deixar imagem e nome do Pokémon lado a lado ▣ Ajustar posicionamento do nome do Pokémon ▢ Usar a imagem correta para cada Pokémon class Pokemon { constructor(info) { this.name = info.name; } getImage() { return `https://img.pokemondb.net/sprites/black-white/normal/${this.name}.png`; } } module.exports = Pokemon; js/models/Pokemon.js retorna a URL da imagem usando o nome do Pokémon
de rolagem ▣ Regular tamanho da imagem ▣ Deixar imagem e nome do Pokémon lado a lado ▣ Ajustar posicionamento do nome do Pokémon ▢ Usar a imagem correta para cada Pokémon retorna a URL da imagem usando o nome do Pokémon var $ = require('jquery'); class PokemonView { constructor(attrs) { this.pokemon = attrs.pokemon; this.$element = $('<div/>'); this.$element.addClass('pokemon'); } render() { var url = this.pokemon.getImage(); var $pokemonImage = $('<img/>'); $pokemonImage.addClass('pokemon-image'); $pokemonImage.attr('src', url); var $pokemonName = $('<div/>'); $pokemonName.addClass('pokemon-name'); $pokemonName.append(this.pokemon.name); this.$element.append($pokemonImage); this.$element.append($pokemonName); } } module.exports = PokemonView; js/views/PokemonViews.js usamos nosso novo método, com a imagem correta!
de rolagem ▣ Regular tamanho da imagem ▣ Deixar imagem e nome do Pokémon lado a lado ▣ Ajustar posicionamento do nome do Pokémon ▣ Usar a imagem correta para cada Pokémon ▢ Testar o novo método
API web? ▢ O que é uma API REST? www API REST /evolutions /pokemons /items /games /pokemons/<nome> /pokemons /pokemons /pokemons/<nome> /pokemons/<nome> GET GET POST PUT DELETE lista de todos pokémons dados de um único pokémon cria um novo pokémon atualiza um pokémon deleta um pokémon
"name": "bulbasaur" }, { "url": "http://pokeapi.co/api/v2/pokemon/2/", "name": "ivysaur" }, { "url": "http://pokeapi.co/api/v2/pokemon/3/", "name": "venusaur" } // outros 17 pokémons ocultados ], "next": "http://pokeapi.co/api/v2/pokemon/?offset=20" } Consumindo uma API de Pokémons ▣ O que é uma API web? ▣ O que é uma API REST? ▢ Pokéapi ▢ Recurso /pokemon http://pokeapi.co/api/v2/pokemon/
"name": "bulbasaur" }, { "url": "http://pokeapi.co/api/v2/pokemon/2/", "name": "ivysaur" }, { "url": "http://pokeapi.co/api/v2/pokemon/3/", "name": "venusaur" } // outros 17 pokémons ocultados ], "next": "http://pokeapi.co/api/v2/pokemon/?offset=20" } Consumindo uma API de Pokémons ▣ O que é uma API web? ▣ O que é uma API REST? ▢ Pokéapi ▢ Recurso /pokemon http://pokeapi.co/api/v2/pokemon/ array com os dados de cada pokémon parecido com a nossa PokemonList :) dados de um pokémon } URL para os dados apenas do pokémon URL para mais 20 pokémons (API paginada)
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▢ Lendo pokémons da API var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; for(var i = 0; i < infoArray.length; i++) { var pokemon = new Pokemon(infoArray[i]); this.items.push(pokemon); } } } module.exports = PokemonList; js/models/PokemonList.js recebemos a URL da página atual da API por parâmetro
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▢ Lendo pokémons da API var PokemonList = require('./models/PokemonList'); var pokemonsInfo = [ { name: 'pikachu' }, { name: 'blaziken' }, { name: 'lucario' } ]; var pokemons = new PokemonList(pokemonsInfo, { nextUrl: 'http://pokeapi.co/api/v2/pokemon/' }); module.exports = pokemons; js/pokemons.js passamos o objeto com o campo nextURL para o PokemonList
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▢ Lendo pokémons da API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; for(var i = 0; i < infoArray.length; i++) { var pokemon = new Pokemon(infoArray[i]); this.items.push(pokemon); } this.fetchNext(); } fetchNext() { return $.get(this.nextUrl).then((data) => { console.log(data); }); } } module.exports = PokemonList; js/models/PokemonList.js importamos o jQuery para usar a função de AJAX dele envia requisição AJAX para a URL e chama a função passando a resposta como parâmetro data chamamos aqui nosso novo método, só para teste :)
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▢ Lendo pokémons da API > npm run build:js # abrir index.html no navegador # abrir console do navegador # esperar a requisição AJAX terminar e verificar o console
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▢ Substituindo pokémons hardcoded pela API var PokemonList = require('./models/PokemonList'); var pokemonsInfo = [ { name: 'pikachu' }, { name: 'blaziken' }, { name: 'lucario' } ]; var pokemons = new PokemonList([], { nextUrl: 'http://pokeapi.co/api/v2/pokemon/' }); module.exports = pokemons; js/pokemons.js podemos remover esta lista daqui passamos um array vazio como lista inicial
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▢ Substituindo pokémons hardcoded pela API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; for(var i = 0; i < infoArray.length; i++) { var pokemon = new Pokemon(infoArray[i]); this.items.push(pokemon); } this.fetchNext(); } fetchNext() { return $.get(this.nextUrl).then((data) => { console.log(data); }); } } module.exports = PokemonList; js/models/PokemonList.js remover esta chamada de teste moveremos este bloco para cá
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▢ Substituindo pokémons hardcoded pela API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; } fetchNext() { return $.get(this.nextUrl).then((data) => { for(var i = 0; i < infoArray.length; i++) { var pokemon = new Pokemon(infoArray[i]); this.items.push(pokemon); } }); } } module.exports = PokemonList; js/models/PokemonList.js substituiremos a variável infoArray por data.results
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▢ Substituindo pokémons hardcoded pela API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; } fetchNext() { return $.get(this.nextUrl).then((data) => { for(var i = 0; i < data.results.length; i++) { var pokemon = new Pokemon(data.results[i]); this.items.push(pokemon); } }); } } module.exports = PokemonList; js/models/PokemonList.js nossa função retorna uma promise
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▣ Substituindo pokémons hardcoded pela API ▢ Renderizar só depois de recebermos os dados var $ = require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); pokemons.fetchNext().then(() => { pokemonListView.render(); $pokedex.append(pokemonListView.$element); }); js/index.js chama nossa função que carrega os pokémons por AJAX e renderiza só depois de receber a resposta
API web? ▣ O que é uma API REST? ▣ Pokéapi ▣ Recurso /pokemon ▣ Como consumiremos? ▢ Consumindo a API ▣ Lendo pokémons da API ▣ Substituindo pokémons hardcoded pela API ▣ Renderizar só depois de recebermos os dados ▢ Verificar no navegador > npm run build:js # abrir index.html no navegador # esperar a API carregar
= require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); var $loadMore = $('<button/>'); $loadMore.text('Load more'); pokemons.fetchNext().then(() => { pokemonListView.render(); $pokedex.append(pokemonListView.$element); $pokedex.append($loadMore); }); js/index.js cria botão escrito “Load more” } adicionamos botão após a lista de pokémons
novos pokémons pela API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; } fetchNext() { return $.get(this.nextUrl).then((data) => { for(var i = 0; i < data.results.length; i++) { var pokemon = new Pokemon(data.results[i]); this.items.push(pokemon); } this.nextUrl = data.next; }); } } module.exports = PokemonList; js/models/PokemonList.js atualiza a URL da próxima página da API
novos pokémons pela API var $ = require('jquery'); var PokemonView = require('./PokemonView'); class PokemonListView { constructor(attrs) { ... } loadNextPage() { return this.pokemonList.fetchNext().then((newPokemons) => { newPokemons.forEach((pokemon) => { var pokemonView = new PokemonView({ pokemon: pokemon }); pokemonView.render(); this.$element.append(pokemonView.$element); }); }); } render() { this.pokemonList.items.forEach((pokemon) => { var pokemonView = new PokemonView({ pokemon: pokemon }); pokemonView.render(); this.$element.append(pokemonView.$element); }); } } module.exports = PokemonListView; js/views/PokemonListViews.js ocultei o construtor para caber tudo na tela :) percorre cada novo pokémon carregado da API e adiciona na tela
novos pokémons pela API var $ = require('jquery'); var PokemonView = require('./PokemonView'); class PokemonListView { constructor(attrs) { ... } loadNextPage() { return this.pokemonList.fetchNext().then((newPokemons) => { this.appendPokemons(newPokemons); }); } appendPokemons(pokemons) { pokemons.forEach((pokemon) => { var pokemonView = new PokemonView({ pokemon: pokemon }); pokemonView.render(); this.$element.append(pokemonView.$element); }); } render() { this.appendPokemons(this.pokemonList.items); } } module.exports = PokemonListView; js/views/PokemonListViews.js método que recebe uma lista de pokémons e adiciona ela na view
novos pokémons pela API var $ = require('jquery'); var Pokemon = require('./Pokemon'); class PokemonList { constructor(infoArray, options) { this.items = []; this.nextUrl = options.nextUrl; } fetchNext() { return $.get(this.nextUrl).then((data) => { var newPokemons = []; for(var i = 0; i < data.results.length; i++) { var pokemon = new Pokemon(data.results[i]); newPokemons.push(pokemon); } this.items = this.items.concat(newPokemons); this.nextUrl = data.next; return newPokemons; }); } } module.exports = PokemonList; js/models/PokemonList.js adiciona cada novo pokémon da API no novo array
novos pokémons pela API ▢ Adicionando comportamento do botão var $ = require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); var $loadMore = $('<button/>'); $loadMore.text('Load more'); $loadMore.on('click', () => { pokemonListView.loadNextPage(); }); pokemons.fetchNext().then(() => { pokemonListView.render(); $pokedex.append(pokemonListView.$element); $pokedex.append($loadMore); }); js/index.js quando o botão é clicado, chama nossa função que carrega mais pokémons
novos pokémons pela API ▣ Adicionando comportamento do botão ▢ Bloqueando o botão enquanto carrega os dados var $ = require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); var $loadMore = $('<button/>'); $loadMore.text('Load more'); $loadMore.on('click', () => { $loadMore.attr('disabled', true); pokemonListView.loadNextPage().then(() => { $loadMore.attr('disabled', false); }); }); pokemons.fetchNext().then(() => { pokemonListView.render(); $pokedex.append(pokemonListView.$element); $pokedex.append($loadMore); }); js/index.js desabilita o botão quando ele é clicado habilita o botão novamente depois de carregado
novos pokémons pela API ▣ Adicionando comportamento do botão ▣ Bloqueando o botão enquanto carrega os dados ▢ Estilizando o botão ▢ Adicionar classe CSS ao botão var $ = require('jquery'); var pokemons = require('./pokemons'); var PokemonListView = require('./views/PokemonListView'); var $pokedex = $('.pokedex'); var pokemonListView = new PokemonListView({ pokemons: pokemons }); var $loadMore = $('<button/>'); $loadMore.text('Load more'); $loadMore.addClass('load-more'); $loadMore.on('click', () => { $loadMore.attr('disabled', true); pokemonListView.loadNextPage().then(() => { $loadMore.attr('disabled', false); }); }); pokemons.fetchNext().then(() => { pokemonListView.render(); $pokedex.append(pokemonListView.$element); $pokedex.append($loadMore); }); js/index.js adicionamos classe load-more ao botão
novos pokémons pela API ▣ Adicionando comportamento do botão ▣ Bloqueando o botão enquanto carrega os dados ▢ Estilizando o botão ▣ Adicionar classe CSS ao botão ▢ Criar css/_loadMore.scss e importar em style.scss @import 'variables'; @import 'pokedex'; @import 'pokemonList'; @import 'pokemon'; @import 'loadMore'; * { box-sizing: border-box; } css/style.scss
novos pokémons pela API ▣ Adicionando comportamento do botão ▣ Bloqueando o botão enquanto carrega os dados ▢ Estilizando o botão ▣ Adicionar classe CSS ao botão ▣ Criar css/_loadMore.scss e importar em style.scss ▢ Criar estilo do botão .load-more { width: 100%; border-radius: 5px; } css/_loadMore.scss largura de 100% e borda arredondada de raio 5px }
novos pokémons pela API ▣ Adicionando comportamento do botão ▣ Bloqueando o botão enquanto carrega os dados ▢ Estilizando o botão ▣ Adicionar classe CSS ao botão ▣ Criar css/_loadMore.scss e importar em style.scss ▣ Criar estilo do botão ▢ Ajustar posicionamento do botão .load-more { width: 100%; border-radius: 5px; margin-top: 10px; } css/_loadMore.scss css/_pokedex.scss .pokedex { height: 100%; width: 100%; background-color: $pokedex-color; padding: 15px; padding-bottom: 40px; # resto do arquivo ocultado para caber tudo aumentamos o espaçamento inferir para 40px adicionamos margem de 10px ao botão, que move ele 10px para baixo
novos pokémons pela API ▣ Adicionando comportamento do botão ▣ Bloqueando o botão enquanto carrega os dados ▣ Estilizando o botão ▣ Adicionar classe CSS ao botão ▣ Criar css/_loadMore.scss e importar em style.scss ▣ Criar estilo do botão ▣ Ajustar posicionamento do botão > npm run build:js > npm run build:css # abrir index.html no navegador