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

文章目录

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

📚Todo-list 案例

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

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

🐇实现静态组件

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

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

    html 复制代码
    <!-- 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>
    html 复制代码
    <!-- 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关键部分

    html 复制代码
    <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关键部分

    html 复制代码
    <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关键部分

    html 复制代码
    <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关键部分

    html 复制代码
    <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关键部分

    html 复制代码
    <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>

  • 进一步完善 :添加完后输入框清空。

    js 复制代码
    add(e){
        // 将用户输入包装成为一个todo对象
        const todoObj = {id:nanoid(),title:e.target.value,done:false}
        this.addTodo(todoObj)
        e.target.value = ''
    }

  • 进一步完善 :输入框必须有输入才能提交,这里不借助event,而是通过v-model完成数据读取。

    html 复制代码
    <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定义)

      html 复制代码
      <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关键代码

    html 复制代码
    <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关键代码

    html 复制代码
    <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关键代码

    html 复制代码
    <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里加一个鼠标悬浮效果

    css 复制代码
    li:hover{
       background-color: #ddd 
    }
  • 让删除按钮悬浮出现 :结构里的内联stylestyle="display:none"删掉,添加悬浮条件(前边默认设置为none)

    css 复制代码
    li:hover button{
      display: block;
    }
  • 交互实现 :点击按钮,拿到id,把对应id的事件删除。

    • 这里依旧注意函数名称设置问题,不要用默认名称,会混乱会报错!
    • 依旧是App.vueItem.vue是爷爷对孙子的关系,相关传输要先给他爸List.vue,再由他爸给他(现阶段)

  • UserItem.vue关键代码

    html 复制代码
    <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关键代码

    html 复制代码
    <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关键代码

    html 复制代码
    <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的数量。
    html 复制代码
    <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关键代码

    html 复制代码
    <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关键代码

    html 复制代码
    <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了)。

    html 复制代码
    <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部分

    html 复制代码
    <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部分

    html 复制代码
    <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

    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里配套读取

    js 复制代码
    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))
    			}
    		}
    	}
    }
  • 刷新后不清除

相关推荐
小白小白从不日白13 分钟前
react hooks--useCallback
前端·react.js·前端框架
恩婧21 分钟前
React项目中使用发布订阅模式
前端·react.js·前端框架·发布订阅模式
mez_Blog22 分钟前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
珊珊而川31 分钟前
【浏览器面试真题】sessionStorage和localStorage
前端·javascript·面试
森叶41 分钟前
Electron 安装包 asar 解压定位问题实战
前端·javascript·electron
drebander44 分钟前
ubuntu 安装 chrome 及 版本匹配的 chromedriver
前端·chrome
软件技术NINI1 小时前
html知识点框架
前端·html
深情废杨杨1 小时前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS1 小时前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
markzzw1 小时前
我在 Thoughtworks 被裁前后的经历
前端·javascript·面试