Salta el contingut

Desenvolupament web dinàmic frontend amb javascript
Conceptes

Sessió 4: Objectes predefinits del llenguatge

Objectiu Sessió 4

L'objectiu d'aquesta 4a sessió serà la de treballar els diferents objectes permetent el control complert de la interfície.

Browser Object Model - BOM

Ja hem treballat el concepte de DOM (Document Object Model) a les sessions anteriors. De manera bàsica ens permet gestionar activament tots els elements web que conté la interfície generada pel codi HTML.

Tenim també una sèrie d’elements sota el model del navegador BOM (Browser Object Model) que permeten gestionar propietats i mètodes associats a la interfície, però no als elements web, com per exemple l'amplada de la finestra a on es mostra la web.

D’alguna manera tenim que l’objecte Window és el superior i per sota tenim, per exemple el document amb el concepte de DOM. Veiem-ho més complert:

graph TD;

    Window-->document;
    Window-->navigator;
    Window-->screen;
    Window-->history;
    Window-->location;
    Window-->console;

Utilitat

Javascript ens permet accedir directament a aquests objectes sense haver de passar per l’objecte window

window.screen.width
screen.width

L'objecte Window

Representa cada finestra oberta del navegador, i si el document conté frames, representa cada frame individual.

Permet obrir i tancar finestres, crear-ne de noves, moure-les i canviar-ne la mida, etc. També és l'objecte que gestiona els esdeveniments de temporització, que permeten executar codi donat un període de temps.

Utilitat

La variable global window està exposada al codi per defecte, per tant no cal escriue window. davant de cada propietat o mètode d'aquest objecte. Per exemple, és el mateix utilitzar window.innerWidth que directament innerWidth.

Algunes propietats de window a tenir en compte són:

propietat informació que retorna valor en aquest navegador
innerWidth Amplada interior de la finestra actual en píxels
innerHeight Alçada interior de la finestra actual en píxels
outerWidth Amplada exterior de la finestra actual en píxels, comptant menús i barres laterals
outerHeight Alçada exterior de la finestra actual en píxels, comptant menú superior, barra d'estat, etc.
scrollX Desplaçament horitzontal de la finestra en píxels (només lectura)
scrollY Desplaçament vertical de la finestra en píxels (només lectura)

Pàgines amb exemples basats en la posició de scroll

Demo de "scroll.js"

Web d'Apple Mac Studio

Nintendo Game Boy

L'objecte window també dona accés a l'emmagatzematge local a través de l'objecte Storage i les seves propietats localStorage i sessionStorage, que veurem més endavant.

Alguns mètodes de window a tenir en compte són:

mètode funció que realitza exemple
alert() Obre una finestra emergent amb un missatge Prova-ho
confirm() Obre una finestra emergent que demana confirmació a un missatge i retorna un booleà en funció de la resposta de l'usuari Prova-ho
prompt() Obre una finestra emergent amb un missatge que retorna la cadena introduida per l'usuari Prova-ho
print() Obre el diàleg d'impressió per la pàgina actual Prova-ho
scroll() Desplaça la finestra a una posició donada Prova-ho

Window (MDN)

L'objecte Document

Representa tot el contingut del document actual, on cada element és representat com un node que forma part del model d'objectes del document (DOM)

Conté subobjectes que representen els diferents tipus d'elements d'un document: formularis, enllaços, imatges, etc. i té propietats i mètodes per manipular qualsevol element del document (getElementById, write, etc.)

Referència

Document (MDN)

L'objecte Navigator

Conté informació sobre el navegador i la plataforma sobre la que s'està executant el codi JavaScript.

Permet per exemple identificar el tipus i versió del navegador i el sistema operatiu de treball. Gràcies a això es pot determinar si és necessari prendre alguna decisió que afecti al codi a executar, però cal tenir en compte que és un paràmetre modificable per l'usuari i per tant no sempre serà fiable.

propietat / mètode informació que retorna valor en aquest navegador
navigator.platform sistema operatiu
navigator.userAgent agent d'usuari
navigator.javaEnabled() Java habilitat?

Identificació del navegador

Per raons històriques de compatibilitat, tots els navegadors s'identifiquen com a Mozilla

Navigator (MDN)

L'objecte Screen

Conté informació sobre la pantalla del dispositiu que està utilitzant l'usuari.

És útil per poder adaptar la presentació de l'aplicació a la mida disponible, o per mostrar elements centrats a la pantalla.

propietat informació que retorna valor en aquest navegador
screen.width amplada de la pantalla en píxels
screen.height alçada de la pantalla en píxels
screen.colorDepth profunditat de color bits

Atenció!

La forma recomanada d'adaptar el contingut a la pantalla del dispositiu és utilitzant media queries de CSS.

Screen (MDN)

L'objecte History

Conté l'historial del navegador per la finestra o pestanya activa.

Per protegir la privacitat dels usuaris, no permet conèixer la URL de les adreces individuals, sinó només desplaçar-se per la llista i saber-ne la mida. S'utilitza principalment per poder recular una pàgina en el navegador sense necessitat d'especificar una adreça de destinació concreta.

propietat / mètode informació que retorna valor en aquest navegador
history.length número d'elements a l'historial
history.back() anar a la pàgina anterior Vés-hi
history.forward() anar a la pàgina següent Vés-hi
history.go( -n ) anar n pàgines enrere Vés 2 pàgines enrere

History (MDN)

L'objecte Location

Conté informació sobre la URL actual, i en pot extreure parts concretes com el domini, protocol o port.

Permet també recarregar la pàgina actual o carregar una pàgina nova.

propietat / mètode informació que retorna valor en aquest navegador
location.href URL completa de la pàgina actual
location.protocol Protocol que utilitza la URL
location.host Nom del servidor i port
location.hostname Domini de la URL
location.port Port la de URL, si en forma part
location.pathname Part corresponent a la ruta de la URL
location.search Paràmetres de la URL si n'hi ha, incloent el ?
location.hash Marcador dins la pàgina, incloent el #
location.reload() Recarrega la pàgina actual Recarrega
location.assign(url) Carrega la url indicada Carrega URL
location.replace(url) Carrega la url subtituint l'actual a l'historial de navegació Reemplaça URL

Propietat útil!

Si modifiquem el valor de location.href el document carregarà la nova pàgina. D'aquesta manera podem aconseguir el mateix comportament que en clicar un enllaç, però des de codi JavaScript i sense interacció per part de l'usuari.

Location (MDN)

L'objecte Console

L'objecte console proporciona accés a la consola de depuració dels navegadors. Els detalls de com funciona varien de navegador a navegador, però hi ha un conjunt de característiques que de facto són proporcionades generalment.

propietat / mètode informació o acció exemple
console.clear() Neteja la consola Console.clear()
console.log Escriu l'expressió a la consola Console.log

Funcionalitat molt útil!

Ens anirà molt bé usar-lo com a métode de depuració o seguiment del que fa un codi javascript

Console (MDN)

Controlem el temps

Sota l'objecte window tenim uns mètodes que ens permeten temporitzar esdeveniments o accions.

setInterval() Executa indefinidament una funció cada interval de mil·lisegons donat

function missatge() {
    console.log("Ha passat un segon");
}

// S'executarem la funció missatge cada segon indefinidament
let intervalMissatge = setInterval( missatge, 1000);

clearInterval() Cancel·la un setInterval() en progrés, sempre que l'haguem assignat a una variable:

clearInterval(intervalMissatge);

setTimeout() Executa una sola vegada una funció després d'un nombre de mil·lisegons donat

function missatge() {
    alert("Han passat cinc segons");
}

// S'executarem la funció missatge un sol cop després de 5 segons
let intervalMissatge = setTimeout( missatge, 5000);

clearTimeout() Cancel·la un setTimeout() en progrés, sempre que l'haguem assignat a una variable:

clearTimeout(intervalMissatge);

Els mètodes setInterval i setTimeout són intercanviables:

function missatge() {
    /// ...
    let temps = 1000;
    setTimeout(missatge, temps);
}

// setTimeout funcionant com un setInterval,
// es reinicia cada cop que acaba el temps
setTimeout(missatge, 1000);

Avantatge

La variable temps podria tenir diferents valor en funció de condicions del codi.

function missatge() {
    /// ...
    if (condicioFinal) clearInterval(interval);
}

// setInterval funcionant com un setTimeout,
// la funció determina si continua o l'aturem
let interval = setInterval(missatge, 1000);

Avantatge

Podem aturar el comptador en funció de condicions del codi cada cop que s'executa la funció.

Important

Els intervals de temps d'aquests dos mètodes no són exactes, ja que estan en funció del temps que necessiti la funció que es crida per executar-se. Si el temps necessari per executar la funció és major que l'interval de repetició establert, s'anirà acumulant un error de temps a cada execució. Si necessitem comptar temps exactes és millor utilitzar l'objecte Date.

requestAnimationFrame

requestAnimationFrame() és una funció de JavaScript que permet sincronitzar la teva animació amb la taxa de refresc del navegador, oferint un rendiment més suau i eficaç per a animacions gràfiques o canvis visuals continus al DOM.

Sintaxi
let requestID = requestAnimationFrame(callback);
  • callback: Una funció que s'executarà abans de pintar el següent frame. Rep com a argument un timestamp que representa el temps, en mil·lisegons, des que la pàgina es va carregar.
  • requestID: Un identificador únic que es pot utilitzar per cancel·lar l'animació amb cancelAnimationFrame(requestID).

Exemple

const box = document.getElementById("box");
let position = 0;

function animate(timestamp) {
    position += 1; // Incrementa la posició
    box.style.transform = translateX(${position}px);

    if (position < 300) {
        requestAnimationFrame(animate); // Demana el següent frame
    }
}

requestAnimationFrame(animate); // Inicia l'animació

Alguns objectes més 💡

JavaScript disposa d'una sèrie d'objectes predefinits i independents del navegador que podem utilitzar en tot moment, entre ells:

Math

Permet realitzar operacions matemàtiques. Conté una sèrie de constants matemàtiques (PI, E, etc.) que actuen com a propietats, així com diferents mètodes relacionats amb operacions matemàtiques.

Tingueu en compte que...

L'objecte Math no té constructor. És estàtic, per tant les seves propietats i mètodes es poden utilitzar directament sense crear-ne primer una instància.

Math (MDN) JavaScript Math Object (W3Schools) JavaScript Math Reference (W3Schools)

String

Permet manipular cadenes de text. Té una sola propietat (length) i diversos mètodes per operar sobre cadenes.

Tingueu en compte que...

El constructor d'objectes string no es sol utilitzar

let txt = new String("string");

és més eficient utilitzar-lo com a tipus de dades, i l'assignació crea l'objecte implícitament

let txt = "string";

String (MDN)

Date

Serveix per treballar amb dates i hores.

Per treballar amb l'objecte Date cal crear-ne una instància amb new indicant la data que volem representar. Si ometem els paràmetres ens retorna la data actual del sistema.

Podem representar qualsevol altra data utilitzant el format:

any, indexMes, dia, hora, minut, segon, mil·lisegon

Tingueu en compte que...

Només l'any i el mes són obligatoris:

new Date(any, indexMes)
new Date(any, indexMes, dia)
new Date(any, indexMes, dia, hora)
new Date(any, indexMes, dia, hora, minut)
new Date(any, indexMes, dia, hora, minut, segon)
new Date(any, indexMes, dia, hora, minut, segon, mil·lisegon)

Els camps omesos es consideren com: dia 1 del mes i hora 00:00:00.000

Important!

Els mesos es numeren amb un índex a partir de 0 (gener) i fins a 11 (desembre) Cal tenir present que hem de posar un número menys del que normalment correspondria al calendari

new Date();                    // Data i hora actuals
new Date(2010, 4);             // 01/05/2010  a les 00:00:00
new Date(2024, 11, 25);        // Dia de Nadal a les 00:00:00
new Date(2024, 0, 15, 23, 30); // 15/01/2024 a les 23:30:00

Date (MDN)

Canvas

Un canvas és un element HTML que representa una àrea d'imatge a la pàgina.

Amb javascript podem gestionar i manipular imatge de mapa de bits.

Abans de res caldrà tenir l'element HTML

<canvas id="myCanvas" width="300" height="150"></canvas>

Podrem accedir a aquest element i crear un contexte en 2d. tot seguit dibuixem

canvas (MDN)

Canvas

    <!doctype html>

    <html lang="ca">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Exemple 9</title>
        </head>

        <body>
          <canvas id="myCanvas" width="300" height="150"></canvas>
          <button>Dibuixa rectangle</button>

        <script>
          const boto  = document.querySelector("button");
          boto.addEventListener("click", function() {
            const myCanvas = document.getElementById("myCanvas");
            const ctx = myCanvas.getContext("2d");
            ctx.fillStyle = "red";
            ctx.fillRect(20, 20, 150, 100);
          });

        </script>

        </body>


    </html>
const myCanvas = document.getElementById("myCanvas");

const ctx = myCanvas.getContext("2d");

ctx.fillStyle = "red";
ctx.fillRect(20, 20, 150, 100);

SVG

Un SVG és un gràfic vectorial que podem inserir al nostre HTML.

El podem incloure i controlar amb javascript com si fos un element més del DOM i modificar els seus atributs dinàmicament.

Ho farem amb:

    element.setAttribute("atribut","valor")

SVG

    <svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
        <circle id="circle1" cx="50" cy="50" r="25" style="fill:red;" />
    </svg>

    <input type="button" value="Canviar Radi" onclick="changeRadius()" />
<script>
    function changeRadius() {
    document.getElementById("circle1").setAttribute("r", "50");
    }
</script>

Exemples

Exemple Rellotge

Tenim aquest resultat:

   <script>
       function actualitzaHora() {

        // guardem la data i hora actual a una variable
        let d = new Date()

        // guardem cada valor de l'hora (h:m:s) per separat
        let h = d.getHours().toString().padStart(2, "0")
        let m = d.getMinutes().toString().padStart(2, "0")
        let s = d.getSeconds().toString().padStart(2, "0")

        // cadena que conté tots els valors de l'hora amb els separadors
        let hora = h + ":" + m + ":" + s

        // escrivim la cadena amb l'hora dins de l'objecte HTML "rellotge"
        document.getElementById("rellotge").innerHTML = hora
    }

    // creem un temporitzador que invoca la funció "actualitzaHora" cada 1000 mil·lisegons (1s)
    setInterval( actualitzaHora, 1000 )

    // forcem l'actualització sense esperar el primer interval
    actualitzaHora()
   </script>  
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <title>Exemple</title>
        <style>
          body {
            background-color: lightgrey;
          }
          #rellotge {
            font-family: 'Montserrat', sans-serif;
            text-shadow: 2px 2px 5px rgba(0,0,0,0.3);
            font-weight: bold;
            font-size: 3em;
            padding: 0.25em 0.5em;
            border: 4px solid black;
            background-color: white;
            position: fixed;
            bottom: 10px;
            right: 10px;
          }

        </style>
      </head>
      <body>
          <span id="rellotge"></span>

        <script>
          function actualitzaHora() {

            // guardem la data i hora actual a una variable
            let d = new Date()

            // guardem cada valor de l'hora (h:m:s) per separat
            let h = d.getHours().toString().padStart(2, "0")
            let m = d.getMinutes().toString().padStart(2, "0")
            let s = d.getSeconds().toString().padStart(2, "0")

            // cadena que conté tots els valors de l'hora amb els separadors
            let hora = h + ":" + m + ":" + s

            // escrivim la cadena amb l'hora dins de l'objecte HTML "rellotge"
            document.getElementById("rellotge").innerHTML = hora
          }

          // creem un temporitzador que invoca la funció "actualitzaHora" cada 1000 mil·lisegons (1s)
          setInterval( actualitzaHora, 1000 )

          // forcem l'actualització sense esperar el primer interval
          actualitzaHora()
        </script>
      </body>
    </html>

Tenim un <span> que és on mostrarem el rellotge

Tenim una funció function actualitzaHora() on obtenim la data i hora actual let d = new Date()

Llavors obtenim exactament la hora, minut i segon

// guardem cada valor de l'hora (h:m:s) per separat
let h = d.getHours().toString().padStart(2, "0")
let m = d.getMinutes().toString().padStart(2, "0")
let s = d.getSeconds().toString().padStart(2, "0")

// cadena que conté tots els valors de l'hora amb els separadors
let hora = h + ":" + m + ":" + s

ja només ens queda mostrar-la modificant el codi HTML a dins de l'element Rellotge.

document.getElementById("rellotge").innerHTML = hora

Tot plegat la màgia radica a la funció de setInterval( actualitzaHora, 1000 ), que fa la crida a la funció actualitzaHora, justament cada segon (1000 ms).

p2-s4-exe-Rellotge.html p2-s4-exe-Rellotge.html :fontawesome-solid-download:

Exemple Scroll

Tenim aquest resultat:

   <script>
        const box = document.querySelector('#caixa')

        window.addEventListener("scroll", function (e) {
            let scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight)

            box.style.right = scrollPercentage * (window.innerWidth - 120) + "px"

        })
   </script>  
    <!DOCTYPE html>
    <html lang="ca">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Exemple scroll</title>
        <style>
            body {
                height: 5000px;
                color: white;
                background-image: url('media/leaves.jpg');
            }

            h1 {
                position: fixed;
                font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
            }

            #caixa {
                position: fixed;
                width: 100px;
                height: 100px;
                background-color: red;
                right: 0px;
                top: 100px;
            }
        </style>
    </head>

    <body>
        <h1>Fes scroll per veure l'animació del requadre</h1>

        <div id="caixa"></div>

        <script>
            const box = document.querySelector('#caixa')

            window.addEventListener("scroll", function (e) {
                let scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight)

                box.style.right = scrollPercentage * (window.innerWidth - 120) + "px"

            })
        </script>
    </body>

    </html>

Tenim un <div> que és on mostrarem la caixa

Obtenim l'element amb queryselector

    const box = document.querySelector('#caixa')

Llavors programem l'esdeveniment Scroll

window.addEventListener("scroll", function (e) {
    let scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight)

    box.style.right = scrollPercentage * (window.innerWidth - 120) + "px"

})

Calculem el percentatge segons la posició de l'scroll i l'alçada

Finalment modifiquem la posició de la caixa des de la posició dreta.

p2-s4-exe-Scroll.html p2-s4-exe-Scroll.html :fontawesome-solid-download: