Web Storage API案例研究



朋友们,美好的一天!

在本文中,我们将介绍一些使用Web Storage API或Storage对象的示例。

我们到底要做什么?

  • 学习记住视频的播放时间。
  • 我们将使用页面登录表单。
  • 让我们编写任务列表的逻辑。
  • 我们实现聊天。
  • 画出一篮子商品。

所以走吧

简短评论


Storage对象用于在客户端存储数据,从这个意义上讲,它是cookie的替代方法。存储的优势在于存储大小(从5 MB开始,取决于浏览器,超过限制后,将引发错误“ QUOTA_EXCEEDED_ERR”),并且无需访问服务器。一个主要的缺点是安全性:它花费了恶意脚本才能访问页面,并且写入丢失。因此,强烈建议不要将机密信息存储在存储中。

公平地讲,值得注意的是,今天有更多高级解决方案用于在客户端存储数据-这是IndexedDB,Service Workers + Cache API等。

您可以在此处了解有关Service Worker的信息

Web存储API包括localStorage和sessionStorage。它们之间的区别是数据存储时间。在localStorage中,数据将永久存储,直到“显式”删除为止(重新加载页面或关闭页面均不会导致数据删除)。顾名思义,sessionStorage中的数据存储时间受浏览器会话限制。由于sessionStorage在实践中几乎从未使用过,因此我们仅考虑localStorage。

您需要了解什么有关localStorage的信息?


  • 使用localStorage时,将创建Storage对象的表示形式。
  • localStorage中的数据存储为键/值对。
  • 数据存储为字符串。
  • 数据未排序,有时会导致它们混合(如我们将在任务列表的示例中看到的那样)。
  • 在浏览器中启用隐身模式或私有模式时,可能无法使用localStorage(取决于浏览器)。

localStorage具有以下方法:

  • Storage.key(n)-索引为n的键名
  • Storage.getItem()-获取项目
  • Storage.setItem()-写一个项目
  • Storage.removeItem()-删除项目
  • Storage.clear()-清除存储
  • Storage.length-存储长度(元素数-键/值对)

在规范中,它看起来像这样:

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();
};

数据以下列方式之一写入存储:

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

您可以像这样获取数据:

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

如何遍历存储键并获取值?


//  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)}`)
}

如上所述,存储中的数据具有字符串格式,因此编写对象存在一些困难,可以使用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

为了与localStorage进行交互,有一个特殊事件-存储(存储),该事件在写入/删除数据时发生。它具有以下属性:

  • 键-键
  • oldValue-旧值
  • newValue-新值
  • url-存储地址
  • storageArea-发生更改的对象

在规范中,它看起来像这样:

[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是否允许原型设计?


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

如何检查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

您可以在这里找到localStorage浏览器:



足够多的话,该开始做生意了。

使用实例


记住视频播放时间


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)
}

结果如下所示:例如,



开始播放视频并在第三秒停止播放。我们离开的时间存储在localStorage中。要验证这一点,请重新加载或关闭/打开页面。我们看到当前的视频播放时间保持不变。

Codepen

Github

我们使用登录表格


标记如下所示:

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

我们有一个表格和三个“输入”。对于密码,我们使用<input type =“ text”>,因为如果您使用正确的类型(密码),Chrome会尝试保存输入的数据,这将阻止我们实现自己的功能。

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')
    }
})

请注意,我们不会“验证”表单。特别是,这允许您将空行记录为用户名和密码。

结果如下所示:



我们引入了魔术词。



数据被写入localStorage,并在页面上显示问候语。

Codepen

Github

编写任务列表的逻辑


标记如下所示:

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

<ul></ul>

我们具有用于输入任务的“输入”,用于将任务添加到列表的按钮,用于清除列表和存储的按钮以及用于列表的容器。

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()
}

结果如下所示:



添加到列表中的任务作为现成的标记存储在localStorage中。当页面被重新加载时,该列表由存储的数据形成(存在混合,如上所述)。



通过单击绿色复选标记从列表中删除任务,将从存储库中删除相应的键/值对。

Codepen

Github

聊天实施


标记如下所示:

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

<div></div>

我们有一个用于输入消息的输入,三个按钮:用于发送消息,用于保存信件以及用于清洁聊天和存储,以及用于存储消息的容器。

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()
})

结果如下所示:



正在发送消息被写入localStorage.message。“存储”事件使您可以组织浏览器选项卡之间的消息交换。



保存聊天后,所有消息都将写入localStorage.messages。重新加载页面时,将根据记录的消息形成对应关系。

Codepen

Github

购物篮布局


我们的目标不是创建一个功能齐全的篮子,因此代码将以“旧样式”编写。

一种产品的布局如下所示:

<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>

我们有一个用于存放货物的容器,货物的名称,图像和价格,以及用于将货物添加到购物篮的按钮。

我们还有一个用于显示篮子内容,清空篮子和存放物的按钮的容器,以及一个篮子的容器。

<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';
});

结果如下所示:



选定的产品作为单个键/值对记录在商店中。



当您单击“购物车”按钮时,来自localStorage的数据显示在一个表中,计算出商品总数及其价值。

Codepen

Github

感谢您的关注。

All Articles