113.【Vue-细刷-04】
Vue-04
(二十四)、浏览器存储(WebStorage)
1.本地缓存(LocalStorage)
在我们没有登入唯品会之前的时候,我们搜索耳机和键盘。会在历史记录中给我们展示出:我们的搜索记录
前提是:没有开启无痕浏览的时候,才会显示我们的数据
查看浏览器缓存放到哪里了
(1). 模仿本地缓存-未用JSON转字符串
window API: 这里的key和value都只能是字符串
window.localStorage.setItem('name','jsxs'); // 左边是 key 右边是 value
1.存字符串可以
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <script> const btn=document.getElementById('btn1'); btn.onclick= ()=>{ window.localStorage.setItem('name','jsxs'); // 左边是 key 右边是 value } </script> </body> </html>
假如我们关闭这个页面的话,那么我们的缓存并不会因为我们关闭浏览器而清除换粗,除非我们清除浏览器缓存的时候,才会消失
2.存数组: 会给我们展开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <script> const btn = document.getElementById('btn1'); const arr = [1, 2, 3]; btn.onclick = () => { window.localStorage.setItem('name', arr); // 左边是 key 右边是 value } </script> </body> </html>
3.存对象:会出现错误
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <script> const btn = document.getElementById('btn1'); const arr = [1, 2, 3]; const obj={age:'52',sex:'30'} btn.onclick = () => { window.localStorage.setItem('name', obj); // 左边是 key 右边是 value } </script> </body> </html>
(2).模拟本地缓存-使用JSON转字符串
非字符串的数据尽量都转换为JSON数据、字符串的数据可以不用转换为JSON数据。
- 对象-转成JSON字符串之后就正常存储
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <script> const btn = document.getElementById('btn1'); const arr = [1, 2, 3]; const obj={age:'52',sex:'30'} btn.onclick = () => { window.localStorage.setItem('name', JSON.stringify(obj)); // 左边是 key 右边是 value } </script> </body> </html>
- 数组-转JSON字符串之后也能正常存储
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <script> const btn = document.getElementById('btn1'); const arr = [1, 2, 3]; const obj={age:'52',sex:'30'} btn.onclick = () => { window.localStorage.setItem('name', JSON.stringify(arr)); // 左边是 key 右边是 value } </script> </body> </html>
- 保存数据和浏览数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <button id="btn2">浏览数据</button> <script> const btn = document.getElementById('btn1'); const btn3 = document.getElementById('btn2'); const person={name:'jsxs',age:'52',sex:'30'} btn.onclick = () => { window.localStorage.setItem('person', JSON.stringify(person)); // 左边是 key 右边是 value } btn3.onclick = () => { const result=window.localStorage.getItem('person'); alert(result); } </script> </body> </html>
- 全部增删改
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>localStorage</title> </head> <body> <h1>localStorage</h1> <button id="btn1">保存数据</button> <button id="btn2">浏览数据</button> <button id="btn4">删除数据</button> <button id="btn5">清除数据</button> <script> const btn = document.getElementById('btn1'); const btn3 = document.getElementById('btn2'); const btn5 = document.getElementById('btn4'); const btn6 = document.getElementById('btn5'); const person = { name: 'jsxs', age: '52', sex: '30' } const person2 = { name: 'ckqn', age: '0', sex: '0' } // 添加存储 btn.onclick = () => { window.localStorage.setItem('person', JSON.stringify(person)); // 左边是 key 右边是 value window.localStorage.setItem('person2', JSON.stringify(person2)); // 左边是 key 右边是 value } // 浏览存储 btn3.onclick = () => { // 输出的是JSON字符串 const result = window.localStorage.getItem('person'); try { // JSON字符串转换为原生的 alert(JSON.parse(result)); } catch (error) { // 假如解析出错,那么清空该数据 alert(error.message) window.localStorage.removeItem('person') } } // 移除存储 btn5.onclick = () => { window.localStorage.removeItem('person'); } // 清除存储 btn6.onclick = () => { window.localStorage.clear(); } </script> </body> </html>
- localStorage的数据: 1.清除浏览器缓存记录 2.clear()清除数据。他不会随着页面的关闭而清除缓存,只有通过上面的两个方法才能清除。
这样做的好处就是: 用户访问的时候有一层缓存会访问的时候加快速度
2.会话缓存(Session Storage)
它会随着一个会话的开始而创建;随着会话的关闭而失效。也就是浏览器的开和关
(1).模拟会话缓存
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SessionStorage</title> </head> <body> <h1>SessionStorage</h1> <button id="btn1">保存数据</button> <button id="btn2">浏览数据</button> <button id="btn4">删除数据</button> <button id="btn5">清除数据</button> <script> const btn = document.getElementById('btn1'); const btn3 = document.getElementById('btn2'); const btn5 = document.getElementById('btn4'); const btn6 = document.getElementById('btn5'); const person = { name: 'jsxs', age: '52', sex: '30' } const person2 = { name: 'ckqn', age: '0', sex: '0' } // 添加存储 btn.onclick = () => { window.sessionStorage.setItem('person', JSON.stringify(person)); // 左边是 key 右边是 value window.sessionStorage.setItem('person2', JSON.stringify(person2)); // 左边是 key 右边是 value } // 浏览存储 btn3.onclick = () => { // 输出的是JSON字符串 const result = window.sessionStorage.getItem('person'); try { // JSON字符串转换为原生的 alert(JSON.parse(result)); } catch (error) { // 假如解析出错,那么清空该数据 alert(error.message) window.sessionStorage.removeItem('person') } } // 移除存储 btn5.onclick = () => { window.sessionStorage.removeItem('person'); } // 清除存储 btn6.onclick = () => { window.sessionStorage.clear(); } </script> </body> </html>
(2).会话缓存和本地缓存的区别
- 本地缓存不会随着浏览器的关闭而关闭;会话缓存会随着浏览器的关闭而关闭。
- 本地缓存清除只有两种方式;会话缓存关闭浏览器即可。
- 存储的内容一般支持 5~10MB(很大了)
(3).JSON转换与JSON解析
- xxx->转换为JSON字符串: JSON.stringify(xxx)
- JSON字符串解析为->原有的变量: JSON.parse(JSON.stringify(xxx))
- 假如说在JSON在解析的时候,解析的数据为null,那么返回值是 null值,而不是字符串。
3.todos案列_本地缓存版
(1).mounted和watch的区别
- mounted: 挂载的意思: 就是和浏览器并发运行。第一次初始化页面的时候就会挂载上去。
- wathc: 监视的意思:当监视的属性发生变化的时候,就会发生相应的变化。但不会在第一次初始化页面的时候监视到数据。我们只需要添加一个命令即可和mounted有一样的效果。
immediate: true, // 若immediate为true则handle会在初始化时就会调用一次,以后就看firstName的改变了
(2).本地缓存版本
我们只修改App.vue这个组件就可以了。其余的不用修改.
App.vue
基本思路我们使用:watch进行监视挂载到浏览器上。然后和data区域的数据进行交互目的是为了浏览缓存的数据,假如说解析的时候为null我们就将数组设置为空数组。假如说不为空且数据格式有问题,我们就将其给重置掉数据并将数组继续重置为空数组。
<template> <div> <div class="todo-container"> <div class="todo-wrap"> <!-- 1.头部 将父APP.VUE的addFather方法传递给子组件--> <Header :addFatherA="addFather"/> <!-- 2.列表 : 将父APP.VUE的todos数组传递给子组件--> <list :todosA="todos" :updateFatherA="updateFather" :deleteFatherA="deleteFather" /> <!-- 3.底部导航 --> <Footer :FooterTodos="todos" :updateAllFatherA="updateAllFather" :clearAllDoneFatherA="clearAllDoneFather" /> </div> </div> </div> </template> <script> // 1.引入组件 import Header from './components/Header.vue' import List from './components/List.vue' import Footer from './components/Footer.vue' export default { name:'App', // 目的是在浏览器VUE插件中的名字都是App不会被改变。 // 2.注册组件 components:{ Header, List, Footer }, data() { const json_arr=localStorage.getItem('arr_Object'); // 这里我们直接得到的是json数组 let parse_arr; // 常量必须复制、let和var不需要 try {// 有一种可能是用户修改了格式,出现错误。我们需要在这里进行捕获。 // 把json数组转换为字符串。如果里面的数据为空也会被try到但是 parse_arr=JSON.parse(json_arr) || []; //当解析的数据JSON.parse(json_arr)为空的时候,会调用空数组。否则不调用空数组 } catch (error) { alert('本地缓存的数据异常-请查看您的数据格式是否正确!!!') localStorage.removeItem('arr_Object') // 重置我们的数据 parse_arr=[] } return { todos:parse_arr } }, methods: { addFather(todoObj){ // 这个方法是对todos这个数组的尾部追加对象todoObj this.todos.unshift(todoObj) }, /* 利用id updateFather(id,doneA){ // 利用map遍历数组todos,获取到的分别是数组对象和对象坐标 this.todos=this.todos.map((value,index)=>{ if(id===value.id){ // 假如说子类传递过来的值和map遍历的值一样,那么就返回 所有的属性+修改后的值 return {...value,done:doneA} }else{ return value } }) } */ // 更新 updateFather(index,doneA){ this.todos[index].done=doneA }, // 删除 deleteFather(index){ // 根据坐标删除数据 this.todos.splice(index,1) }, // 全选或者不选 updateAllFather(doneOption){ // map():创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。 this.todos=this.todos.map((value)=>{ // 这个参数是遍历的单个对象 return {...value,done:doneOption} // 返回将done属性改编为doneOption的完整对象 }) }, // 清除已经已经勾选的 clearAllDoneFather(){ this.todos=this.todos.filter((value)=>{ // 假如说done值为false就不用过滤-保留,否则就需要过滤-不保留 return value.done===false }) } }, watch:{// 我们初步设想的是利用,mounted目的是一上来就挂载上去。但是webStorage数据不会随着新增能新增... immediate: true, // 若immediate为true则handle会在初始化时就会调用一次,以后就看firstName的改变了 todos(newValue,oldValue){ // 会接受到改变前的值和改变后的值 localStorage.setItem('arr_Object',JSON.stringify(newValue)); // 这里一定要转换为JSON字符串 } } } </script> <style> /*base*/ body { background: #fff; } .btn { display: inline-block; padding: 4px 12px; margin-bottom: 0; font-size: 14px; line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); border-radius: 4px; } .btn-danger { color: #fff; background-color: #da4f49; border: 1px solid #bd362f; } .btn-danger:hover { color: #fff; background-color: #bd362f; } .btn:focus { outline: none; } .todo-container { width: 600px; margin: 0 auto; } .todo-container .todo-wrap { padding: 10px; border: 1px solid #ddd; border-radius: 5px; } </style>
4.todos案列_深度监视
(1).发现问题
我们发现我们在勾选单个任务的时候,vue的done值是随着我们勾选变化而变化的但是localSroage本地缓存的数据是不会变化的。原因不是我们代码的问题,而是vue监视的问题。
这里我们勾选最下面的全部任务,vue和loacalStorage才会全部变化。
(2).原理探究
- 监视问题
我们通常所说的监视有以下两种形式:
- Vue自带的监视:比如在我们没有手动添加watch的情况下,更改某一个数据,Vue会监视到并且给我们改变。
Vue会自动给监视data中所有层次对象的属性
。 - Vue的watch手动写的监视。
Vue已经可以自动监视到数据了,为什么我们还要写watch呢?
- Vue默认能够监视到所有层次的属性,但Vue的监视它只做两件事情:“第一件事请: 帮我们更改数据”。“第二件事:帮我们更新模板,将页面更换为最新的” 。
- 我们自己写的watch监视,是因为Vue默认的监视完成不了我们所需要的业务逻辑,这就需要我们自己定义一个满足我们的业务需求的监视。
(3).深度监视和浅度监视
- 浅度监视(默认): 只能监视到数据的增加和删除,监视不到数据某一个属性内部的变化
- 深度监视:能监视到数据的增加和删除,也能监视的到数据某一个属性的变化。
- 深度监视
必须
需要用到watch的完整写法且加上一个属性: deep:true。
只有完整的监视方法才能使用到属性。所以深度监视需要用到完整监视方法
watch:{// 我们初步设想的是利用,mounted目的是一上来就挂载上去。但是webStorage数据不会随着新增能新增... todos:{ immediate: true, // 若immediate为true则handle会在初始化时就会调用一次,以后就看firstName的改变了 deep: true, //开启深度监视 handler(newValue,oldValue){ //假如data是方法旧值获取不到(旧址也是新值),假如data是对象就能获取到旧值 localStorage.setItem('arr_Object',JSON.stringify(newValue)); // 这里一定要转换为JSON字符串 } } }
<template> <div> <div class="todo-container"> <div class="todo-wrap"> <!-- 1.头部 将父APP.VUE的addFather方法传递给子组件--> <Header :addFatherA="addFather"/> <!-- 2.列表 : 将父APP.VUE的todos数组传递给子组件--> <list :todosA="todos" :updateFatherA="updateFather" :deleteFatherA="deleteFather" /> <!-- 3.底部导航 --> <Footer :FooterTodos="todos" :updateAllFatherA="updateAllFather" :clearAllDoneFatherA="clearAllDoneFather" /> </div> </div> </div> </template> <script> // 1.引入组件 import Header from './components/Header.vue' import List from './components/List.vue' import Footer from './components/Footer.vue' export default { name:'App', // 目的是在浏览器VUE插件中的名字都是App不会被改变。 // 2.注册组件 components:{ Header, List, Footer }, data() { // const json_arr=localStorage.getItem('arr_Object'); // 这里我们直接得到的是json数组 // let parse_arr; // 常量必须复制、let和var不需要 // try {// 有一种可能是用户修改了格式,出现错误。我们需要在这里进行捕获。 // // 把json数组转换为字符串。如果里面的数据为空也会被try到但是 // parse_arr=JSON.parse(json_arr) || []; //当解析的数据JSON.parse(json_arr)为空的时候,会调用空数组。否则不调用空数组 // } catch (error) { // alert('本地缓存的数据异常-请查看您的数据格式是否正确!!!') // localStorage.removeItem('arr_Object') // 重置我们的数据 // parse_arr=[] // } return { todos:[] } }, methods: { addFather(todoObj){ // 这个方法是对todos这个数组的尾部追加对象todoObj this.todos.unshift(todoObj) }, /* 利用id updateFather(id,doneA){ // 利用map遍历数组todos,获取到的分别是数组对象和对象坐标 this.todos=this.todos.map((value,index)=>{ if(id===value.id){ // 假如说子类传递过来的值和map遍历的值一样,那么就返回 所有的属性+修改后的值 return {...value,done:doneA} }else{ return value } }) } */ // 更新 updateFather(index,doneA){ this.todos[index].done=doneA }, // 删除 deleteFather(index){ // 根据坐标删除数据 this.todos.splice(index,1) }, // 全选或者不选 updateAllFather(doneOption){ // map():创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。 this.todos=this.todos.map((value)=>{ // 这个参数是遍历的单个对象 return {...value,done:doneOption} // 返回将done属性改编为doneOption的完整对象 }) }, // 清除已经已经勾选的 clearAllDoneFather(){ this.todos=this.todos.filter((value)=>{ // 假如说done值为false就不用过滤-保留,否则就需要过滤-不保留 return value.done===false }) } }, watch:{// 我们初步设想的是利用,mounted目的是一上来就挂载上去。但是webStorage数据不会随着新增能新增... todos:{ immediate: true, // 若immediate为true则handle会在初始化时就会调用一次,以后就看firstName的改变了 deep: true, //开启深度监视 handler(newValue,oldValue){ //假如data是方法旧值获取不到(旧址也是新值),假如data是对象就能获取到旧值 localStorage.setItem('arr_Object',JSON.stringify(newValue)); // 这里一定要转换为JSON字符串 } } } } </script> <style> /*base*/ body { background: #fff; } .btn { display: inline-block; padding: 4px 12px; margin-bottom: 0; font-size: 14px; line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); border-radius: 4px; } .btn-danger { color: #fff; background-color: #da4f49; border: 1px solid #bd362f; } .btn-danger:hover { color: #fff; background-color: #bd362f; } .btn:focus { outline: none; } .todo-container { width: 600px; margin: 0 auto; } .todo-container .todo-wrap { padding: 10px; border: 1px solid #ddd; border-radius: 5px; } </style>
watch监视 默认开启的是浅度监视并不是深度监视