Estudios de casos de API de almacenamiento web



¡Buen dia amigos!

En este artículo, veremos un par de ejemplos sobre el uso de la API de almacenamiento web o el objeto de almacenamiento.

¿Qué vamos a hacer exactamente?

  • Aprenda a recordar el tiempo de reproducción del video.
  • Trabajaremos con el formulario de inicio de sesión de la página.
  • Escribamos la lógica de la lista de tareas.
  • Implementamos chat.
  • Dibuja una canasta para los bienes.

Entonces vamos.

Breve reseña


El objeto Almacenamiento se usa para almacenar datos en el lado del cliente y, en este sentido, actúa como una alternativa a las cookies. La ventaja del almacenamiento es el tamaño de almacenamiento (desde 5 MB, depende del navegador, cuando se excede el límite, se produce el error "QUOTA_EXCEEDED_ERR") y no hay necesidad de acceder al servidor. Un inconveniente importante es la seguridad: cuesta acceder a la página a un script malicioso y se pierde la escritura. Por lo tanto, se recomienda no almacenar información confidencial en Almacenamiento.

Para ser justos, vale la pena señalar que hoy en día existen soluciones más avanzadas para almacenar datos en el lado del cliente: esto es IndexedDB, Service Workers + Cache API, etc.

Puede leer sobre los trabajadores de servicio aquí .

La API de almacenamiento web incluye localStorage y sessionStorage. La diferencia entre ellos es el tiempo de almacenamiento de datos. En localStorage, los datos se almacenan permanentemente hasta que se eliminan "explícitamente" (ni recargar la página ni cerrarla da como resultado la eliminación de datos). El tiempo de almacenamiento de datos en sessionStorage, como su nombre lo indica, está limitado por la sesión del navegador. Como sessionStorage casi nunca se usa en la práctica, solo consideraremos localStorage.

¿Qué necesitas saber sobre localStorage?


  • Cuando se usa localStorage, se crea una representación del objeto Storage.
  • Los datos en localStorage se almacenan como pares clave / valor.
  • Los datos se almacenan como cadenas.
  • Los datos no están ordenados, lo que a veces conduce a su mezcla (como veremos con el ejemplo de la lista de tareas).
  • Cuando habilita el modo incógnito o privado en su navegador, puede ser imposible usar localStorage (depende del navegador).

localStorage tiene los siguientes métodos:

  • Storage.key (n): nombre de clave con índice n
  • Storage.getItem () - obtiene el artículo
  • Storage.setItem () - escribe un elemento
  • Storage.removeItem (): elimina un elemento
  • Storage.clear () - borrar almacenamiento
  • Storage.length - longitud de almacenamiento (número de elementos - pares clave / valor)

En la especificación, se ve así:

interface Storage {
    readonly attribute unsigned long length;
    DOMString? key(unsigned long index);
    getter DOMString? getItem(DOMString key);
    setter void setItem(DOMString key, DOMString value);
    deleter void removeItem(DOMString key);
    void clear();
};

Los datos se escriben en el almacenamiento de una de las siguientes maneras:

localStorage.color = 'deepskyblue'
localStorage[color] = 'deepskyblue'
localStorage.setItem('color', 'deepskyblue') //    

Puede obtener los datos de esta manera:

localStorage.getItem('color')
localStorage['color']

¿Cómo iterar sobre claves de almacenamiento y obtener valores?


//  1
for (let i = 0; i < localStorage.length; i++) {
    let key = localStorage.key(i)
    console.log(`${key}: ${localStorage.getItem(key)}`)
}

//  2
let keys = Object.keys(localStorage)
for (let key of keys) {
    console.log(`${key}: ${localStorage.getItem(key)}`)
}

Como señalamos anteriormente, los datos en el almacenamiento tienen un formato de cadena, por lo que existen algunas dificultades con la escritura de objetos, que se pueden resolver fácilmente utilizando el tándem JSON.stringify () - JSON.parse ():

localStorage.user = {
    name: 'Harry'
}
console.dir(localStorage.user) // [object Object]

localStorage.user = JSON.stringify({
    name: 'Harry'
})
let user = JSON.parse(localStorage.user)
console.dir(user.name) // Harry

Para interactuar con localStorage, hay un evento especial: el almacenamiento (onstorage), que ocurre cuando los datos se escriben / eliminan. Tiene las siguientes propiedades:

  • llave llave
  • oldValue - valor antiguo
  • newValue - nuevo valor
  • url: dirección de almacenamiento
  • storageArea: el objeto en el que ocurrió el cambio

En la especificación, se ve así:

[Constructor(DOMString type, optional StorageEventInit eventInitDict)]
    interface StorageEvent : Event {
    readonly attribute DOMString? key;
    readonly attribute DOMString? oldValue;
    readonly attribute DOMString? newValue;
    readonly attribute DOMString url;
    readonly attribute Storage? storageArea;
};

dictionary StorageEventInit : EventInit {
    DOMString? key;
    DOMString? oldValue;
    DOMString? newValue;
    DOMString url;
    Storage? storageArea;
};

¿LocalStorage permite la creación de prototipos?


Storage.prototype.removeItems = function() {
    for (item in arguments) {
        this.removeItem(arguments[item])
    }
}

localStorage.setItem('first', 'some value')
localStorage.setItem('second', 'some value')

localStorage.removeItems('first', 'second')

console.log(localStorage.length) // 0

¿Cómo verificar los datos en localStorage?


//  1
localStorage.setItem('name', 'Harry')

function isExist(name) {
    return (!!localStorage[name])
}

isExist('name') // true

//  2
function isItemExist(name) {
    return (name in localStorage)
}

isItemExist('name') // true

El navegador localStorage se puede encontrar aquí:



palabras suficientes, es hora de ponerse manos a la obra.

Ejemplos de uso


Recuerda el tiempo de reproducción del video


window.onload = () => {
    //   <video>
    let video = document.querySelector('video')
    
    //  localStorage   currentTime ( ),    video.currentTime
    if(localStorage.currentTime) {
        video.currentTime = localStorage.currentTime
    }
    
    //    video.currentTime,     localStorage.currentTime
    video.addEventListener('timeupdate', () => localStorage.currentTime = video.currentTime)
}

El resultado se ve así:



por ejemplo, inicie el video y detenga la reproducción en el tercer segundo. El tiempo que dejamos se almacena en localStorage. Para verificar esto, vuelva a cargar o cierre / abra la página. Vemos que el tiempo de reproducción de video actual sigue siendo el mismo.

Codepen

Github

Trabajamos con el formulario de inicio de sesión


El marcado se ve así:

<form>
    Login: <input type="text">
    Password: <input type="text">
    <input type="submit">
</form>

Tenemos un formulario y tres "entradas". Para la contraseña, usamos <input type = "text">, porque si usa el tipo correcto (contraseña), Chrome intentará guardar los datos ingresados, lo que nos impedirá implementar nuestra propia funcionalidad.

JavaScript:

//         
let form = document.querySelector('form')
let login = document.querySelector('input')
let password = document.querySelector('input + input')

//  localStorage  
//     
//    
if (localStorage.length != 0) {
    login.value = localStorage.login
    password.value = localStorage.password
}

//      "submit"
form.addEventListener('submit', () => {
    //      localStorage
    localStorage.login = login.value
    localStorage.password = password.value
    
    //    hello  world     , 
    //       "welcome"  
    if (login.value == 'hello' && password.value == 'world') {
        document.write('welcome')
    }
})

Tenga en cuenta que no "validamos" el formulario. Esto, en particular, le permite grabar líneas vacías como nombre de usuario y contraseña.

El resultado se ve así:



Introducimos palabras mágicas.



Los datos se escriben en localStorage y se muestra un saludo en la página.

Codepen

Github

Escribir la lógica de la lista de tareas


El marcado se ve así:

<input type="text"><button class="add">add task</button><button class="clear">clear storage</button>

<ul></ul>

Tenemos una "entrada" para ingresar una tarea, un botón para agregar una tarea a la lista, un botón para limpiar la lista y el almacenamiento, y un contenedor para la lista.

JavaScript:

//      
let input = document.querySelector('input')
input.focus()
//       
let addButton = document.querySelector('.add')
//    
let list = document.querySelector('ul')

//   localStorage  
if (localStorage.length != 0) {
    //     /
    for (let i = 0; i < localStorage.length; i++) {
        let key = localStorage.key(i)
        //   -  
        let template = `${localStorage.getItem(key)}`
        //    
        list.insertAdjacentHTML('afterbegin', template)
    }
    
    //      "close" -    
    document.querySelectorAll('.close').forEach(b => {
        //   
        b.addEventListener('click', e => {
            //    "li"
            let item = e.target.parentElement
            //    
            list.removeChild(item)
            //    localStorage
            localStorage.removeItem(`${item.dataset.id}`)
        })
    })
}

//       "Enter"
window.addEventListener('keydown', e => {
    if (e.keyCode == 13) addButton.click()
})

//           ""
addButton.addEventListener('click', () => {
    //   - 
    let text = input.value
    //  ,          "data-id"
    let template = `<li data-id="${++localStorage.length}"><button class="close">V</button><time>${new Date().toLocaleDateString()}</time> <p>${text}</p></li>`
    //   -   
    list.insertAdjacentHTML('afterbegin', template)
    //    localStorage
    localStorage.setItem(`${++localStorage.length}`, template)
    //   
    input.value = ''

    //           ""
    document.querySelector('.close').addEventListener('click', e => {
        //    -   
        let item = e.target.parentElement
        //    
        list.removeChild(item)
        //    localStorage
        localStorage.removeItem(`${item.dataset.id}`)
    })
})

//        ""
document.querySelector('.clear').onclick = () => {
    //  
    localStorage.clear()
    //    
    document.querySelectorAll('li').forEach(item => list.removeChild(item))
    //   
    input.focus()
}

El resultado se ve así: las



tareas agregadas a la lista se almacenan en localStorage como marcado listo para usar. Cuando la página se vuelve a cargar, la lista se forma a partir de los datos del almacenamiento (hay una mezcla, que se mencionó anteriormente).



Al eliminar una tarea de la lista haciendo clic en la marca de verificación verde, se elimina el par clave / valor correspondiente del repositorio.

Codepen

Github

Implementación de chat


El marcado se ve así:

<input type="text">
<button class="send">send message</button>
<button class="save">save chat</button>
<button class="clear">clear chat</button>

<div></div>

Tenemos una entrada para ingresar un mensaje, tres botones: para enviar un mensaje, para guardar correspondencia y para limpiar el chat y el almacenamiento, y también un contenedor para mensajes.

JavaScript:

//      
let input = document.querySelector('input')
input.focus()

//  
let sendButton = document.querySelector('.send')
let saveButton = document.querySelector('.save')
let clearButton = document.querySelector('.clear')

//  
let box = document.querySelector('div')

//      "messages"
if (localStorage.messages) {
    //  
    localStorage.messages
        .split('</p>,')
        .map(p => box.insertAdjacentHTML('beforeend', p))
}

//   
sendButton.addEventListener('click', () => {
    //   
    let text = document.querySelector('input').value
    //  
    let template = `<p><time>${new Date().toLocaleTimeString()}</time> ${text}</p>`
    //    
    box.insertAdjacentHTML('afterbegin', template)
    //   
    input.value = ''
    //    
    localStorage.message = template
})

//       "Enter"
window.addEventListener('keydown', e => {
    if (e.keyCode == 13) sendButton.click()
})

//   "storage"
window.addEventListener('storage', event => {
    //     "messages"
    //  
    if (event.key == 'messages') return
    //      null
    //     
    //     
    event.newValue == null ? clearButton.click() : box.insertAdjacentHTML('afterbegin', event.newValue)
})

//  
saveButton.addEventListener('click', () => {
    //  
    let messages = []
    //  
    document.querySelectorAll('p').forEach(p => messages.push(p.outerHTML))
    //    
    localStorage.messages = messages
})

//    
clearButton.addEventListener('click', () => {
    localStorage.clear()
    document.querySelectorAll('p').forEach(p => box.removeChild(p))
    input.focus()
})

El resultado se ve así: el



mensaje que se envía se escribe en localStorage.message. El evento "almacenamiento" le permite organizar el intercambio de mensajes entre pestañas del navegador.



Cuando se guarda un chat, todos los mensajes se escriben en localStorage.messages. Cuando se vuelve a cargar la página, se forma correspondencia a partir de los mensajes grabados.

Codepen

Github

Diseño de la cesta de la compra


No pretendemos crear una canasta completamente funcional, por lo que el código se escribirá "al estilo antiguo".

El diseño de un producto se ve así:

<div class="item">
    <h3 class="title">Item1</h3>
    <img src="http://placeimg.com/150/200/tech" alt="#">
    <p>Price: <span class="price">1000</span></p>
    <button class="add" data-id="1">Buy</button>
</div>

Tenemos un contenedor para los productos, el nombre, la imagen y el precio de los productos, así como un botón para agregar productos a la cesta.

También tenemos un contenedor para botones para mostrar el contenido de la canasta y vaciar la canasta y el almacenamiento y un contenedor para la canasta.

<div class="buttons">
    <button id="open">Cart</button>
    <button id="clear">Clear</button>
</div>
<div id="content"></div>

JavaScript:

//    
let itemBox = document.querySelectorAll('.item'),
    cart = document.getElementById('content');

//    localStorage
function getCartData() {
    return JSON.parse(localStorage.getItem('cart'));
}

//    
function setCartData(o) {
    localStorage.setItem('cart', JSON.stringify(o));
}

//    
function addToCart() {
    //       
    this.disabled = true;
    //        ,   
    let cartData = getCartData() || {},
        //    "Buy"
        parentBox = this.parentNode,
        // id 
        itemId = this.getAttribute('data-id'),
        //  
        itemTitle = parentBox.querySelector('.title').innerHTML,
        //  
        itemPrice = parentBox.querySelector('.price').innerHTML;
    // +1  
    if (cartData.hasOwnProperty(itemId)) {
        cartData[itemId][2] += 1;
    } else {
        // + 
        cartData[itemId] = [itemTitle, itemPrice, 1];
    }
    //    localStorage
    if (!setCartData(cartData)) {
        //   
        this.disabled = false;
    }
}

//    ""    "Buy"
for (let i = 0; i < itemBox.length; i++) {
    itemBox[i].querySelector('.add').addEventListener('click', addToCart)
}

//  
function openCart() {
    //    
    let cartData = getCartData(),
        totalItems = '',
        totalGoods = 0,
        totalPrice = 0;
    //    
    if (cartData !== null) {
        totalItems = '<table><tr><th>Name</th><th>Price</th><th>Amount</th></tr>';
        for (let items in cartData) {
            totalItems += '<tr>';
            for (let i = 0; i < cartData[items].length; i++) {
                totalItems += '<td>' + cartData[items][i] + '</td>';
            }
            totalItems += '</tr>';
            totalGoods += cartData[items][2];
            totalPrice += cartData[items][1] * cartData[items][2];
        }
        totalItems += '</table>';
        cart.innerHTML = totalItems;
        cart.append(document.createElement('p').innerHTML = 'Goods: ' + totalGoods + '. Price: ' + totalPrice);
    } else {
        //    
        cart.innerHTML = 'empty';
    }
}
//  
document.getElementById('open').addEventListener('click', openCart);

//  
document.getElementById('clear').addEventListener('click', () => {
    localStorage.removeItem('cart');
    cart.innerHTML = 'leared';
});

El resultado es el siguiente: los



productos seleccionados se registran en la tienda como un solo par clave / valor.



Cuando hace clic en el botón Carrito, los datos de localStorage se muestran en una tabla, se calcula el número total de productos y su valor.

Codepen

Github

Gracias por su atención.

All Articles