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))
    			}
    		}
    	}
    }
  • 刷新后不清除

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax