vue基礎(六)全局事件總線


全局事件總線原理圖

 

 

 

通信方式 props
父子之間傳遞
父向子傳遞屬性,通過屬性把數據交給子組件
子向父傳遞數據,子組件通過調用父組件的行為函數,把數據當參數交給父組件

 

通信方式 全局事件總線(自定義事件是全局事件總線的基礎)


vm對象和組件對象的關系
vm的原型對象 === 組件對象的原型對象的原型對象

本身自定義事件可以完成子父之間的傳遞,因為父組件中可以看到子組件,可以為子組件綁定事件,子組件中可以觸發事件
但是如果不是子向父,那么其余的就沒辦法了,因為兩個組件互相是看不到的,沒辦法再其中一個給另外一個綁定事件

此時我們可以借助中間人,也就是他們都可以同時看到的一個人,就是全局事件總線(所有的組件對象都能看到)
在接收數據的組件中,獲取總線綁定事件
在發送數據的組件中,獲取總線觸發事件

全局事件總線說到底就是個對象,我們通常就是用vm對象作為全局事件總線使用
把vm對象添加到Vue原型對象 就形成全局事件總線(vm)

 

在main.js中設置全局事件總線

// new Vue()實例化了一個Vue的實例化對象
//因為只有組件對象或者Vue的實例化對象才能調用$on和$emit

//想要成為事件總線的條件:
//1、所有的組件對象必須都能看得到這個總線對象,因此我們把這個對象放在了Vue原型 //2、這個事件總線對象必須能調用$on和$emit方法(總線對象必須是Vue的實例化對象或者是組件對象)


new Vue({
  beforeCreate(){
    Vue.prototype.$bus = this
  },
  el:'#root',
  render: h => h(App)
})

 

在父組件app中綁定事件

  mounted(){
    this.$bus.$on('updateOne',this.updateOne)
    //跟新事件
    this.$bus.$on("addTodo",this.addTodo)
    //刪除一個事件
    this.$bus.$on("deleteOne",this.deleteOne)
    //刪除全部事件
    this.$bus.$on("deleteAll",this.deleteAll)
    //全選框,跟新所有的li狀態
    this.$bus.$on("updateAll", this.updateAll)
  },

 

在子組件中觸發事件,並且傳遞數據給父組件

addT(){
      //回車之后干活
      let {content} = this
      if(content.trim()){
        let id = Date.now()
        let isOver = false
        let todo = {
          id,
          content,
          isOver
        }

        this.$bus.$emit('addTodo',todo) 

 

 

二, 具名插槽,默認插槽, 作用域插槽 

通信方式 slot插槽
    一個組件會多次使用,但是不同場景下又有少部分結構數據會發生變化,(當然可以用不同的子組件)
    那么就得通過父組件告訴子組件變化的內容是什么,此時就要用到這個插槽
    子組件當中<slot></sloat>其實就是占位用的,讓父元素給它填充內容,可以帶標簽
作用域插槽  
        子組件的slot可以通過 屬性傳遞值給父組件,然后父組件可以根據不同需求改變這個slot內部的顯示結構
        把子組件的值,傳給父組件固定的區域進行操作
        默認不能有其它插槽,如果要有其它插槽,必須設置為具名插槽

 

App組件

<template>
  <div>
    <Child>
      <template slot="btn">
        <button>點我</button>
      </template>
      <template slot="aa">
        <a href="http://www.atguigu.com">點我去學習</a>
      </template>
      <template slot="ss">
        <span>嘿嘿</span>
      </template>
    </Child>


    <Child>
      <template>
        <h2>我愛你</h2>
      </template>
    </Child>



    <Child2 :todos="todos">
      <!-- 決定子組件內部的結構,比如假設isOver為true,那么內容需要包含在span當中並且內容前面帶√ -->
      <!-- slot-scope會把子組件傳遞過來的數據,放在一個對象當中作為屬性 -->

      <!-- 什么時候用作用域插槽: 當碰到數據是在子組件當中展示的,而結構是由父組件決定的,此時必然使用作用域插槽 -->
      <template slot-scope="scopePerps">
        <span v-if="scopePerps.todo.isOver"></span>
        {{scopePerps.todo.content}}
      </template>
    </Child2>



    
  </div>
</template>

<script>
import Child from '@/components/Child'
import Child2 from '@/components/Child2'
export default {
  name: '',
  components:{
    Child,
    Child2
  },
  data(){
    return {
      todos:[
        {id:1,content:'抽煙',isOver:false},
        {id:2,content:'喝酒',isOver:true},
        {id:3,content:'燙頭',isOver:false}
      ]
    }
  },

}
</script>

<style scoped>

</style>

 

Child1 組件

<template>
    <div>
      <h1>我愛你</h1>
      <!-- slot占位置,結構不確定,需要父組件傳遞 -->
      <slot name="btn"></slot>
      <slot  name="aa"></slot>
      <slot  name="ss"></slot>
      <!-- 默認插槽,沒有名字的slot -->
      <slot  name="btn"></slot>
    </div>
</template>

<script>
export default {
    data() {
        return {

        };
    },
  
};
</script>

<style scoped >

</style>

 

Childer2組件

<template>
  <div>
    <h1>我愛你趙麗穎</h1>
    
    <ul>
      <li v-for="(todo, index) in todos" :key="todo.id">
        <slot :todo="todo">
          <!-- 這個:todo="todo" 是作用域插槽的一部分,會傳遞給父組件當中固定的某個區域 -->
          <!-- {{todo.content}} -->
        </slot>
      </li>
    </ul>


  </div>
</template>

<script>
export default {
  name: '',
  props:['todos']
}
</script>

<style scoped>

</style>

 

 

二, 利用全局事件總線傳遞數據, 組件內發送請求,獲取數據

main.js中設置全局事件總線

// 引入vue
import Vue from 'vue'
//引入app
import APP from '@/APP'

Vue.config.productionTip=false

new Vue({
  beforeCreate() { // 設置事件總線 Vue.prototype.$bus=this },

  el:"#root",
  render:h=>h(APP)
})

 

app組件

<template>
  <div >
    <Header></Header>
   <Main></Main>
    
  </div>
</template>

<script>
import Header from '@/components/Header'
import Main from '@/components/Main'

export default {
  data() {
    return {};
  },

  components:{
    Header,
    Main,
  }
};
</script>

<style scoped ></style>

 

header組件

<template>
  <section class="jumbotron">
    <h3 class="jumbotron-heading">Search Github Users</h3>
    <div>
      <input type="text" placeholder="enter the name you search" v-model="content"  />
      <button  @click="sendSj">Search</button>
    </div>
  </section>
</template>

<script>
export default {
  //在該組件中,需要將輸入的數據傳遞給main,讓main組件去發送請求,獲取數據
  //兄弟關系,需要用事件總線傳遞

  name:"Header",
  data() {
    return {
      content:'',
    };
  },

  methods:{
    sendSj(){
      this.$bus.$emit('addO', this.content)
    }
  }



};
</script>

<style scoped></style>

 

main組件, 安裝axios, 引入axios

<template>
  <div class="row">
    <h2 v-if="isFirst">歡迎光臨,請輸入關鍵字進行搜索</h2>
    <h2 v-else-if="isLoading">正在搜索中,請稍后</h2>
    <h2 v-else-if="errMsg">請求出錯:{{ errMsg }}</h2>
    <div v-else class="card" v-for="(user, index) in users" :key="user.id">
      <a :href="user.url" target="_blank">
        <img
          :src="user.imgUrl"
          style="width: 100px"
        />
      </a>
      <p class="card-text">{{user.name}}</p>
    </div>
  </div>
</template>

<script>
// 引入axios
import axios from "axios";

export default {
  //發送請求前,isFirst為fasle, isLoading為true
  //發送請求后,isLoading為false,

  name: "Main",
  data() {
    return {
      users: [],
      isFirst: true,
      isLoading: false,
      errMsg: "",
    };
  },
  //頁面加載后獲取header的數據
  mounted() {
    this.$bus.$on("addO", this.addO); // this.addO()
    console.log(111)
  },

// #region
  // methods:{
  //   addO(q){
     
  //     //發送請求前,在搜索中
  //       this.isFirst= false
  //       this.isLoading= true
  //     axios({
  //       url:"https://api.github.com/search/users",
  //       method:'get',
  //       params:{
  //           q
  //       }
  //     }).then((res)=>{
  //      let newArray=  res.data.items.map(item=>({name:item.login, url:item.url, imgUrl: item.avatar_url, id:item.id}))
  //       // console.log(newArray)
  //      this.users = newArray
  //      //發送請求后,更改狀態
  //       this.isLoading = false

  //     }).catch((error)=>{
  //       console.log(error.message)
  //       //發送請求有誤,更改狀態
  //       this.errMsg = error.message
  //       this.isLoading = false
  //     })
  //   }
  // }
//  #endregion

  methods: {
    // 接口2: https://api.github.com/search/users?q=aa
    //收到header組件的數據,並且去發送請求,獲取數據
    async addO(content) {
      //發送請求前,在搜索中
        this.isFirst= false
        this.isLoading= true

      try {
        let result = await axios({
          url: "https://api.github.com/search/users",
          method: "get",
          params: {
            q: content,
          },
        });
        //map計算一個新數組
        let newAarry=  result.data.items.map(item =>({name:item.login, url:item.url, imgUrl: item.avatar_url, id:item.id}))
        this.users = newAarry
        //發送請求后,更改狀態
        this.isLoading = false
      } catch (error) {
        console.log(error.message)
        //發送請求有誤,更改狀態
        this.errMsg = error.message
        this.isLoading = false
      }
    },
  },
};
</script>

<style scoped>
.card {
  float: left;
  width: 33.333%;
  padding: 0.75rem;
  margin-bottom: 2rem;
  border: 1px solid #efefef;
  text-align: center;
}

.card > img {
  margin-bottom: 0.75rem;
  border-radius: 100px;
}

.card-text {
  font-size: 85%;
}
</style>

 

注;async, awiat 是es8語法,需要用它babel- polyfill來轉換,安裝;npm install --save @babel/polyfill

webpackde.config.js的 entry配置, entry: ["@babel/polyfill", "./src/main.js"], 在任何組件中引入async和await, 都不會報錯了

報錯情況

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM