小于博客 小于博客
首页
  • Java学习笔记
  • Docker专区
  • 实战教程
  • Shell
  • 内存数据库
  • Vue学习笔记
  • Nginx
  • Php
  • CentOS
  • Docker
  • Gitlab
  • GitHub
  • MySql
  • MongoDB
  • OpenVPN
  • 配置文件详解
  • Other
  • ELK
  • K8S
  • Nexus
  • Jenkins
  • 随写编年
  • 电影音乐
  • 效率工具
  • 博客相关
  • 最佳实践
  • 迎刃而解
  • 学习周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • 网站状态 (opens new window)
    • json2go (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

小于博客

行者常至,为者常成
首页
  • Java学习笔记
  • Docker专区
  • 实战教程
  • Shell
  • 内存数据库
  • Vue学习笔记
  • Nginx
  • Php
  • CentOS
  • Docker
  • Gitlab
  • GitHub
  • MySql
  • MongoDB
  • OpenVPN
  • 配置文件详解
  • Other
  • ELK
  • K8S
  • Nexus
  • Jenkins
  • 随写编年
  • 电影音乐
  • 效率工具
  • 博客相关
  • 最佳实践
  • 迎刃而解
  • 学习周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • 网站状态 (opens new window)
    • json2go (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Java学习笔记

  • Docker专区

  • Shell编程

  • 实战教程

  • 内存数据库

  • Vue学习笔记

    • 基础知识

    • 脚手架工程化

      • src_分析脚手架
      • src_ref属性
      • src_props配置
      • src_mixin(混入)
      • src_插件
      • src_scoped样式
      • src_TodoList案例
      • 浏览器本地存储
      • src_TodoList_本地存储
      • src_组件自定义事件
      • src_TodoList_自定义事件
      • src_全局事件总线
      • src_TodoList_事件总线
        • 代码
          • 代码路径
          • App.vue
          • MyFooter.vue
          • MyHeader.vue
          • MyItem.vue
          • MyList.vue
          • main.js
      • src_消息订阅与发布
      • src_TodoList_pubsub
      • src_TodoList_nextTick
      • src_过渡与动画
      • src_TodoList_动画
      • src_配置代理服务器
      • src_github搜索案例
      • 插槽
      • src_求和案例_纯Vue版本
    • 实战积累

  • 编程世界
  • Vue学习笔记
  • 脚手架工程化
小于博客
2022-08-17
目录

srcTodoList事件总线

# 代码

# 代码路径

$ tree -N
.
├── App.vue
├── components
│   ├── MyFooter.vue
│   ├── MyHeader.vue
│   ├── MyItem.vue
│   └── MyList.vue
└── main.js
1
2
3
4
5
6
7
8
9

# App.vue

<template>
  <div id="app">
    <div class="todo-container">
      <div class="todo-wrap">
        <!-- header -->
        <MyHeader @addTodo="addTodo"></MyHeader>
        <MyList :todos="todos"></MyList>
        <MyFooter
          :todos="todos"
          @checkAllTodo="checkAllTodo"
          @clearAllTodo="clearAllTodo">
        </MyFooter>
      </div>
    </div>
  </div>
</template>

<script>
    import MyFooter from './components/MyFooter.vue'
    import MyHeader from './components/MyHeader.vue'
    import MyList from './components/MyList.vue'

    export default {
        name:'App',
        components:{MyFooter,MyHeader,MyList},
        data() {
            return {
                todos:[
                    {id:'001',title:'抽烟',done:true},
                    {id:'002',title:'喝酒',done:false},
                    {id:'003',title:'开车',done:true}
                ]
            }
        },
        methods: {
          // 添加一个todo
          addTodo(todoObj){
            // console.log('我是App,我接收到了数据:',x);
            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
            })
          },
          // 全选or取消全选
          checkAllTodo(done){
            this.todos.forEach(todo => {
              todo.done = done
            });
          },
          // 清除所有已完成的todo
          clearAllTodo(){
            this.todos = this.todos.filter((todo) =>{
              return !todo.done
            })
          }
        },
        mounted() {
          this.$bus.$on('checkTodo',this.checkTodo)
          this.$bus.$on('deleteTodo',this.deleteTodo)
        },
        beforeDestroy(){
          this.$bus.$off('checkTodo')
          this.$bus.$off('deleteTodo')
        }
    }
</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

# MyFooter.vue

<template>
    <div class="todo-footer" v-show="total">
        <label>
            <!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
            <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:'MyFooter',
        props:['todos'],
        computed:{
            total(){
                return this.todos.length
            },
            doneTotal(){
                // 第一种:使用遍历的方式
                // let i = 0
                // this.todos.forEach(todo => {
                //     if(todo.done){
                //         i++
                //     }
                // });
                // return i

                // 第二种:使用 reduce 处理
                // return this.todos.reduce((pre, todo) => pre+(todo.done ? 1 : 0), 0);

                // 第三种:使用filter处理
                const a = this.todos.filter(todo => {
                   return todo.done
                });
                return a.length
            },
            isAll:{
                get(){
                    return this.total === this.doneTotal && this.total > 0
                },
                set(value){
                    // this.checkAllTodo(value)
                    this.$emit('checkAllTodo', value);
                }
            }
        },
        methods: {
            clearAll(){
                console.log('aaaa');

                // this.clearAllTodo()
                this.$emit('clearAllTodo')
            }
        //     checkAll(e){
        //         this.checkAllTodo(e.target.checked)
        //     }
        },
    }
</script>

<style scoped>
/*footer*/
.todo-footer {
  height: 40px;
  line-height: 40px;
  padding-left: 6px;
  margin-top: 5px;
}

.todo-footer label {
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}

.todo-footer label input {
  position: relative;
  top: -1px;
  vertical-align: middle;
  margin-right: 5px;
}

.todo-footer button {
  float: right;
  margin-top: 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

# MyHeader.vue

<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:'MyHeader',
        // props:['addTodo'],
        data() {
            return {
                title:''
            }
        },
        methods: {
            add(){
                // 校验数据
                if(!this.title.trim()){
                    return alert('输入不能为空')
                }
                // 将用户的输入包装成一个todo对象
                const todoObj = {id:nanoid(),title:this.title,done:false}
                // 通知APP组件添加一个todo对象
                this.$emit('addTodo',todoObj)
                // 清空输入框
                this.title=''
            }
        },
    }
</script>

<style scoped>
/*header*/
.todo-header input {
  width: 560px;
  height: 28px;
  font-size: 14px;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 4px 7px;
}

.todo-header input:focus {
  outline: none;
  border-color: rgba(82, 168, 236, 0.8);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
</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

# MyItem.vue

<template>
    <li>
        <label>
            <input type="checkbox"
                :checked="todo.done"
                @change="changeTodo(todo.id)"/>
            <span>{{todo.title}}</span>
        </label>
        <button class="btn btn-danger" @click="handlerTodo(todo.id)">删除</button>
    </li>
</template>

<script>
    export default {
        name:'MyItem',
        // 声明接收todo对象
        props:['todo'],
        methods: {
            // 勾选or取消勾选
            changeTodo(id){
                // 通知App组件将对应的todo对象的done值取反
                // this.checkTodo(id)
                this.$bus.$emit('checkTodo',id)
            },
            // 删除todo
            handlerTodo(id){
                if(confirm('确定删除吗?')){
                    // this.deleteTodo(id)
                    this.$bus.$emit('deleteTodo',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: gray;
}
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>
    <ul class="todo-main">
        <MyItem
            v-for="t in todos"
            :key="t.id"
            :todo="t"/>
    </ul>
</template>

<script>
    import  MyItem  from "./MyItem.vue";

    export default {
        name:'MyList',
        components:{MyItem},
        props:['todos'],
    }
</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

# main.js

import Vue from "vue"
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    el: '#app',
    components:{App},
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this
    },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
上次更新: 2024/02/28, 13:00:35

← src_全局事件总线 src_消息订阅与发布→

最近更新
01
SpringBoot 快速实现 api 加密!
03-21
02
SpringBoot整合SQLite
03-07
03
SpringBoot配置使用H2数据库的简单教程
02-21
更多文章>
Theme by Vdoing | Copyright © 2017-2024 | 点击查看十年之约 | 豫ICP备2022014539号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式