No meu post anterior discorri um pouco sobre aspectos pessoais que envolveram a criação do meu site. Neste aqui vou dar uma olhada no aspecto mais técnico envolvendo o código. As tecnologias que utilizei no meu site foram muito simples, mas que deram a forma final a ele e, se bem utilizadas, são muito poderosas.
Pois bem, vamos começar pelo básico. Inicialmente, a web se deteve sob a estrutura básica de comunicação em textos por onde quer que se via. Foi obtida uma pequena evolução fazendo com que textos se interliguem com outros textos através de links. Esse formato foi nomeado "hypertexto" e sua linguagem associada o HTML: HyperText Markup Language.
O HTML é organizado através de tags que indicam ao navegador como formatar cada parte do site:
- As tags "h1" a "h6" são headers que possuem certo destaque pelo tamanho e/ou pelo "peso" da fonte;
- A tag "a" indica uma âncora, que seria uma orientação a outro link;
- A tag "p" indica um parágrafo;
- e por aí vai.
Temos também tags que indiquem seções do texto ou trechos que possuem significado especial, como "main", "head", "strong", "em". Essas tags fazem parte do conjunto do HTML semântico.
As tags, além de serem elementos indicativos para o navegador formatar a página, também possuem modificadores que são chamados de Atributos. Para os casos de uma tag "a", insiro um atributo "href" para indicar qual seria o link para aquela âncora, ou um atributo "src" para indicar o caminho de uma tag "img".
Nisso, a página HTML tem todo um conjunto de elementos (objetos) com nenhum ou vários atributos (propriedades). Essa é uma razão muito forte para que Javascript seja uma linguagem orientada a objetos e para que o CSS fosse construído através de identificadores.
Assim, seria mais fácil ao programador conseguir associar e referenciar cada elemento dentro dessas linguagens. E graças a essas duas compreensões (Orientação a Objetos e referenciação de elementos) que podemos entender mais a fundo como um site ou, mais especificamente, o meu site foi construído, especialmente no âmbito do Javascript.
Orientação à Objetos
Javascript é uma linguagem que é orientada a objetos até os ossos. Tudo com o que Javascript lida são objetos e tudo é encapsulado dentro de objetos, mas não do jeito que um Java, que também é orientado a objetos até os ossos, faz.
O primeiro encapsulamento que um código sofre de fato é o fato da janela de uma página web ser o objeto global. Todo o código que você faz no front-end da página está, querendo ou não, compreendido dentro do objeto window, e é por isso que, quando você coloca no console do navegador um comando como alert("hello"), pouco importa se você referencia o window ou não nele. De qualquer maneira, o comando já está encapsulado no objeto window.
É bom termos uma certa precaução nisso. O objeto Global no Javascript, tecnicamente, é o ambiente de execução do Js. No caso de execução em front-end, sempre será o objeto window. Todas as interações que Js rodar, vão rodar dentro do contexto da janela daquela página (exceto quando trabalhamos com Web Workers). Para NodeJs, o ambiente de execução é o próprio runtime.
Mas, então, o que seria um objeto? O objeto é uma entidade abstrata que possui propriedades e é capaz de realizar métodos. As propriedades seriam as características e os métodos o que o objeto é capaz de fazer. Para explicar melhor isso, vou dar o exemplo mais comum sobre objetos: um carro.
Pensando num modelo (uma abstração simplificada) do carro, consideremos que ele tem uma cor, um fabricante e uma potência de motor. Ele pode ligar, acelerar e frear. Cor, fabricante e potência de motor são as propriedades do carro, ou seja, informações que caracterizam e unificam esse objeto. Ligar, acelerar e frear são os seus métodos. Perceba que as propriedades são substantivos e os métodos são verbos.
Vamos supor que nosso modelo de carro é um Nissan verde com potência de 200cv. Partindo disso, vamos construir esse objeto dentro de Js:
let car = {
color = "verde";
custommer = "Nissan";
horsePower = 220;
this.powerOn = function (){
console.log("Carro ligado");
};
this.speedUp = function (){
console.log("Acelerando");
};
this.brake = function (){
console.log("Freando");
setTimeout( () => { console.log("parado") }, 3000);
};
}
Os métodos aqui são apenas ilustrativos para facilitar a compreensão. Com isso, construimos o objeto carro que a qualquer podemos referenciar. Por exemplo, para saber o fabricante do carro, basta chamar:
car.custommer
// "Nissan"
Para executar um método, basta chamar também:
car.powerOn()
Então sabemos como construir um objeto, porém temos carros de diversas cores, fabricantes e potências de motor, ou seja, temos uma classe de carros. Se para cada carros que tivéssemos que construir, fôssemos declarar esse monte de código, estaríamos enrolados, pois o código logo logo ficaria gigantesco.
Em Java, essa classe poderia ser declarada como uma classe mesmo, e, a partir dela, os novos objetos que fossem formados a partir dela herdariam sua característica. Javascript tem uma implementação de classes, porém ela não é uma linguagem class-style, e sim prototype-style. As implementações de objetos não são feitos a partir de classes e sim de protótipos. A implementação de classes da linguagem foi um grande frankenstein que fizeram na linguagem e que hoje em dia não tem como "desimplementar" devido ao uso dessas classes em diversos frameworks.
Ok, se o Javascript originalmente não tem implementação de classes, como podemos representar uma classe de objetos? Pense que, para reduzir um código, você pega blocos de código que foram declarados da mesma forma e transforma em uma função. Nessa mesma lógica, podemos declarar uma função construtora onde simplificaremos a construção de classes de objetos a uma linha de código para cada objeto.
Para o carro, seria da seguinte forma:
function car(color, custommer, horsePower){
this.color = color;
this.custommer = custommer;
this.horsePower = horsePower;
this.powerOn = function (){
console.log("Carro ligado");
};
this.speedUp = function (){
console.log("Acelerando");
};
this.brake = function (){
console.log("Freando");
setTimeout( () => { console.log("parado") }, 3000);
};
}
Assim, toda vez que for criar um novo objeto de carro, usaremos a keyword "new", dessa forma:
let nissan = new car("Verde", "Nissan", 220);
Muito mais simples, não? Os mesmos comandos para acessar propriedades e métodos descritos acima podem ser realizados, como "nissan.custommer", "nissan.powerUp()", etc.
Dito isso, temos uma compreensão básica e suficiente sobre objetos. No meu caso, implementei eles de forma mais explícita dentro da página de Projetos.
Repare que cada uma dessas divs não são iguais, mas guardam características em comum:
- Todas elas tem uma imagem
- Todas elas tem um título
- Todas elas tem uma descrição
- Ao passar o mouse por cima delas, se percebe que há um link de demonstração do projeto e um link para o código
Pois é, percebe que aqui se formou uma classe né?
Lá no código, referente à função que carrega essa página de projetos, tem uma declaração de Função Construtora assim:
function projectCell(name, img, descr, page, source){
this.name = name;
this.img = img;
this.descr = descr;
this.page = page;
this.source = source;
}
E para facilitar a inserção de informações, declaro todos os objetos em um array:
const projectArray = [
new projectCell("Jogo da velha", "images/tikTakToe.png", "Projeto de Jogo da Velha feito inteiramente em C, basta abrir a página e clicar em RUN", "https://onlinegdb.com/7hQFBUJ0S","https://github.com/TTTecnology/Jogo-da-Velha"),
new projectCell("Relógio Digital", images/digitalClock.png", "Relógio Digital moderno, imita a aparência de um rádio-relógio", projects/digitalClock/index.html", "https://github.com/TTTecnology/Digital-Clock"),
new projectCell("Gerador de Senhas", "images/geraSenha.png", "Gerador de senhas totalmente aleatório, baseado em charcodes e arrays", "projects/geraSenha/index.html","https://github.com/TTTecnology/Password-Generator")
]
Assim, inseri toda a parte do processamento dessas informações em um loop que vai iterar sobre cada um dos objetos contidos no array, criando os elementos necessários e anexando-os nos elementos pais.
Apesar de aqui eu utilizar a compreensão de objetos de forma mais explícita, o seu uso é feito por todo o código Javascript.
Por exemplo, preciso criar um elemento "img" via Javascript (ver mais detalhadamente o próximo tópico), tenho que declarar um atributo src e um atributo alt para poder compor esse elemento, bem como atribuir uma classe para aplicar CSS sobre este elemento específico. Nesse caso, estou acessando as propriedades do objeto e declarando valores sobre ela.
let imgCli = document.createElement("img");
imgCli.src = "images/linuxCLI.png";
imgCli.alt = "Linux Terminal";
imgCli.className = "icons";
Referenciando Elementos e os Criando Dinamicamente
Como será que trabalha um React ou um Vue da vida? No primeiro post afirmei que os mesmos servem para resolver problemas de escalabilidade e legibilidade do código Js que envolvem geração dinâmica de elementos e reusabilidade de componentes.
O primeiro contato de um iniciante em desenvolvimento web geralmente é com código HTML. Ele vai criando elemento por elemento direto no arquivo .html. Semanas depois ele aprende CSS e refatora aquele código HTML para aplicar CSS nele. Depois aprende Javascript, então, quando ele tem um contato com um framework que cria a página HTML para ele toda dentro do Javascript, acontece um certo estranhamento. Quando você vai no meu site e pede ao browser para abrir o código fonte, tudo o que você verá é isto:
<!doctype HTML>
<html>
<head>
<title>Eron Alves Dev</title>
<meta charset="UTF-16" />
<!--meta http-equiv="refresh" content="3" /-->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles/style.css">
</head>
<body>
<header>
<div id="logo">
<img src="images/myImage.jpg" />
<p>Eron Alves Developer</p>
</div>
<nav>
<span class="button clicked">
Página Principal
</span>
<span class="button" id="ads">
Projetos
</span>
<span class="button">
Blog
</span>
<span class="button">
Contatos
</span>
</nav>
<div id="border"></div>
</header>
<main>
<div id="changes">
</div>
</main>
<script src="scripts/script.js"></script>
</body>
</html>
Parece distoante não? Só parece. Acontece que Javascript tem funcionalidades muito interessantes para cuspir código html na página, e, inicialmente, uma página que não era para ter um único conteúdo, se torna uma página cheia de conteúdo e funcionalidades, colocando nas mãos do programador capacidades para fazer Single Page Apps. Isso se torna melhor ainda se o programador domina AJAX (Asynchronous Javascript And XML).
O primeiro problema disso, é, por onde começar?
Primeiro, você tem que ter uma div básica pela qual você pode referenciar ela no código Javascript e guardar essa referência na memória. Então, se o seu código html estiver assim:
<html>
<body>
<div>
</div>
</body>
</html>
Você tem que referenciar em seu código Js é aquela div no meio do body.
Para isso, iremos trabalhar muito com a API Document, que nos fornece métodos, tanto para referenciar elementos na página HTML, quando para criar esses elementos e associá-los.
Os métodos document.getElementById(), "".getElementByClassName(), "".querySelector(), "".querySelectorAll() e "".getElementByTagName() são os que devem ser usados nessa tarefa. Como no código de exemplo acima só tem um div, eu usaria um querySelector assim:
const pageDiv = document.querySelector("div");
A partir daí, já consigo associar elementos filhos a este elemento que referenciei na constante.
Para criar os elementos, são dois métodos que vão ser mais utilizados:
- document.createElement() = para criar o elemento com tag de abertura (e de fechamento quando se aplica);
- document.createTextNode() = para criar uma string que tem que ser colocada dentro da tag.
Então, vamos supor que no nosso código de exemplo queremos criar uma tag h1 que tenha o texto "Olá mundo!", e uma tag p com o texto "Página de teste". Podemos fazer da seguinte forma:
let h1 = document.createElement("h1");
let h1Text = document.createTextNode("Olá Mundo");
let p = document.createElement("p");
let pText = document.createTextNode("Página de teste");
Criamos o texto e as tags, mas faltou organizar isso. Para a organização, pode-se usar dois métodos:
- .appendChild() = Este permite anexar um elemento por vez, portanto uso mais para anexar um texto a um elemento.
- .append() = Este permite anexar vários elementos por vez, portanto uso mais para fazer o anexo final.
Então, iremos organizar o código acima e inserir ele dentro da página, assim:
h1.appendChild(h1Text);
p.appendChild(pText);
pageDiv.append(h1, p);
Atenção: não se esqueça de referenciar seu script em sua página HTML!!!
Seguindo a recomendação acima, nosso código HTML estará assim:
<html>
<body>
<div>
</div>
</body>
<script src="script.js"></script>
</html>
Nosso código JS assim:
const pageDiv = document.querySelector("div");
let h1 = document.createElement("h1");
let h1Text = document.createTextNode("Olá Mundo");
let p = document.createElement("p");
let pText = document.createTextNode("Página de teste");
h1.appendChild(h1Text);
p.appendChild(pText);
pageDiv.append(h1, p);
Resultado Final
É algo que é muito simples, porém muito poderoso, pelo qual a partir daí, você pode adicionar elementos a medida que há ações do usuário sobre a página. Essas ações são capturadas pelos event handlers, como por exemplo, um clique, uma passada de mouse, uma tecla apertada, etc. Para refazer o conteúdo da página, basta definir o conteúdo da div referenciada lá no começo para uma string vazia, assim:
pageDiv.innerHTML = "";
Apesar dos elementos ainda estarem na memória, a página toda irá se apagar, e um novo conteúdo pode ser anexado nela. Isso é o básico para fazer um Single Page App com Javascript puro.
Outras técnicas
Antes de finalizar este post, quero dar uma pequena pincelada em técnicas que usei em dois elementos da minha página.
Mudando um painel de tempos em tempos
Este painel aqui está programado para mudar de 4 em 4 segundos:
Os dados estão em um array de objetos contendo nome e imagem do projeto. Usando o método window.setInterval(), você introduz um tic que vai gerar um ID (que pode ser armazenada em uma variável, caso queira parar o intervalo de execução) que periodicamente vai executar uma função.
let intervalChange;
function changing(){
body.remove();
projTitle.remove();
projTitle = 0;
projTitle = document.createElement("p");
let j = Math.floor(Math.random()*3);
let textPTitle = projectArray[j].title;
projTitle.appendChild(document.createTextNode(textPTitle));
projImg.alt = projectArray[j].title;
projImg.src = projectArray[j].img;
projImg.className = "showroom";
body.append(projTitle,projImg);
asideContent[i].append(body);
}
changing();
if (!intervalChange){
intervalChange = setInterval(changing, 4000);
}
No caso, a mudança dos elementos é feita via remoção e readição dos elementos, utilizando os métodos para geração dinâmica de elementos vistos anteriormente e também Element.remove.
Divs que aparecem quando o mouse está em cima do elemento
Na página de projetos, quando você passa o mouse por cima de uma das células dos projetos, aparece um quadro branco transparente com links para o código e para a demonstração do projeto.
Isso tem que ser feito via Javascript e CSS.
Adicionar isso diretamente no elemento antes de gerá-lo no DOM, pelo que tentei, não dá muito certo, então o caminho a ser seguido é o inverso: anexar o elemento no DOM e, no final do código, após ele estar anexado, você captura o elemento para adicionar um gestor de eventos:
changeDiv.append(h3El, projectsDiv);
let cells = document.getElementsByClassName("projectCell");
for (let i = 0; i<cells.length; i++){
cells[i].addEventListener("mouseover", ()=>{
cells[i].getElementsByClassName("hiddenLinks")[0].style.visibility = "visible";
})
cells[i].addEventListener("mouseout", ()=>{
cells[i].getElementsByClassName("hiddenLinks")[0].style.visibility = "hidden";
})
}
Separei a célula aparente da célula não-aparente em duas divs diferentes. A célula não-aparente está organizada como filha da célula aparente. Para alinhar elas, utilizei o código CSS abaixo:
.projectCell{
width: 300px;
height: 500px;
padding: 7px;
margin: 10px;
position: relative;
}
.hiddenLinks{
visibility: hidden;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(200,200,200,0.60);
display: flex;
align-items: center;
}
Garantindo um tamanho relativo ao div filho, consegue-se um alinhamento e dimensionamento que irá corresponder de acordo com o tamanho do div pai.
Finalizando..
Demonstrei algumas técnicas que usei para construir meu site, e vejam que são técnicas simples. De certa forma, isso serve de motivação para que os iniciantes de hoje não desanimem, pois com alguns construtos básicos já se consegue fazer algo elegante e funcional, e que, talvez, no futuro, possa se tornar comercial.
Para isso, é fundamental aprender as bases. Não utilizei nenhum framework para construir tudo, foram linhas de código 100% Vanilla!
No próximo post irei falar sobre desafios de gerenciamento de projetos relevantes a construção de projetos pessoais, como o meu site.
Top comments (0)