vue的组件通信和插槽

本文详细介绍了Vue中组件间的通信方式,包括props、$emit、ref、$parent/$children、EventBus以及Vuex。此外,还讲解了插槽的使用,如匿名插槽、具名插槽和插槽作用域,帮助理解Vue组件如何进行数据传递和内容定制。
摘要由CSDN通过智能技术生成

目录

组件通信

父组件向子组件传递数据

 props

子组件向父组件传递数据

多个参数

非父子组件之间通信

Vue 组件间通信有哪几种方式? 

插槽

匿名插槽

具名插槽

插槽作用域


组件通信


父组件向子组件传递数据

1.父传子: 父变,子变,子变,父不变,并且报错.
2.父传子:父变,子变,子变,父变,需要传递一个对象
3.父传子: 父变,子不变,子变, 父不变, 需要在子组件中将数据传递新的data属性

父级 

Parent.vue
<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <input v-model="name" />
      <!--1.父传子: 父变,子变,子变,父不变,并且报错.  -->
      <div>name的值为:{{name}}</div>
      <hr />
      <!-- 2.父传子:父变,子变,子变,父变,需要传递一个对象 -->
      <input v-model="person.name" />
      <div>person对象中的name值为:{{person.name}}</div>
      <hr />
      <!-- 3.父传子: 父变,子不变,子变, 父不变, 需要在子组件中将数据传递新的data属性-->
     <input v-model="age" />
      <div>age的值为:{{age}}</div>
      <!-- 3.组件调用 -->
      <!-- 找到父子组件的关联点 -->
    <v-child :a="10" :num="666" :name="name" :person="person" :age="age"></v-child>
  </div>
</template>

<script>
// 1.引入组件
import vChild from './Child'
export default {
    data(){
        return{
            name:'平安夜',
            person:{
                name:'王一博',
            },
            age:20,
        }
    },
    // 2.组件注册
    components:{
        vChild
    }
}
</script>

<style>

</style>

 子级

<template>
  <div class="well">
      <h2>子组件</h2>
      <div>num的值为:{{num}}</div>
      <input type="text" v-model="name">
      <div>name的值为:{{name}}</div>
      <hr>
      <input v-model="person.name" />
      <div>person对象中的name值为:{{person.name}}</div>
      <hr>
      <input v-model="newAge" />
      <div>newAge的值为:{{newAge}}</div>
  </div>
</template>

<script>
export default {
    props:['num','a','name','person','age'],//props选项:专门来接收父组件传递给子组件的数据
    data(){
        return {
            newAge:'',
        }
    },
    mounted(){
        this.newAge = this.age;
    }
}
</script>

<style>

</style>

总结:
 找到父子组件的关联点
   父组件:通过自定义属性传递数据
  子组件:通过props选项接受数据
  
  2)ref 与 $parent / $children 适用 父子组件通信
  ref:如果在普通的 DOM 元素上使用,引用指向的就是
  DOM 元素;如果用在子组件上,引用就指向组件实例
   $parent / $children:访问父 / 子实例 

 props

作用: 父组件向子组件传递时,通过props选项来接受.
props的值: 对象 | 数组

 props的值为:{},则表示在props中可以做数据类型的校验
校验类型:Number String Array Object Function Boolean

required:  #必填项
type:            #类型
validator: #验证器
default:   #默认值

Child.vue
<template>
  <div class="well">
      <h2>子组件</h2>
      <div>name的值为:{{name}}</div>
      <div>newAge的值为:{{newAge}}</div>
      <div>phone的值为:{{phone}}</div>
  </div>
</template>

<script>
export default {
    // props做数据的校验
    props:{
        name:{
            type:String,//类型: String
            required:true,//必填项
        },
        newAge:{
            type:Number,//类型:Number
            default:18,//默认值
            validator:function(age){//validator:验证器
              return 0 <= age <= 100
            }
        },
        phone:{
            type:[String,Number],//类型:  或关系 
        }
    }
}
</script>

<style>

</style>

子组件向父组件传递数据

总结
    子组件:通过触发$emit来传递自定义事件
    父组件:触发自定义事件来触发父组件的事件函数,通过参数来接受数据
    
    接受子组件的数据的方式:
        1.显示接收: 在事件函数中$event
        3.隐士接收: 在事件函数声明处,直接通过形参来接收

 

Parent
<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <div>name的值为:{{name}}</div>
      <!-- 父子组件的关联点 -->
      <!-- @message表示触发了自定义事件
            @message 相当于 @click
       -->
       <!-- 通过显示$event接受数据 -->
      <v-child @message="send($event)"></v-child>
      <hr />
      <!-- 通过隐士接收数据 -->
      <v-child @message="send"></v-child>
  </div>
</template>

<script>
import vChild from './Child'
export default {
    data(){
        return{
            name:'',
        }
    },
    methods:{
        send(name){
            this.name = name;
        }
    },
    components:{
        vChild
    }
}
</script>

<style>

</style>
Child
<template>
  <div class="well">
      <h2>子组件</h2>
      <input type="text" v-model="name" @change="send1">
      <div>name的值为:{{name}}</div>
      <button @click="send">发送</button>
  </div>
</template>

<script>
export default {
    data(){
        return{
            name:'王成玉',
        }
    },
    methods:{
        send(){
            // 触发$emit事件
            /**
             * 参数一:自定义事件名称
             * 参数二:传递的数据
            */
            this.$emit('message',this.name);
        },
        send1(){
            this.$emit('message',this.name);
        }
    },
    watch:{
        name(){
            this.$emit('message',this.name);
        }
    },
    mounted(){
        console.log(this);
    }
}
</script>

<style>

</style>

多个参数

<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <div>name的值为:{{name}}</div>
      <div>age:{{age}}</div>
      <!-- 父子组件的关联点 -->
      <!-- @message表示触发了自定义事件
            @message 相当于 @click
       -->
       <!-- 通过显示$event接受数据 -->
      <v-child @message="sendP(arguments)"></v-child>
      <hr />

  </div>
</template>

<script>
import vChild from './Child'
export default {
    data(){
        return{
            name:'',
            age:''
        }
    },
    methods:{
        sendP(data){
            //传递多个参数
           
            this.name = data[0],
            this.age = data[1]
         
        }

    },
    components:{
        vChild
    }
}
</script>

<style>

</style>

非父子组件之间通信

方式有三种:

1.eventBus A组件--> B组件同时存在,并且在组件实现事件的传递,

2.本地存储: localStorage sessionStorage

3.vuex状态管理

Vuex 适用于 父子、隔代、兄弟组件通信 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit)mutation。这样使得我们可以方便地跟踪每一个状态的变化。

步骤

在Vue的原型链上实例化vue

main.js
Vue.prototype.$eventBus = new Vue();

通过触发$emit方法来从触发自定义 事件

this.$eventBus.$emit('自定义事件的名称',参数)

通过$on监听自定义事件的触发

this.$eventBus.$on('自定义事件的名称',(e)=>{
  //e:接受传递的数据    
})

 

Box1.vue
<template>
  <div class="well">
      <h2>box1组件</h2>
      <div>name的值为:{{name}}</div>
      <button @click="send">发送</button>
  </div>
</template>

<script>
export default {
  data(){
    return{
      name:'李佳琦'
    }
  },
  methods:{
    send(){
      /**
       * 触发自定义事件
       * 参数一:自定义事件名
       * 参数二:传递的数据
      */
    //  this.$eventBus === new Vue()
      this.$eventBus.$emit('message',this.name);
    }
  },
  mounted(){
    // console.log(this.a);
    // console.log(this.$eventBus);
    // 实现监听
    this.$eventBus.$on('message',(e)=>{
      this.name = e;
    })
  }
}
</script>

<style>
Box2
<template>
  <div class="well">
      <h2>box2组件</h2>
      <input type="text" v-model="name">
      <div>name的值为:{{name}}</div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      name:'',
    }
  },
  watch:{
    name(){
      this.$eventBus.$emit('message',this.name)
    }
  },
  mounted(){
    // 监听message事件的触发
    /**
     * 监听自定义事件的触发
     * 参数一:监听自定义事件名
     * 参数二:callback
    */
  //  this.$eventBus  ===  new Vue()
    this.$eventBus.$on('message',(e)=>{
      // console.log('被监听到了');
      this.name =  e;
    })
    // console.log(this.a);
    // console.log(this.$eventBus);
  }
}
</script>

<style>

</style>
Box3
<template>
  <div class="well">
      <h2>box3组件</h2>
      <div>name的值为:{{name}}</div>
  </div>
</template>

<script>
export default {
  data(){
    return{
      name:'',
    }
  },
  mounted(){
    // 实现监听
    this.$eventBus.$on('message',(e)=>{
      this.name = e;
    })
  }
}
</script>

<style>

</style>

Vue 组件间通信有哪几种方式? 

Vue 组件间通信是面试常考的知识点之一,这题有点类似于开放题,你回答出越多方法当然越加分,表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信。

(1)props / $emit 适用 父子组件通信 这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。

(2)ref 与 $parent / $children 适用 父子组件通信 ref:如果在普通的 DOM 元素上使用,引用指向的就是DOM 元素;如果用在子组件上,引用就指向组件实例$parent / $children:访问父 / 子实例

(3)EventBus ($emit / $on) 适用于 父子、隔代、兄弟 组件通信 这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。

(4)Vuex 适用于 父子、隔代、兄弟组件通信 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit)mutation。这样使得我们可以方便地跟踪每一个状态的变化。

 

插槽


系统中提供了一个组件slot:槽口
插槽又名槽口

匿名插槽

Index
<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <v-child>
          <div>直播带货选手:王成玉,李志远</div>
          <h1>这是一级标题</h1>
      </v-child>
  </div>
</template>

<script>
import vChild from './Child'
export default {
    components:{
        vChild
    }
}
</script>

<style>

</style>
Child
<template>
  <div class="well">
      <h2>子组件</h2>
      <!-- 系统中提供了一个组件slot:槽口 -->
      <!-- 匿名槽口 -->
      <slot></slot>
      <slot></slot>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

具名插槽

<!-- 为槽口这是名称,称为具名槽口 -->
 <slot name="students"></slot>

 

Index
<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <!-- 1.匿名槽口 -->
      <!-- <v-child>
          <div>直播带货选手:王成玉,李志远</div>
          <h1>这是一级标题</h1>
      </v-child> -->

      <v-child1>
        <ul slot="stars">
          <li>薇娅</li>
          <li>李佳琦</li>
          <li>雪梨</li>
        </ul>

      <ol slot="students">
          <li>张同学</li>
          <li>李同学</li>
          <li>王同学</li>
      </ol>

      </v-child1>
  </div>
</template>

<script>
// import vChild from './Child'
import vChild1 from './Child1'
export default {
    components:{
        // vChild
        vChild1
    }
}
</script>

<style>

</style>
Child1
<template>
  <div class="well">
      <h2>子组件</h2>
      <!-- 为槽口这是名称,称为具名槽口 -->
      <slot name="students"></slot>
      <slot name="stars"></slot>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

插槽作用域

作用域插槽就是父组件在调用子组件的时候给子组件传了一个插槽,这个插槽为作用域插槽,该插槽必须放在template标签里面,同时声明从子组件接收的数据放在一个自定义属性内,并定义该数据的渲染方式。

Index
<template>
  <div class="alert alert-info">
      <h2>父组件</h2>
      <!-- 1.匿名槽口 -->
      <!-- <v-child>
          <div>直播带货选手:王成玉,李志远</div>
          <h1>这是一级标题</h1>
      </v-child> -->

    <!-- 2.具名槽口 -->
      <!-- <v-child1>
        <ul slot="stars">
          <li>薇娅</li>
          <li>李佳琦</li>
          <li>雪梨</li>
        </ul>

      <ol slot="students">
          <li>张同学</li>
          <li>李同学</li>
          <li>王同学</li>
      </ol> 
      </v-child1>-->
      <v-child2>
           <!-- 
               1.scope变量自定义
               2.scope接受的值为一个对对象: {row:{id:1,name:'牙膏',price:20.00}}
            -->
           <template v-slot="scope">
               <div>编号:{{scope.row.id}}</div>
               <div>商品名称:{{scope.row.name}}</div>
               <div>商品价格:{{scope.row.price}}</div>
           </template>
      </v-child2>
  </div>
</template>

<script>
// import vChild from './Child'
// import vChild1 from './Child1'
import vChild2 from './Child2'
export default {
    components:{
        // vChild
        vChild2
    }
}
</script>

<style>

</style>
Child2
<template>
  <div class="well">
      <h2>子组件</h2>
      <!-- <ul>
          <li v-for="item in list" :key="item">
               槽口 
              <slot :row="item"></slot>
          </li>
      </ul> -->

      <ul>
          <li v-for="item in goods" :key="item.id">
              <!-- 设置槽口 -->
              <slot :row="item"></slot>
          </li>
      </ul>
  </div>
</template>

<script>
export default {
    data(){
        return{
            list:['宝马','奔驰','凤凰牌自行车','奥迪'],
            goods:[
                {id:1,name:'牙膏',price:20.00},
                {id:2,name:'牙刷',price:10.00},
                {id:3,name:'洗脸盆',price:10.00},
                {id:4,name:'洗面奶',price:70.00},
            ]
        }
    }
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值