天天看點

vue事件總線

前言:

👏作者簡介:我是笑霸final,一名熱愛技術的在校學生。

vue事件總線

  • ​​一、步驟總結​​
  • ​​二、詳細介紹(小案列==計劃小幫手==)​​
  • ​​2.1在main安裝全局事件總線​​
  • ​​2.1 在收資料的“人”綁定自定事件(app)​​
  • ​​3.1 3.給傳輸資料的‘人’觸發事件(除app的其他元件)​​
  • ​​MyHeader​​
  • ​​MyItem​​
  • ​​MyFooter​​
  • ​​注意MyList并不需要傳遞資料​​
  • ​​效果圖​​

一、步驟總結

在 vue 裡我們可以通過全局事件總線來實作任意元件之間通信

它的原理是給 Vue 的原型對象上面添加一個屬性。這樣的話我所有元件的都可以通路到這個屬性,然後可以通過這個屬性來通路其他元件給這個屬性上面綁定的一些方法,進而去傳遞資料。而且這個屬性還可以去通路 Vue 執行個體對象上的方法。因為 Vue 元件構造函數的原型對象的原型對象是指向 Vue 的原型對象的

​1.安裝全局事件總線​

new Vue({
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus=this//安裝全局事件總線
  },
}).$mount('#app')      

​2.收資料的“人”綁定自定事件​

​别忘了解綁事件

mounted和beforeDestroy

mounted(){// 加載時給$bus綁定事件
      this.$bus.$on('deletetodo',this.deletetodo)
      this.$bus.$on('changTodos',this.changTodos)

    },
    beforeDestroy(){//銷毀時解綁
      this.$bus.$off('deletetodo')
      this.$bus.$off('changTodos')
    }      

​3.給傳輸資料的‘人’觸發事件​

<template>
    <li>
      <label>
            <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>
            <span >{{todo.title}}</span>
      </label>
        <button class="btn btn-danger" @click="mydelete(todo.id)">删除</button>
    </li>
  
</template>      
methods: {
        handleCheck(id){
            this.$bus.$emit('changTodos',id)
        },
        mydelete(id){
            if(confirm("确認删除嗎?")){
              this.$bus.$emit('deletetodo',id)
            
            }
        }
    },      

二、詳細介紹(小案列計劃小幫手)

元件關系
vue事件總線
vue事件總線

2.1在main安裝全局事件總線

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

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus=this//安裝全局事件總線
  },
}).$mount('#app')      

2.1 在收資料的“人”綁定自定事件(app)

<template>
<div>
       
        <div class="d1">計劃小幫手</div>
        <br>
  <div id="root">
  <div class="todo-container">
    <div class="todo-wrap">
    
      <!-- 頭部 -->
      <MyHeader ></MyHeader>
      <!-- ============= -->
      <MyList :todos="todos"></MyList>
      <!-- ============== -->
      <MyFooter :todos="todos"></MyFooter>
    </div>
  </div>
</div>
</div>
  
</template>

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


export default {
    name: "App",
    components: { MyList, MyFooter,MyHeader },
    data() {
    return {
      todos: JSON.parse(localStorage.getItem('todos'))||[]
      //{id:'1',title:'吃飯',done:false},
      // {id:'2',title:'睡覺',done:true},
      // {id:'3',title:'打豆豆',done:true},
      //{id:'4',title:'學習',done:true}
    }
  },
  methods: {
    //添加一個todo
    addTodos(x){
      this.todos.unshift(x)
    },
    //修改一個todo
    changTodos(id){
      this.todos.forEach((todo)=>{
        if(todo.id==id){
          todo.done=!todo.done
        }
      })
    },
    //删除一個todo
    deletetodo(id){
      this.todos=this.todos.filter((todo)=>{
        localStorage.removeItem(id)
        return todo.id!==id
      })
    },
    //删除所有選中的todo
    deleteappok(){
      this.todos=this.todos.filter((todo)=>{
        if(todo.done==true){
          localStorage.removeItem(todo.id)
        }
        return todo.done!==true
      })
    },
    //全選or取消全選
    cheackAlltodo(done){
        this.todos.forEach(todo=>{
          todo.done=done
        })
    }
  },
  watch:{
    todos:{
      deep:true,
      handler(value){
          localStorage.setItem('todos',JSON.stringify(value))
      }
    }
  },
  // 給$bus綁定事件
  mounted(){
      this.$bus.$on('deletetodo',this.deletetodo)
      this.$bus.$on('changTodos',this.changTodos)
      this.$bus.$on('addTodos',this.addTodos)
      this.$bus.$on('deleteappok',this.deleteappok)
      this.$bus.$on('cheackAlltodo',this.cheackAlltodo)

    },
    beforeDestroy(){//銷毀時解綁
      this.$bus.$off('deletetodo')
      this.$bus.$off('changTodos')
      this.$bus.$off('addTodos',this.addTodos)
      this.$bus.$off('deleteappok',this.deleteappok)
      this.$bus.$off('cheackAlltodo',this.cheackAlltodo)
    }
}</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;
}

.d1{
  margin: 0 auto; 
  text-align: center
}</style>      

3.1 3.給傳輸資料的‘人’觸發事件(除app的其他元件)

MyHeader

<template>
    <div class="todo-header">
      <!-- @keyup綁定一個鍵盤事件 add是一個回調函數的名字 -->
      <!-- v-model雙向資料綁定 -->
        <input type="text" placeholder="請輸入你的任務名稱,按Enter鍵确認" @keyup.enter="add" v-model="title"/>
      </div>
 
</template>

<script>import {nanoid} from 'nanoid'

export default {
    name:'MyHeader',
    data() {
      return {
        title:''
      }
    },
   
    methods: {
      add(){
        if(!this.title) return alert("輸入不能為空");
        //将使用者的輸入包裝成一個對象
        const todobj={id:nanoid(),title:this.title,done:false}
        this.$bus.$emit('addTodos',todobj)
        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>      

MyItem

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

<script>export default {
    name:'MyItem',
    //聲明接受對象
    props:['todo'],
    methods: {
        handleCheck(id){
            this.$bus.$emit('changTodos',id)
        },
        mydelete(id){
            if(confirm("确認删除嗎?")){
              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: chartreuse;
}
li:hover button {
  float: right ;
  display: block;
  margin-top: 3px;
}</style>      

MyFooter

<template>
  <div class="todo-footer">
        <label>
          <input type="checkbox"  
          :checked='todos.length===doneTotal &&todos.length>0'
          @change="chaeckAll"
          />
          <span>全選</span>
        </label>
        
        <span >
          <span>已完成{{doneTotal}}項 </span> / 全部{{todos.length}}項
        </span>
        <button class="btn btn-danger" @click='deteleok' >打卡</button>
      </div>
</template>

<script>export default {
    name:'MyFooter',
    props:['todos'],
    computed:{
      doneTotal(){
        let i=0;
        this.todos.forEach((a)=>{
            if(a.done){
              i++
            }
        })
        return i
      }
    },
    methods: {
      deteleok(){
        //通知app删除選中的
        this.$bus.$emit('deleteappok')
        
        alert("今天内容已經全部完成!!!!請繼續保持")
      },
      //全選or取消全選
      chaeckAll(value){
         
        
          this.$bus.$emit('cheackAlltodo' ,value.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>      

注意MyList并不需要傳遞資料

效果圖

初始界面
vue事件總線
添加一個目标
vue事件總線
删除
vue事件總線

繼續閱讀