Vue | (三)使用Vue脚手架(中)| 尚硅谷Vue2.0+Vue3.0全套教程

news2025/5/22 13:25:56

文章目录

  • 📚Todo-list 案例
    • 🐇组件化编码流程(通用)
    • 🐇实现静态组件
    • 🐇展示动态数据
    • 🐇交互
      • ⭐️添加一个todo
      • ⭐️todo勾选实现
      • ⭐️删除功能实现
      • ⭐️底部统计功能实现
      • ⭐️底部全选功能实现
      • ⭐️底部一键清除功能实现
  • 📚案例小结
  • 📚浏览器本地存储
  • 📚TodoList本地存储

学习链接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通,本文对应p70-p79,博客参考尚硅谷公开笔记,补充记录实操。

📚Todo-list 案例

🐇组件化编码流程(通用)

  1. 实现静态组件:抽取组件,使用组件实现静态页面效果。
  2. 展示动态数据
    • 数据的类型、名称是什么?
    • 数据保存在哪个组件?
  3. 交互——从绑定事件监听开始。

🐇实现静态组件

在这里插入图片描述

  • 组件名:不要和原有标签名冲突(不管大小写,例如Header),开发中也一般不用MyHeader,Vue鼓励采用UserHeade.vue类似命名。

  • 注册好先搭结构,链接好层级关系(关注地址的正确链接)

    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter}
    	}
    </script>
    
    <!-- UserList.vue -->
    <script>
        import UserItem from '../components/UserItem'
        export default {
            name:'UserList',
            components:{UserItem}
        }
    </script>
    
  • 样式套用

    • 先都放到App.vue里,然后再拆,先拆结构,再拆样式
    • 拆结构的时候,App.vue里的结构剪切后,要连带着补上标签,防忘。
    • 拆样式的时候,在特定vue对应样式可补上scoped,放冲突。
      在这里插入图片描述

在这里插入图片描述

🐇展示动态数据

  • 数据的类型、名称是什么? 一堆数据用数组,每个数据里的属性用对象。
    在这里插入图片描述
  • 数据保存在哪个组件? 那个组件要展示就给谁,即谁用给谁——UserList。
  • 重要】链接上数据发送:demo='xxx'和接收props:[demo]

  • UserList.vue关键部分
    <template>
        <ul class="todo-main">
            <UserItem v-for="todoObj in todos" :key="todoObj.id" :fasong="todoObj"></UserItem>
        </ul>
    </template>
    
    <script>
        import UserItem from '../components/UserItem.vue'
        export default {
            name:'UserList',
            components:{UserItem},
            data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            }
        }
    </script>
    
  • UserItem.vue关键部分
    <template>
        <li>
            <label>
                <input type="checkbox" :checked="fasong.done"/>
                <span>{{fasong.title}}</span>
            </label>
            <button class="btn btn-danger" style="display:none">删除</button>
        </li>
    </template>
    
    <script>
        export default {
            name:'UserItem',
            // 声明接收发送内容
            props:['fasong']
        }
    </script>
    
  • 目前的设置是数据都放List且暂时还都合理。
    在这里插入图片描述

🐇交互

⭐️添加一个todo

  • id自动生成借助nanoid
    在这里插入图片描述
  • 遇到的问题:按暂时的知识量,兄弟vue(header和list)之间的数据传输很难办——解决办法:把数据交给“爹”App.vue。具体通过爹提前给儿传一个函数(props也可以传函数),然后儿把数据借助函数传给爹实现。
    在这里插入图片描述在这里插入图片描述

  • UserList.vue关键部分

    <template>
        <ul class="todo-main">
            <UserItem v-for="todoObj in todos" :key="todoObj.id" :fasong="todoObj"></UserItem>
        </ul>
    </template>
    
    <script>
        import UserItem from '../components/UserItem.vue'
        export default {
            name:'UserList',
            components:{UserItem},
            props:['todos']
        }
    </script>
    
  • UserHeader.vue关键部分

    <template>
        <div class="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
        </div>
    </template>
    
    <script>
        import {nanoid} from 'nanoid'
        export default {
            name:'UserHeader',
            props:['addTodo'],
            methods:{
                add(e){
                    // 将用户输入包装成为一个todo对象
                    const todoObj = {id:nanoid(),title:e.target.value,done:false}
                    this.addTodo(todoObj)
                }
            }
        }
    </script>
    
  • App.vue关键部分

    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<UserHeader :addTodo="addTodo"></UserHeader>
    				<UserList :todos="todos"></UserList>
    				<UserFooter></UserFooter>
    			</div>
    		</div>
    	</div>
    </template>
    
    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter},
    		data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            },
    		methods:{
    			addTodo(todoObj){
    				this.todos.unshift(todoObj)
    			}
    		}
    	}
    </script>
    

在这里插入图片描述


  • 进一步完善:添加完后输入框清空。
    add(e){
        // 将用户输入包装成为一个todo对象
        const todoObj = {id:nanoid(),title:e.target.value,done:false}
        this.addTodo(todoObj)
        e.target.value = ''
    }
    

在这里插入图片描述


在这里插入图片描述

  • 进一步完善:输入框必须有输入才能提交,这里不借助event,而是通过v-model完成数据读取。
    <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:'UserHeader',
            props:['addTodo'],
            methods:{
                add(){
                    // 校验数据
                    if(!this.title) return alert('输入不能为空')
                    // 将用户输入包装成为一个todo对象
                    const todoObj = {id:nanoid(),title:this.title,done:false}
                    // 通知APP组件去添加一个todo对象
                    this.addTodo(todoObj)
                    // 清空输入
                    this.title = ''
                }
            }
        }
    </script>
    
    • 这时会出现以下警告,而且清空失效。在这里插入图片描述
    • 修改(给title定义)
      <script>
          import {nanoid} from 'nanoid'
          export default {
              name:'UserHeader',
              props:['addTodo'],
              data(){
                  return{
                      title:""
                  }
              },
              methods:{
                  add(){
                      // 校验数据
                      if(!this.title) return alert('输入不能为空')
                      // 将用户输入包装成为一个todo对象
                      const todoObj = {id:nanoid(),title:this.title,done:false}
                      // 通知APP组件去添加一个todo对象
                      this.addTodo(todoObj)
                      // 清空输入
                      this.title = ''
                  }
              }
          }
      </script>
      

在这里插入图片描述

在这里插入图片描述

  • 其他注意点:函数命名不能重复(addaddtodo)。

⭐️todo勾选实现

  • 现在可以勾选,但是vue实际的数据是没有变化的。
    在这里插入图片描述
  • 关键点
    • 数据在哪,关于数据的操作就在哪——在App.vue里定义函数。
    • App.vueItem.vue是爷爷对孙子的关系,相关传输要先给他爸List.vue,再由他爸给他(现阶段)。

  • UserItem.vue关键代码
    <template>
        <li>
            <label>
                <input type="checkbox" :checked="fasong.done" @change="handleCheck(fasong.id)"/>
                <span>{{fasong.title}}</span>
            </label>
            <button class="btn btn-danger" style="display:none">删除</button>
        </li>
    </template>
    
    <script>
        export default {
            name:'UserItem',
            // 声明接收发送内容
            props:['fasong','checkTodo'],
            methods:{
                handleCheck(id){
                    // 通知App组件将对应的todo对象的done值取反
                    this.checkTodo(id)
                }
            }
        }
    </script>
    
  • UserList.vue关键代码
    <template>
        <ul class="todo-main">
            <UserItem 
                v-for="todoObj in todos" 
                :key="todoObj.id" 
                :fasong="todoObj" 
                :checkTodo="checkTodo"
            ></UserItem>
        </ul>
    </template>
    
    <script>
        import UserItem from '../components/UserItem.vue'
        export default {
            name:'UserList',
            components:{UserItem},
            props:['todos','checkTodo']
        }
    </script>
    
  • App.vue关键代码
    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<UserHeader :addTodo="addTodo"></UserHeader>
    				<UserList :todos="todos" :checkTodo="checkTodo"></UserList>
    				<UserFooter></UserFooter>
    			</div>
    		</div>
    	</div>
    
    </template>
    
    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter},
    		data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            },
    		methods:{
    			// 数据在哪,对数据的操作就在哪
    			// 添加一个todo
    			addTodo(todoObj){
    				this.todos.unshift(todoObj)
    			},
    			// 勾选or取消勾选一个todo
    			checkTodo(id){
    				this.todos.forEach((todo)=>{
    					if(todo.id === id) todo.done = !todo.done
    				})
    			}
    		}
    	}
    </script>
    

在这里插入图片描述在这里插入图片描述


  • v-model实现:就是在上一个功能实现的基础上,忽略本功能实现的之前代码,只将:checked="fasong.done"改为v-model="fasong.done" ,但这里已经和视频有出入,即vue版本更新后,这个方法不可行,会报错(本质是props只读):
    在这里插入图片描述

⭐️删除功能实现

  • 在Item里加一个鼠标悬浮效果
    li:hover{
       background-color: #ddd 
    }
    
    在这里插入图片描述
  • 让删除按钮悬浮出现:结构里的内联stylestyle="display:none"删掉,添加悬浮条件(前边默认设置为none)
    li:hover button{
      display: block;
    }
    
    在这里插入图片描述
  • 交互实现:点击按钮,拿到id,把对应id的事件删除。
    • 这里依旧注意函数名称设置问题,不要用默认名称,会混乱会报错!
    • 依旧是App.vueItem.vue是爷爷对孙子的关系,相关传输要先给他爸List.vue,再由他爸给他(现阶段)

  • UserItem.vue关键代码

    <template>
        <li>
            <label>
                <input type="checkbox" :checked="fasong.done" @change="handleCheck(fasong.id)"/>
                <span>{{fasong.title}}</span>
            </label>
            <button class="btn btn-danger" @click="handleDelete(fasong.id)">删除</button>
        </li>
    </template>
    
    <script>
        export default {
            name:'UserItem',
            // 声明接收发送内容
            props:['fasong','checkTodo','deleteTodo'],
            methods:{
                // 勾选or取消勾选
                handleCheck(id){
                    // 通知App组件将对应的todo对象的done值取反
                    this.checkTodo(id)
                },
                // 删除
                handleDelete(id){
                    if(confirm('确定删除吗?')){
                        // 通知App组件删除
                        this.deleteTodo(id)
                    }
                }
            }
        }
    </script>
    
  • UserList.vue关键代码

    <template>
        <ul class="todo-main">
            <UserItem 
                v-for="todoObj in todos" 
                :key="todoObj.id" 
                :fasong="todoObj" 
                :checkTodo="checkTodo"
                :deleteTodo="deleteTodo"
            ></UserItem>
        </ul>
    </template>
    
    <script>
        import UserItem from '../components/UserItem.vue'
        export default {
            name:'UserList',
            components:{UserItem},
            props:['todos','checkTodo','deleteTodo']
        }
    </script>
    
  • App.vue关键代码

    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<UserHeader :addTodo="addTodo"></UserHeader>
    				<UserList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></UserList>
    				<UserFooter></UserFooter>
    			</div>
    		</div>
    	</div>
    
    </template>
    
    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter},
    		data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            },
    		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)=>{
    				// 	return todo.id !== id
    				// })
    				// 精简写法
    				this.todos = this.todos.filter(todo => todo.id != id)
    			}
    		}
    	}
    </script>
    

    在这里插入图片描述
    在这里插入图片描述

⭐️底部统计功能实现

  1. todos传给Footer,在App.vue添加<UserFooter :todos="todos"></UserFooter>
  2. UserFooter.vue
    • 读取todos.length作为全部数值显示。
    • 计算属性,算donetrue的数量。
    <template>
        <div class="todo-footer">
            <label>
                <input type="checkbox"/>
            </label>
            <span>
                <span>已完成{{doneTotal}}</span> / 全部{{todos.length}}
            </span>
            <button class="btn btn-danger">清除已完成任务</button>
        </div>
    </template>
    
    <script>
        export default {
            name:'UserFooter',
            props:['todos'],
            computed:{
                doneTotal(){
                    // 法一
                    // let i = 0
                    // this.todos.forEach((todo)=>{
                    //     if(todo.done) i++
                    // })
                    // return i
    
                    // 法二
                    return this.todos.reduce((pre,current)=> pre + (current.done ? 1 : 0),0)
                }
            }
        }
    </script>
    
    在这里插入图片描述

⭐️底部全选功能实现

  • 考虑实际情境的细节优化。
  • 同样也是对todos的操作写到App.vue
  • App.vue关键代码
    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<UserHeader :addTodo="addTodo"></UserHeader>
    				<UserList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></UserList>
    				<UserFooter :todos="todos" :checkAllTodo="checkAllTodo"></UserFooter>
    			</div>
    		</div>
    	</div>
    
    </template>
    
    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter},
    		data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            },
    		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)=>{
    				// 	return todo.id !== id
    				// })
    				// 精简写法
    				this.todos = this.todos.filter(todo => todo.id != id)
    			},
    			// 全选or取消全选
    			checkAllTodo(done){
    				this.todos.forEach((todo)=>{
    					todo.done = done
    				})
    			}
    		}
    	}
    </script>
    
  • UserFooter.vue关键代码
    <template>
        <div class="todo-footer" v-show="total">
            <label>
                <input type="checkbox" :checked="isAll" @change="checkAll"/>
            </label>
            <span>
                <span>已完成{{doneTotal}}</span> / 全部{{total}}
            </span>
            <button class="btn btn-danger">清除已完成任务</button>
        </div>
    </template>
    
    <script>
        export default {
            name:'UserFooter',
            props:['todos','checkAllTodo'],
            computed:{
                total(){
                    return this.todos.length
                },
                doneTotal(){
                    // 法一
                    // let i = 0
                    // this.todos.forEach((todo)=>{
                    //     if(todo.done) i++
                    // })
                    // return i
    
                    // 法二
                    return this.todos.reduce((pre,current)=> pre + (current.done ? 1 : 0),0)
                },
                isAll(){
                    return this.doneTotal === this.total && this.total > 0
                }
            },
            methods:{
                checkAll(e){
                    this.checkAllTodo(e.target.checked)
                }
            }
        }
    </script>
    

在这里插入图片描述


  • 优化UserFooter.vue:借助v-model及计算属性(之前v-model失效是因为绑到props了)。
    <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">清除已完成任务</button>
        </div>
    </template>
    
    <script>
        export default {
            name:'UserFooter',
            props:['todos','checkAllTodo'],
            computed:{
                total(){
                    return this.todos.length
                },
                doneTotal(){
                    return this.todos.reduce((pre,current)=> pre + (current.done ? 1 : 0),0)
                },
                isAll:{
                    get(){
                        return this.doneTotal === this.total && this.total > 0
                    },
                    set(value){
                        this.checkAllTodo(value)
                    }
                }
            }
        }
    </script>
    

⭐️底部一键清除功能实现

  • App.vue部分
    <template>
    	<div id="root">
    		<div class="todo-container">
    			<div class="todo-wrap">
    				<UserHeader :addTodo="addTodo"></UserHeader>
    				<UserList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></UserList>
    				<UserFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"></UserFooter>
    			</div>
    		</div>
    	</div>
    
    </template>
    
    <!-- App.vue -->
    <script>
    	import UserHeader from './components/UserHeader.vue'
    	import UserList from './components/UserList'
    	import UserFooter from './components/UserFooter'
    	
    	export default {
    		name:'App',
    		components:{UserHeader,UserList,UserFooter},
    		data(){
                return{
                    todos:[
                        {id:'001',title:'吃早饭',done:true},
                        {id:'002',title:'睡午觉',done:false},
                        {id:'003',title:'散散步',done:true},
                    ]
                }
            },
    		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)=>{
    				// 	return todo.id !== 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
    				})
    			}
    		}
    	}
    </script>
    
  • UserFooter.vue部分
    <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:'UserFooter',
            props:['todos','checkAllTodo','clearAllTodo'],
            computed:{
                total(){
                    return this.todos.length
                },
                doneTotal(){
                    return this.todos.reduce((pre,current)=> pre + (current.done ? 1 : 0),0)
                },
                isAll:{
                    get(){
                        return this.doneTotal === this.total && this.total > 0
                    },
                    set(value){
                        this.checkAllTodo(value)
                    }
                }
            },
            methods:{
                clearAll(){
                    this.clearAllTodo()
                }
            }
        }
    </script>
    
    在这里插入图片描述
    在这里插入图片描述

📚案例小结

  1. 组件化编码流程

    • 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
    • 实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
      • 一个组件在用:放在组件自身即可。
      • 一些组件在用:放在他们共同的父组件上(状态提升)。
    • 实现交互:从绑定事件开始。
  2. props适用于

    • 父组件 ==> 子组件 通信
    • 子组件 ==> 父组件 通信(要求父先给子一个函数)
  3. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

📚浏览器本地存储

  1. 浏览器的搜索历史就是借助了本地存储。

  2. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

  3. 浏览器端通过 Window.sessionStorageWindow.localStorage属性来实现本地存储机制。

  4. 相关API:

    • xxxxxStorage.setItem('key', 'value');:该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
    • xxxxxStorage.getItem('person');:该方法接受一个键名作为参数,返回键名对应的值。
    • xxxxxStorage.removeItem('key');:该方法接受一个键名作为参数,并把该键名从存储中删除。
    • xxxxxStorage.clear():该方法会清空存储中的所有数据。
  5. 备注:

    • SessionStorage存储的内容会随着浏览器窗口关闭而消失。
    • LocalStorage存储的内容,需要手动清除才会消失。
    • xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null。
    • JSON.parse(null)的结果依然是null。

  • localStorage.html
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>localStorage</title>
    	</head>
    	<body>
    		<h2>localStorage</h2>
    		<button onclick="saveData()">点我保存一个数据</button>
    		<button onclick="readData()">点我读取一个数据</button>
    		<button onclick="deleteData()">点我删除一个数据</button>
    		<button onclick="deleteAllData()">点我清空一个数据</button>
    
    		<script type="text/javascript" >
    			let p = {name:'张三',age:18}
    
    			function saveData(){
    				localStorage.setItem('msg','hello!!!')
    				localStorage.setItem('msg2',666)
    				localStorage.setItem('person',JSON.stringify(p))
    			}
    			function readData(){
    				console.log(localStorage.getItem('msg'))
    				console.log(localStorage.getItem('msg2'))
    				const result = localStorage.getItem('person')
    				console.log(JSON.parse(result))
    			}
    			function deleteData(){
    				localStorage.removeItem('msg2')
    			}
    			function deleteAllData(){
    				localStorage.clear()
    			}
    		</script>
    	</body>
    </html>
    
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
  • **localStorage.html**即对应部分API换成sessionStorage

📚TodoList本地存储

  • 目的:自添加事项刷新后不清除。
  • App.vue添加watch,同时data里配套读取
    export default {
    	name:'App',
    	components:{UserHeader,UserList,UserFooter},
    	data(){
            return{
                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)=>{
    			// 	return todo.id !== 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
    			})
    		}
    	},
    	watch:{
    		todos:{
    			// 开启深度监视
    			deep:true,
    			handler(value){
    				localStorage.setItem('todos',JSON.stringify(value))
    			}
    		}
    	}
    }
    
  • 刷新后不清除
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1459405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue报错,xxx is defined #变量未定义

vue.js:5129 [Vue warn]: Error in v-on handler: "ReferenceError: count is not defined" 浏览器将这个变量 当做全局变量了&#xff0c;事实上它只是实例中的变量 加上this指定&#xff0c;是vue实例中的变量

Android之Android.bp文件格式语法(一百八十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

代码随想录算法训练营day20

题目&#xff1a;530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先 参考链接&#xff1a;代码随想录 530.二叉搜索树的最小绝对差 思路&#xff1a;我一开始想到的方法是先生成中序序列&#xff0c;然后对相邻两项的差进行计算&#xff0c;取…

代码随想录刷题笔记-Day21

1. 二叉搜索树中的插入操作 701. 二叉搜索树中的插入操作https://leetcode.cn/problems/insert-into-a-binary-search-tree/给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。…

聊聊 Git SubModule(子模块)

比如在公司不同开发团队中&#xff0c;有一个基础共享库&#xff0c;同时被多个项目调用。若要保证基础共享库的动态更新&#xff0c;那么就需要把共享库独立为一个代码库&#xff0c;但是分别把共享库中的文件拷贝到各自的项目中会造成冗余&#xff0c;而且再次更新共享库就会…

提升认知水平和防止偏见浅谈

提升认知水平和防止偏见浅谈 《庄子外物》&#xff1a;井蛙不可语海&#xff0c;夏虫不可语冰。 不要跟井底的青蛙谈论大海&#xff0c;因为它的认知只有井底那么大&#xff0c;大海对于它来说是认知盲区&#xff1b;不要与夏虫去谈论冰雪&#xff0c;因为夏虫一生很短没有经历…

香港优才计划认可大学名单有哪些?武大/西安交大/哈工大/中南大学毕业生,能加名校30分吗?

关注香港优才的朋友应该知道&#xff0c;优才计划采用计分制&#xff0c;综合计分制下&#xff0c;有一个“名校”加分项&#xff0c;如果毕业院校在世界百强大学名单内&#xff0c;可以多加30分&#xff01; 但这个世界百强大学名单&#xff0c;可能有很多人不是很清楚&#x…

用冒泡排序实现快速排序(qsort函数),指针进阶实例

目录 1、qsort函数是什么 2、冒泡排序实现指针进阶 2.1 主函数 2.2 功能函数声明​编辑 2.3 my_qsort函数介绍 2.4 Swap函数 总结 1、qsort函数是什么 qsort函数是c语言自带的函数&#xff0c;其功能是实现快速排序。我们来看一下他的参数和返回值&#xff1a; 以上就是q…

代码随想录算法训练营DAY21 | 二叉树 (9)

一、LeetCode 669 修建二叉搜索树 题目链接&#xff1a;669.修建二叉搜索树https://leetcode.cn/problems/trim-a-binary-search-tree/description/ 思路&#xff1a;递归三部曲-定参数、返回值-定终止条件-定单层递归逻辑 class Solution {public TreeNode trimBST(TreeNode …

深度学习基础——卷积神经网络(一)

卷积操作与自定义算子开发 卷积是卷积神经网络中的基本操作&#xff0c;对于图像的特征提取有着关键的作用&#xff0c;本文首先介绍卷积的基本原理与作用&#xff0c;然后通过编写程序实现卷积操作&#xff0c;并展示了均值、高斯与sobel等几种经典卷积核的卷积效果&#xff…

HTML-介绍-MDN文档学习笔记

HTML-介绍 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 HTML-简介 MDN 文档引用&#xff1a; 就其核心而言&#xff0c;HTML 是一种相当简单的、由不同元素组成的标记语言&#xff0c;它可以被应用于文本片段&#xff0c;使文本在文档中具…

Security6.2 中的SpEL 表达式应用(权限注解使用)

最近学习若依框架&#xff0c;里面的权限注解涉及到了SpEL表达式 PreAuthorize("ss.hasPermi(system:user:list)")&#xff0c;若依项目中用的是自己写的方法进行权限处理&#xff0c; 也可以只用security 来实现权限逻辑代码&#xff0c;下面写如何用security 实现。…

[计算机网络]---UDP协议

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、端口号…

HarmonyOS - 实现多设备协同开发实战教程~

前言 现在随着个人设备越来越多&#xff0c;越来越需要多个设备之间相互感知和连接&#xff0c;设备和设备之间可以相互联动&#xff0c;形成互联互通的场景&#xff0c;而搭载HarmonyOS的设备恰好可以满足这一点 。下面通过开发一个HarmonyOS的多端分布式表白应用来实现设备之…

STM32_ESP8266 连接阿里云 操作图解

一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是&#xff1a;AT固件。连接阿里云需要&#xff1a;MQTT固件。 因此&#xff0c;我们需要给8266重新烧录 MQTT固件。 针对“魔女开发板&#xff0c;ESP8266模块烧录MQTT固件&#xff0c;图解教程如下&#xff1a; ESP8266 烧录 …

代码随想录算法训练营|二叉树总结

二叉树的定义&#xff1a; struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode():val(0),left(nullptr),right(nullptr){}TreeNode(int val):val(val),left(nullptr),right(nullptr){}TreeNode(int val,TreeNode* left,TreeNode* right):val(val),left(left),…

网工内推 | 证券公司急招网工,base上海,年薪50W

01 广发证券 招聘岗位&#xff1a;网络工程师 任职要求&#xff1a; 1、懂基础建设网络&#xff0c;虚拟化&#xff0c;或者服务器中任意一个都可以&#xff08;需资深&#xff09;2、985/211本硕 3、年龄最好35以下 薪资待遇&#xff1a; 1、工作时间9:00-17:00 2、根据资历…

思腾合力邀您共赴第二届世界元宇宙大会

由中国仿真学会、中国指挥与控制学会和北京理工大学共同主办&#xff0c;上海市嘉定区安亭镇人民政府和中国仿真学会元宇宙专业委员会承办的第二届世界元宇宙大会大会以“虚实相生、产业赋能”为主题&#xff0c;聚焦元宇宙关键技术发展的共性问题&#xff0c;交流元宇宙技术产…

Window系统GPT-SoVITS配置安装

GPT-SoVITS配置安装 GPT-SoVITS配置Python下载以及安装源文件安装依赖 运行整理在安装配置环境时遇到的报错总结 GPT-SoVITS配置 作者链接 Python下载以及安装 版本这里根据教程的版本走即可&#xff0c;这里不会安装python或者不会配置环境的参考我之前的文章 Python 3.9,…

C# GTS四轴运动控制器实例(固高科技步进电机不带编码器)

注&#xff1a;由于电机不带编码器&#xff0c;无法做home和当前位置信息读取&#xff01; 功能&#xff1a; 三个轴的点位运动&#xff1a;前进后退&#xff0c;并分别显示每个轴的移动脉冲数(可以换算为距离)&#xff01; 开发环境&#xff1a;VS2017 硬件设备&#xff1a;固…