存储内容大小一般支持 **5MB **左右(不同浏览器可能还不一样)
浏览器端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制
相关API
备注
localStorage
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>localStoragetitle>
head>
<body>
<h2>localStorageh2>
<button onclick="saveDate()">点我保存数据button><br/>
<button onclick="readDate()">点我读数据button><br/>
<button onclick="deleteDate()">点我删除数据button><br/>
<button onclick="deleteAllDate()">点我清空数据button><br/>
<script>
let person = {
name:"JOJO",
age:20
};
function saveDate() {
localStorage.setItem('msg', 'localStorage');
localStorage.setItem('person', JSON.stringify(person));
}
function readDate() {
console.log(localStorage.getItem('msg'));
const person = localStorage.getItem('person');
console.log(JSON.parse(person))
}
function deleteDate() {
localStorage.removeItem('msg');
localStorage.removeItem('person');
}
function deleteAllDate() {
localStorage.clear();
}
script>
body>
html>
sessionStorage
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>sessionStoragetitle>
head>
<body>
<h2>sessionStorageh2>
<button onclick="saveDate()">点我保存数据button><br/>
<button onclick="readDate()">点我读数据button><br/>
<button onclick="deleteDate()">点我删除数据button><br/>
<button onclick="deleteAllDate()">点我清空数据button><br/>
<script>
let person = {
name:"JOJO",
age:20
};
function saveDate() {
sessionStorage.setItem('msg', 'sessionStorage');
sessionStorage.setItem('person', JSON.stringify(person));
}
function readDate() {
console.log(sessionStorage.getItem('msg'));
const person = sessionStorage.getItem('person');
console.log(JSON.parse(person))
}
function deleteDate() {
sessionStorage.removeItem('msg');
sessionStorage.removeItem('person');
}
function deleteAllDate() {
sessionStorage.clear();
}
script>
body>
html>
使用本地存储优化Todo-List
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"/>
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
div>
div>
div>
template>
<script>
// 引入组件
import MyFooter from './components/MyFooter';
import MyHeader from './components/MyHeader';
import MyList from './components/MyList';
export default {
name:'App',
components:{
MyFooter,
MyHeader,
MyList
},
data() {
return {
// 从本地存储中获得数据,null就创建空数组[]
todos: JSON.parse(localStorage.getItem('todos')) || []
}
},
methods: {
// 添加一个todo
addTodo(todoObj) {
this.todos.unshift(todoObj);
},
// 勾选or取消勾选一个todo
checkTodo(id) {
this.todos.forEach((todo)=>{
if(todo.id === id) todo.done = !todo.done;
});
},
// 删除一个todo
deleteTodo(id) {
this.todos = this.todos.filter( todo => todo.id !== id )
},
// 全选or取消全选
checkAllTodo(done){
this.todos.forEach((todo)=>{
todo.done = done;
});
},
// 清除所有已经完成的todo
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
return !todo.done;
})
}
},
// 数据发生改变就放到本地存储中,注意深度侦听,以及JSON转化为字符串
watch: {
todos: {
deep:true,
handler(value) {
localStorage.setItem('todos', JSON.stringify(value));
}
}
}
}
script>
<style>
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>
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('atguigu',this.test);
}
src/App.vue
<template>
<div class="app">
<h1>{{ msg }},学生姓名是:{{ studentName }}h1>
<School :getSchoolName="getSchoolName"/>
<Student ref="student" @click.native="show"/>
div>
template>
<script>
// 引入组件
import Student from './components/Student.vue';
import School from './components/School.vue';
export default {
name:'App',
components:{
Student,
School
},
data() {
return {
msg:'你好啊!',
studentName:''
}
},
methods: {
getSchoolName(name) {
console.log('App收到了学校名:', name);
},
getStudentName(name,...params) {
console.log('App收到了学生名:', name, params);
this.studentName = name;
},
m1() {
console.log('demo事件被触发了!')
},
show() {
alert(123);
}
},
mounted() {
this.$refs.student.$on('atguigu', this.getStudentName);
// 绑定自定义事件 // this.$refs.student.$once('atguigu',this.getStudentName) // 绑定自定义事件(一次性)
}
}
script>
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
style>
src/components/Student.vue
<template>
<div class="student">
<h2>学生姓名:{{ name }}h2>
<h2>学生性别:{{ sex }}h2>
<h2>当前求和为:{{number}}h2>
<button @click="add">点我number++button>
<button @click="sendStudentlName">把学生名给Appbutton>
<button @click="unbind">解绑atguigu事件button>
<button @click="death">销毁当前Student组件的实例(vc)button>
div>
template>
<script>
export default {
name:'Student',
data() {
return {
name: "liqb",
sex: '男',
number:0
}
},
methods: {
add() {
console.log('add回调被调用了');
this.number++;
},
sendStudentlName() {
// 触发Student组件实例身上的atguigu事件
this.$emit('atguigu', this.name, 666, 888, 900);
// this.$emit('demo');
// this.$emit('click');
},
unbind() {
// 解绑
this.$off('atguigu') // 解绑一个自定义事件
// this.$off(['atguigu','demo']) // 解绑多个自定义事件
// this.$off() // 解绑所有的自定义事件
},
death() {
// 销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效
this.$destroy();
}
}
}
script>
<style lang="less" scoped>
.student{background-color: pink;padding: 5px;margin-top: 30px;}
style>
src/components/School.vue
<template>
<div class="school">
<h2 >学校地址:{{address}}h2>
<h2>学校名称:{{name}}h2>
<button @click="sendSchoolName">把学校名给Appbutton>
div>
template>
<script>
export default {
name:'School',
props: ['getSchoolName'],
data() {
return {
name: "莆田学院",
address: '福建莆田'
}
},
methods: {
sendSchoolName() {
this.getSchoolName(this.name);
}
}
}
script>
<style scoped>
.school{
background-color: skyblue;
}
style>
src/App.vue
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader @addTodo="addTodo"/>
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
<MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
div>
div>
div>
template>
<script>
// 引入组件
import MyFooter from './components/MyFooter';
import MyHeader from './components/MyHeader';
import MyList from './components/MyList';
export default {
name:'App',
components:{
MyFooter,
MyHeader,
MyList
},
data() {
return {
// 从本地存储中获得数据,null就创建空数组[]
todos: JSON.parse(localStorage.getItem('todos')) || []
}
},
methods: {
// 添加一个todo
addTodo(todoObj) {
this.todos.unshift(todoObj);
},
// 勾选or取消勾选一个todo
checkTodo(id) {
this.todos.forEach((todo)=>{
if(todo.id === id) todo.done = !todo.done;
});
},
// 删除一个todo
deleteTodo(id) {
this.todos = this.todos.filter( todo => todo.id !== id )
},
// 全选or取消全选
checkAllTodo(done){
this.todos.forEach((todo)=>{
todo.done = done;
});
},
// 清除所有已经完成的todo
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
return !todo.done;
})
}
},
// 数据发生改变就放到本地存储中,注意深度侦听,以及JSON转化为字符串
watch: {
todos: {
deep:true,
handler(value) {
localStorage.setItem('todos', JSON.stringify(value));
}
}
}
}
script>
<style>
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>
src/components/MyHeader.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
div>
template>
<script>
import {nanoid} from 'nanoid';
export default {
name: "Header",
data(){
return {
title:'' // 收集用户输入的title
}
},
methods: {
add(){
// 校验数据
if(!this.title.trim()) return alert('输入不能为空')
// 将用户的输入包装成一个todo对象
const todoObj = {
id: nanoid(),
title:this.title,
done:false
};
// 通知App组件去添加一个todo对象
this.$emit('addTodo', todoObj);
// 清空输入
this.title = '';
}
}
}
script>
<style scoped>
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
style>
src/components/MyFooter
<template>
<div class="todo-footer" v-show="total">
<label>
<input type="checkbox" v-model="isAll"/>
label>
<span>
<span>已完成{{doneTotal}}span> / 全部{{total}}
span>
<button class="btn btn-danger" @click="clearAll">清除已完成任务button>
div>
template>
<script>
export default {
name: "Footer",
props: ['todos'],
computed: {
// 总数
total() {
return this.todos.length;
},
// 已完成数
doneTotal() {
// 此处使用reduce方法做条件统计
return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);
},
// 控制全选框
isAll:{
// 全选框是否勾选
get(){
return this.doneTotal === this.total && this.total > 0;
},
// isAll被修改时set被调用
set(value){
this.$emit('checkAllTodo', value);
}
}
},
methods: {
clearAll() {
this.$emit('clearAllTodo');
}
}
}
script>
<style scoped>
.todo-footer {
height: 40px;
line-height: 40px;
padding-left: 6px;
margin-top: 5px;
}
.todo-footer label {
display: inline-block;
margin-right: 20px;cursor: pointer;
}
.todo-footer label input {
position: relative;
top: -1px;
vertical-align: middle;
margin-right: 5px;
}
.todo-footer button {
float: right;
margin-top: 5px;
}
style>