• vue学习-07TodoList本地存储以及TodoList的自定义事件


    关于TodoList在上篇也简单介绍了,这篇,就是将TodoList与本地存储绑定起来,算是综合利用吧,在实际开发中我们均有涉及到灵活使用我们所学所敲的demo,这或许就是我们平时多敲demo然后实际开发中CV改造Demo吧。

    Todolist本地存储

    main.js

    //引入Vue组件
    import Vue from 'vue';
    
    //引入App组件
    import App from './App.vue';
    
    //关闭Vue生产提示信息
    Vue.config.productionTip=false;
    
    //创建Vue实例对象nm
    const vm = new Vue({
        el:'#app',
        render(h) {
            return h(App);
        }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    App.vue

    说来说起,其实就这段代码
    localStorage.setItem('todos',JSON.stringify(value));//将数据存储到本地缓存中,并监视其变化。

    <template>
        <div id="root">
            <div class="todo-container">
                <div class="todo-wrap">
                
                <MyHeader :addTodo="addTodo">MyHeader>
                
                
                <MyList 
                    :todos="todos" 
                    :checkTodo="checkTodo"
                    :todoDelete="todoDelete">
                MyList>
    
                
                <MyFooter 
                    :todos="todos"
                    :checkAllTodo="checkAllTodo"
                    :clearAllTodo="clearAllTodo">
                MyFooter>
                div>
            div>
        div>
    template>
    
    <script>
        //引入组件
        import MyHeader from './components/MyHeader.vue';
        import MyFooter from './components/MyFooter.vue';
        import MyList from './components/MyList.vue';
    
        export default {
            name:'App',
            components:{
                MyHeader,
                MyFooter,
                MyList
            },
            data() {
                return {
                    todos:JSON.parse(localStorage.getItem('todos')) || []//将本地缓存的字符串解释成js对象
                }
            },
            methods:{
                // 添加一个todo
                addTodo(todoObj){
                    console.log("我是组件App,我收到数据:",todoObj);
                    //this.todos.push(x);//将数据加入数组中
                    this.todos.unshift(todoObj);//将数据加入数组中
                },
                //勾选or取消一个todo
                checkTodo(id){
                    // for (let index = 0; index < this.todos.length; index++) {
                    //     if(this.todos[index].id===id){
                    //         this.todos[index].done=!this.todos[index].done;
                    //     }
                    // }
                    //使用forEach,注意:当foreach无法使用的使用可能是脚手架没有安装对应的js版本,需要运行:npm install core-js@3.6.4名
                    this.todos.forEach((todo)=>{
                        if (todo.id===id) {
                            todo.done=!todo.done;
                        }
                    });
                },
                //删除一个todo
                todoDelete(id){
                    //使用过滤器删除,需要运行npm install core-js@3.6.4命令才能使用filter过滤器
                    this.todos=this.todos.filter((todo)=>{
                        return todo.id!==id;
                    });
    
                    //传统的过滤删除方法
                    // for (let index = 0; index < this.todos.length; index++) {
                    //     if(this.todos[index].id===id){
                    //         this.todos.pop(index);
                    //     }
                    // }
                },
    
                //全选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));//将数据存储到本地缓存中,并监视其变化。
                    }
                }
            }
        }
    script>
    
    <style>
        /*base*/
        body {
            background: #fff;
        }
    
        .btn {
            display: inline-block;
            padding: 4px 12px;
            margin-bottom: 0;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
            border-radius: 4px;
        }
    
        .btn-danger {
            color: #fff;
            background-color: #da4f49;
            border: 1px solid #bd362f;
        }
    
        .btn-danger:hover {
            color: #fff;
            background-color: #bd362f;
        }
    
        .btn:focus {
            outline: none;
        }
    
        .todo-container {
            width: 600px;
            margin: 0 auto;
        }
    
        .todo-container .todo-wrap {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150

    MyHeader.vue

    <template>
        <div id="root">
            <div class="todo-container">
                <div class="todo-wrap">
                
                <MyHeader :addTodo="addTodo">MyHeader>
                
                
                <MyList 
                    :todos="todos" 
                    :checkTodo="checkTodo"
                    :todoDelete="todoDelete">
                MyList>
    
                
                <MyFooter 
                    :todos="todos"
                    :checkAllTodo="checkAllTodo"
                    :clearAllTodo="clearAllTodo">
                MyFooter>
                div>
            div>
        div>
    template>
    
    <script>
        //引入组件
        import MyHeader from './components/MyHeader.vue';
        import MyFooter from './components/MyFooter.vue';
        import MyList from './components/MyList.vue';
    
        export default {
            name:'App',
            components:{
                MyHeader,
                MyFooter,
                MyList
            },
            data() {
                return {
                    todos:JSON.parse(localStorage.getItem('todos')) || []//将本地缓存的字符串解释成js对象
                }
            },
            methods:{
                // 添加一个todo
                addTodo(todoObj){
                    console.log("我是组件App,我收到数据:",todoObj);
                    //this.todos.push(x);//将数据加入数组中
                    this.todos.unshift(todoObj);//将数据加入数组中
                },
                //勾选or取消一个todo
                checkTodo(id){
                    // for (let index = 0; index < this.todos.length; index++) {
                    //     if(this.todos[index].id===id){
                    //         this.todos[index].done=!this.todos[index].done;
                    //     }
                    // }
                    //使用forEach,注意:当foreach无法使用的使用可能是脚手架没有安装对应的js版本,需要运行:npm install core-js@3.6.4名
                    this.todos.forEach((todo)=>{
                        if (todo.id===id) {
                            todo.done=!todo.done;
                        }
                    });
                },
                //删除一个todo
                todoDelete(id){
                    //使用过滤器删除,需要运行npm install core-js@3.6.4命令才能使用filter过滤器
                    this.todos=this.todos.filter((todo)=>{
                        return todo.id!==id;
                    });
    
                    //传统的过滤删除方法
                    // for (let index = 0; index < this.todos.length; index++) {
                    //     if(this.todos[index].id===id){
                    //         this.todos.pop(index);
                    //     }
                    // }
                },
    
                //全选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));//将数据存储到本地缓存中,并监视其变化。
                    }
                }
            }
        }
    script>
    
    <style>
        /*base*/
        body {
            background: #fff;
        }
    
        .btn {
            display: inline-block;
            padding: 4px 12px;
            margin-bottom: 0;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
            border-radius: 4px;
        }
    
        .btn-danger {
            color: #fff;
            background-color: #da4f49;
            border: 1px solid #bd362f;
        }
    
        .btn-danger:hover {
            color: #fff;
            background-color: #bd362f;
        }
    
        .btn:focus {
            outline: none;
        }
    
        .todo-container {
            width: 600px;
            margin: 0 auto;
        }
    
        .todo-container .todo-wrap {
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150

    MyItem.vue

    <template>
        <div>
            <li>
                <label>
                    <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
                    
                    
                    <span>{{todo.title}}span>
                label>
                <button class="btn btn-danger" @click="handleDelete(todo.id)">删除button>
            li>
        div>
    template>
    
    <script>
        export default {
            name:'MyItem',
            //声明接收todo对象
            props:['todo','checkTodo','todoDelete'],
            methods:{
                // 勾选or取消勾选
                handleCheck(id){
                    this.checkTodo(id);
                },
                //删除一个todo
                handleDelete(id){
                    if(confirm("确定删除吗?")){
                        this.todoDelete(id);
                    }
                }
            }
        }
    script>
    
    <style scoped>
        /*item*/
        li {
            list-style: none;
            height: 36px;
            line-height: 36px;
            padding: 0 5px;
            border-bottom: 1px solid #ddd;
        }
    
        li label {
            float: left;
            cursor: pointer;
        }
    
        li label li input {
            vertical-align: middle;
            margin-right: 6px;
            position: relative;
            top: -1px;
        }
    
        li button {
            float: right;
            display: none;
            margin-top: 3px;
        }
    
        li:before {
            content: initial;
        }
    
        li:last-child {
            border-bottom: none;
        }
    
        li:hover{
            background-color: #ddd;
        }
    
        li:hover button{
            display: block;
        }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    MyList.vue

    <template>
        <div>
            <ul class="todo-main">
                
                <MyItem 
                    v-for="todoObj in todos" 
                    :key="todoObj.id" 
                    :todo="todoObj"
                    :checkTodo="checkTodo"
                    :todoDelete="todoDelete">
                MyItem>
            ul>
        div>
    template>
    
    <script>
        import MyItem from './MyItem.vue'
        export default {
            name:'MyList',
            components:{
                MyItem
            },
            props:['todos','checkTodo','todoDelete']
        }
    script>
    
    <style scoped>
        /*main*/
        .todo-main {
            margin-left: 0px;
            border: 1px solid #ddd;
            border-radius: 2px;
            padding: 0px;
        }
    
        .todo-empty {
            height: 40px;
            line-height: 40px;
            border: 1px solid #ddd;
            border-radius: 2px;
            padding-left: 5px;
            margin-top: 10px;
        }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    MyFoot.vue

    <template>
        <div>
            <ul class="todo-main">
                
                <MyItem 
                    v-for="todoObj in todos" 
                    :key="todoObj.id" 
                    :todo="todoObj"
                    :checkTodo="checkTodo"
                    :todoDelete="todoDelete">
                MyItem>
            ul>
        div>
    template>
    
    <script>
        import MyItem from './MyItem.vue'
        export default {
            name:'MyList',
            components:{
                MyItem
            },
            props:['todos','checkTodo','todoDelete']
        }
    script>
    
    <style scoped>
        /*main*/
        .todo-main {
            margin-left: 0px;
            border: 1px solid #ddd;
            border-radius: 2px;
            padding: 0px;
        }
    
        .todo-empty {
            height: 40px;
            line-height: 40px;
            border: 1px solid #ddd;
            border-radius: 2px;
            padding-left: 5px;
            margin-top: 10px;
        }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    todoList自定义事件

    自定义事件

    在Vue.js中,您可以使用自定义事件来实现组件之间的通信。自定义事件允许一个组件触发事件并让其他组件监听和响应这些事件。下面是使用Vue.js自定义事件的基本步骤:

    在触发事件的组件中定义自定义事件: 使用$emit方法在组件中触发一个自定义事件,并传递需要传递的数据。例如:

    Vue.component('child-component', {
      template: '',
      methods: {
        notifyParent: function() {
          this.$emit('custom-event', 'Hello from child component');
        },
      },
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在上面的例子中,当用户点击按钮时,notifyParent方法触发了一个名为custom-event的自定义事件,并传递了字符串数据。

    在监听事件的组件中使用v-on指令监听自定义事件: 在另一个组件中,您可以使用v-on指令来监听之前定义的自定义事件,并在事件触发时执行相应的处理函数。例如:

    new Vue({
      el: '#app',
      data: {
        message: '',
      },
      methods: {
        handleCustomEvent: function(data) {
          this.message = data; // 更新数据
        },
      },
      template: '

    {{ message }}

    '
    , });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在上面的例子中,我们在根组件中使用v-on指令监听了名为custom-event的自定义事件,并在事件触发时调用了handleCustomEvent方法来处理传递的数据。这个数据会被用来更新页面上的内容。

    现在,当用户在child-component组件中点击按钮时,自定义事件将触发,handleCustomEvent方法会被调用,并且更新了页面上的数据。

    • 触发自定义事件: 在一个组件中,您可以使用$emit方法来触发一个自定义事件。该方法接受两个参数:事件名称和可选的数据。例如:

      this.$emit('custom-event', data);
      
      • 1

      在上面的例子中,我们触发了一个名为custom-event的自定义事件,并传递了一个名为data的数据。

    • 监听自定义事件: 在另一个组件中,您可以使用v-on指令来监听之前定义的自定义事件,并在事件触发时执行相应的处理函数。例如:

      <child-component v-on:custom-event="handleCustomEvent">child-component>
      
      • 1

      在上面的例子中,我们使用v-on指令监听了名为custom-event的自定义事件,并在事件触发时调用了名为handleCustomEvent的处理函数。

    • 传递数据: 当触发自定义事件时,您可以选择传递一些数据给监听者。这些数据可以通过事件处理函数的参数进行访问。例如:

      this.$emit('custom-event', data);
      
      • 1
      handleCustomEvent(data) {
        // 处理传递的数据
      }
      
      • 1
      • 2
      • 3

      在上面的例子中,我们在触发自定义事件时传递了一个名为data的数据,并在事件处理函数中通过参数data访问该数据。

    组件之间的通信: 自定义事件提供了一种简单而有效的方式,让组件之间进行通信。一个组件可以触发一个自定义事件,而其他组件可以监听并响应这个事件。这种通信机制可以用于父子组件之间、兄弟组件之间以及更复杂的组件关系。

    需要注意的是,自定义事件只能在父子组件之间进行通信。如果需要在非父子组件之间进行通信,可以考虑使用Vue.js提供的其他通信机制,如Vuex状态管理或事件总线。

    通过使用自定义事件,可以实现组件之间的通信,使应用程序更加灵活和可扩展。

    TodoList自定义事件案例

    在Vue.js中,可以使用自定义事件来实现todoList组件中的通信。下面是一个示例,展示了如何在Vue.js中使用自定义事件来实现todoList组件的功能:

    1. 创建TodoItem组件: 首先,创建一个TodoItem组件,用于显示单个todo项,并提供删除按钮。
    <template>
      <li>
        <span>{{ todo.text }}span>
        <button @click="removeTodo">删除button>
      li>
    template>
    
    <script>
    export default {
      props: ['todo'],
      methods: {
        removeTodo() {
          this.$emit('remove', this.todo); // 触发自定义事件,并传递todo项
        },
      },
    };
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在TodoItem组件中,我们使用$emit方法触发了一个名为remove的自定义事件,并传递了当前的todo项作为参数。

    1. 创建TodoList组件: 然后,创建一个TodoList组件,用于管理todo项的列表,并监听TodoItem组件触发的自定义事件。
    <template>
      <div>
        <input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加新的todo项">
        <ul>
          <todo-item v-for="todo in todos" :key="todo.id" :todo="todo" @remove="removeTodo">todo-item>
        ul>
      div>
    template>
    
    <script>
    import TodoItem from './TodoItem.vue'; // 导入TodoItem组件
    
    export default {
      components: {
        TodoItem, // 注册TodoItem组件
      },
      data() {
        return {
          todos: [], // 存储todo项的数组
          newTodo: '', // 用于输入新todo项的文本
        };
      },
      methods: {
        addTodo() {
          if (this.newTodo.trim() === '') return;
          this.todos.push({
            id: Date.now(),
            text: this.newTodo,
          });
          this.newTodo = ''; // 清空输入框
        },
        removeTodo(todo) {
          this.todos = this.todos.filter(item => item.id !== todo.id);
        },
      },
    };
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在TodoList组件中,我们使用v-for指令遍历todos数组,并将每个todo项传递给TodoItem组件。我们还监听了TodoItem组件触发的remove自定义事件,并在事件触发时调用removeTodo方法来删除相应的todo项。

    现在,当用户在输入框中输入新的todo项并按下回车键时,该项将被添加到列表中。当用户点击TodoItem组件中的删除按钮时,相应的todo项将被从列表中删除。

  • 相关阅读:
    网络爬虫之爬虫原理
    计算机网络体系结构——网络层
    pytorch学习3(pytorch手写数字识别练习)
    ​Spring Framework(Spring 框架):IOC、DI 和 AOP
    RocketMQ Topic/Group/Tags介绍
    Flask初体验
    面试某大厂,被Channel给吊打了,这次一次性通关channel!
    第六十三章 符号概览
    Hadoop生态之hive
    程序人生 | 测试工程师还只会点点点?7个捷径教给你快速学习新技术...
  • 原文地址:https://blog.csdn.net/qq_45922256/article/details/133279104