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

文章目录

  • 📚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))
    			}
    		}
    	}
    }
    
  • 刷新后不清除
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【黑马程序员】C++文件操作

20240220 文章目录 文件操作背景文件分类操作文件的三大类 文本文件写文件写文件步骤文件打开方式代码示例 读文件读文件步骤代码示例 写二进制文件写二进制文件步骤代码示例 读二进制文件代码示例 文件操作 背景 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行…

TypeScript(三):TypeScript面向对象

TypeScript面向对象 类的定义 与JS不同的是&#xff0c;成员属性需要在前面进行提前声明 class Person{//需要在前面对成员变量进行声明name: string//声明的时候&#xff0c;可以对值进行初始化&#xff0c;初始化可以带有类型注解&#xff0c;也可以省略age 18//construc…

基于YOLOv7算法和Widerperson数据集的高精度实时行人检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法和Widerperson数据集的高精度实时行人检测系统可用于日常生活中检测与定位行人目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检…

3个密码学相关的问题

一、离散对数问题&#xff08;Discrete Logarithm Problem, DLP&#xff09; 问题描述&#xff1a;给定 有限阿贝尓群 G中的2个元素a和b&#xff0c;找出最小的正整数x满足&#xff1a;b a ^^ x &#xff08;或者证明这样的x不存在&#xff09;。 二、阶数问题&#xff08;O…

云服务器ECS价格表出炉——阿里云

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

[element] el-upload实现 “读取本地表格内容并上传“

需求: 通过表格一键导入数据 表格模板: 导入按钮: <el-uploadref"upload"class"filter-item"style"margin-left: 10px"action"/"accept".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.sp…

Open3D三维重建

原始点云&#xff1a; alpha_shape算法 import open3d as o3dpcd o3d.io.read_point_cloud("airplane_0001.pcd") mesh o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha0.1) o3d.visualization.draw_geometries([mesh], mesh_show_b…

相机图像质量研究(39)常见问题总结:编解码对成像的影响--运动模糊

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

我把ChatGPT部署到我的手机上

正常的大模型部署都是在服务器上的 但是最近我看到一个手机上可以运行的大模型 分享给大家 MiniCPM MiniCPM是基于 MLC-LLM 开发&#xff0c;将 MiniCPM 和 MiniCPM-V 在 Android 手机端上运行。 使用起来很简单&#xff0c;下载好安装包后 按照教程安装好 下载2个模型 一个是M…

C++拷贝构造函数与赋值运算符重载

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、拷贝构造函数 1.概念 在现实生活中&#xff0c;可能存在一个与你一样的自己&#xff0c;我们称其为双胞胎。 那在创…

虹科方案丨低负载ECU老化检测解决方案:CANCAN FD总线“一拖n”

来源&#xff1a;虹科汽车智能互联 虹科方案丨低负载ECU老化检测解决方案&#xff1a;CANCAN FD总线“一拖n” 原文链接&#xff1a;https://mp.weixin.qq.com/s/4tmhyE5hxeLFCiaeoRhlSg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #汽车总线 #ECU #CAN卡 导读 …

配置Python环境及job运行的虚拟环境

1、配置Jenkins的Python环境&#xff1a;Manage Jnekins-Global Tool Configuration-Python 2、安装pyenv插件 此插件会给每个job都创建一个虚拟Python环境 安装后&#xff0c;在job config-build中选择 virtualenv builder build job的时候会自动在/opt/jenkins(node主机的…

详解平面点云面积计算

部分代码展示&#xff1a; &#xff08;1&#xff09;利用格网法计算面积&#xff1a; //&#xff08;2&#xff09;测试使用格网法计算平面点云面积 void main() {char *inputpath "D:\\testdata\\data.txt";vector<pcl::PointXYZ> points ReadPointXYZIn…

vue的十大面试题详情

1 v-show与v-if区别 v-if与v-show可以根据条件的结果,来决定是否显示指定内容&#xff1a; v-if: 条件不满足时, 元素不会存在. v-show: 条件不满足时, 元素不会显示(但仍然存在). <div id"app"><button click"show !show">点我</but…

【动态规划专栏】专题二:路径问题--------6.地下城游戏

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

【PX4-AutoPilot教程-TIPS】Gazebo仿真环境昏暗的解决办法即Ubuntu系统安装NVIDIA显卡驱动方法

Gazebo仿真环境昏暗的解决办法即Ubuntu系统安装NVIDIA显卡驱动方法 分析原因手动安装方法&#xff08;推荐&#xff09;自动安装方法检查是否安装成功Gazebo仿真环境前后对比 分析原因 具体原因为&#xff1a;大多数情况是因为显卡性能不足&#xff0c;Gazebo自动关闭了灯光和…

线性规划求解点云最大内接圆

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 本期话题&#xff1a;利用线性规划求解点云最大内接圆 参考资料&#xff1a; Tschebyscheff approximation for the calculation of maximum inscribed minimum circ…

风云温商在湖北:黄卓仁会长的商业传奇

黄卓仁,一位来自柳市的传奇人物,他的人生就像一部精彩纷呈的商业传奇,充满了挑战与机遇。他是1966年出生的优秀民营企业家,也是一位充满激情与智慧的领导者。今天,让我们一起走进黄卓仁的世界,感受他那不凡的人生历程。 首先,让我们了解一下黄卓仁的基本情况。他是温州人,出生…

[极客大挑战2019]upload

该题考点&#xff1a;后缀黑名单文件内容过滤php木马的几种书写方法 phtml可以解析php代码&#xff1b;<script language"php">eval($_POST[cmd]);</script> 犯蠢的点儿&#xff1a;利用html、php空格和php.不解析<script language"php"&…

492. Construct the Rectangle(构造矩形)

问题描述 作为一位web开发者&#xff0c; 懂得怎样去规划一个页面的尺寸是很重要的。 所以&#xff0c;现给定一个具体的矩形页面面积&#xff0c;你的任务是设计一个长度为 L 和宽度为 W 且满足以下要求的矩形的页面。要求&#xff1a; 你设计的矩形页面必须等于给定的目标面…