Vue框架2.0基础知识(5)组件以及组件间的通讯

组件:复用的 Vue 实例,且带有一个名字,并且接受相同的选项对象,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样的根实例特有的选项。

 作用:可以将组件进行任意次数的复用。每个组件都会各自独立维护它自己。因为每用一次组件,就会有一个它的新实例被创建。

    组件的模板只能有一个根元素。

//以下情况是不允许的

Vue.component('my-component', {
  template: `<div>这是一个局部的自定义组件,只能在当前Vue实例中使用</div>
            <button>hello</button>`
})

组件中的data必须是一个函数?

      由于JS中对象类型的变量实际上保存的是对象的引用,所以当存在多个这样的组件时,会共享数据,导致一个组件中数据的改变会引起其他组件数据的改变
而使用一个返回对象的函数,每次使用组件都会创建一个新的对象,这样就不会出现共享数据的问题了。
  总结:通过函数生成了不同的对象, 属性的改变不会再互相影响

Vue.component('my-component', {
   data:function(){
          return {
              name:'Lee‘
          }
  },
})


组件名:
使用kebab-case(短横线分割命名):当使用短横线分割命名定义一个组件时,在引用这个自定义元素时也必须使用这种方式。

Vue.component('my-component-name', { /* ... */ })

使用PascalCase(首字母大写命名):当使用首字母大写命名定义一个组件时,在引用这个自定义元素时两种命名法都可以使用。

Vue.component('MyComponentName', { /* ... */ })


全局组件的定义

   component----组件(就是对象)

Vue.component("mynav",{
    template:"<ul><li>首页</li><li>我的</li></ul>"
})

注意:在定义组件时里面的data属性必须是函数式编程,目的是每次调用组件返回一个独立的数。

局部组件的定义
//1.创建组件

//局部注册的组件只能在当前的Vue实例中使用。
let mynav={
    template:"<p>这是一个导航</p>",
    data(){
        return{
            
        }
    },
    methods:{},
    watch:{},
    computed:{},
    
}

//2.注册组件

const app=new Vue({
    el:'#app',
  components:{
      mynav
  }
})

*注意:驼峰命名组件时,使用组件写标签形式的时候该用-连接,例如定义了一个组件时myIpt,那么使用标签就应该这样写<my-ipt></my-ipt>

局部组件component的用方法
我们来看用法:

<!-- 动态组件由 vm 实例的 `componentId` property 控制 -->
<component :is="componentId"></component>

我们来看例子:

<body>
    <div id="app">
        <!-- 组件的另外一种引入方式 -->
        <component :is="current"></component>
    </div>
    <script src="../../node_modules/vue/dist/vue.js"></script>
    <script>
        let home = {
            template: '<div>home</div>'
        }
        let about = {
            template: '<div>about</div>'
        }

        const app = new Vue({
            el: '#app',
            data: {
                current: about
            },
            components: {
                home, about
            }
        })
    </script>

</body>

   组件的嵌套

<body>
    <div id="app">
        <father></father>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
     let son = {
            template: '<div>son</div>'
        }
        let father = {
            template: '<span>father<son></son></span>',
            components: {
                son
            }
        }
     
        const app = new Vue({
            el: '#app',
            components: {
                father
            }
        })

    </script>
</body>

                   注意:组件的嵌套子组件声明要放在父组件前面,父组件内必须声明子组件

组件间的通信
父向子通讯

     父组件通过Props向子组件传递数据:
props的使用首先父组件的子标签内写上要传递的元素接着在子组件中通过props来接收,相当于一个data值,不过注意这里不能够改变该值,因为是父组件给的。

在子组件中使用 props 接收父组件传递的数据,props 里的名字跟父组件定义的属性名一致

但是子组件内想要修改父组件传过来的值却不“污染”父组件的话,可以在子组件内定义一个变量mydata去接收fatherData数据,并使用 watch 监听fatherData数据的变更。

Vue子组件通过props属性来接受父组件传递过来的数据。

由于HTML特性是不区分大小写的,所以传递属性值时,要用短横线分割命名。

<body>
    <div id="app">
        <father></father>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
     let son = {
            template: '<div>son {{m}}</div>',
            // props: ['m'],     //props:两种方法书写,对象和数组的方式
            props:{
                m:{
                    // type:Number,   //规定该值的类型必须是什么
                    // default:300,   //默认值
                    required:true      //父组件是否必须写这个m属性
                }
            }
        
        }
        let father = {
            template: '<span>father<son :m="money" ></son></span>',
            components: {
                son
            },
            data(){
                return{
                    money:100
                }
            }
        }
     
        const app = new Vue({
            el: '#app',
            components: {
                father
            }
        })

    </script>
</body>

子向父通讯
使用自定义事件

  //子组件发布事件

this.$emit('more') 发布事件

 //父组件注册事件

@more='handler()' //handler是一个函数体


我们来看详细代码:

<body>
    <div id="app">
        <father></father>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
     let son = {
            template: '<div>son {{m}} <button @click="add">点击增加</button> </div>',
            // props: ['m'],
            props:{
                m:{
    
                    required:true
                }
            },
            methods: {
                add(){
                    this.$emit('add')  //发布一个add
                }
            },
        
        }
        let father = {
            template: '<span>father<son :m="money" @add="add"></son></span>',  //son标签内接收add并触发后面的函数。
            components: {
                son
            },
            data(){
                return{
                    money:100
                }
            },
            methods:{
                add(){
                    this.money+=100
                }
            }
           
        }
     
        const app = new Vue({
            el: '#app',
            components: {
                father
            }
        })

    </script>
</body>

兄弟组件之间的通信
创建一个事件车的Vue实例,通过它来发布和订阅。

<body>
    <div id="app">
        <brother1></brother1>
        <bro-ther2></bro-ther2>  //注意驼峰命名的组件标签的写法
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        const eventBus = new Vue()
        let brother1 = {
            template: '<span @click="changecolor">111</span>',
            methods:{
                changecolor(){
                    eventBus.$emit('green')   //通过事件车去发布green
                }
            }

        }
        let broTher2 = {
            template: '<span :style={color:color}>222</span>',
            created(){
                eventBus.$on('green',()=>{  //通过事件车订阅了green事件,并执行回调函数赋值color
                this.color='green'
                })
            },
            data(){
                return{
                    color:''
                }
            }
        }
        const app = new Vue({
            el: '#app',
            components: {
                brother1,
                broTher2
            }
        })
    </script>
</body>

隔代通讯
使用的方法:provide inject

<body>
    <div id="app">
        <grand-father></grand-father>

    </div>

    <!-- 各个模板的书写 -->
    <template id="son">
        <div>
            Son
            {{msg}}
        </div>
    </template>

    <template id="father">
        <div>
            Father
            <son></son>
        </div>
    </template>
    <template id="grandFather">
        <div>
            grandFather
            <father></father>
        </div>
    </template>

    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let son = {
            template: '#son',
            inject:['msg']   //inject接收

        }
        let father = {
            template: '#father',
            components: {
                son
            }
        }
        let grandFather = {
            template: '#grandFather',
            components: {
                father
            },
            provide:{
                msg:"隔代通讯"  //provide 提供 
            }

        }

        const app = new Vue({
            el: '#app',
            components: {
                grandFather
            }
        })
    </script>
</body>


PubSub插件实现 任意组件间的通讯
同样的可以用第三方插件:PubSub来实现同样的操作

pubsub.subscribe() 订阅
pubsub.publish() 发布

<body>
    <div id="app">
        <brother1></brother1>
        <brother2></brother2>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/PubSub"></script>
    <script>
        const eventBus = new Vue();
        const pubsub = new PubSub();
        let brother1 = {
            template: '<span @click="changeGreen" :style={color:color}>brother1</span>',
            methods: {
                changeGreen() {
                    pubsub.publish('green')
                }
            },
            data() {
                return {
                    color: ''
                }
            },
            created() {
                pubsub.subscribe('red', () => {
                    this.color = 'red'
                })
            }
        }
        let brother2 = {
            template: '<span :style={color:color}  @click="changeRed">brother2</span>',
            created() {
                pubsub.subscribe('green', () => {
                    console.log(111);
                    this.color = 'green';
                })
            },
            data() {
                return {
                    color: ''
                }
            },
            methods: {
                changeRed() {
                    pubsub.publish('red')
                }
            }

        }
        const app = new Vue({
            el: '#app',
            components: {
                brother1,
                brother2
            }
        })
    </script>
</body>


父子组件的互相访问
父访问子
ref方法的使用,利用ref绑定组件,获得绑定的组件。 

<body>
    <div id="app">
<father></father>

    </div>

    <!-- 各个模板的书写 -->
    <template id="son">
        <div v-show='isShow'>
            Son
        </div>
    </template>

    <template id="father">
        <div>
            Father
            <son ref="myson"></son>
            <button @click="change">显示或隐藏</button>
        </div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let son={
            template:'#son',
            methods: {
                changeColor(){
                   return this.isShow=!this.isShow
                }
            },
            data(){
                return{
                    isShow:false
                }
            }
        }
//ref 加到组件上的时候,获取到的是Vue实例

        let father={
        template:'#father',
        components:{
            son
        },
        methods:{
change(){
    console.log(this.$refs.myson)
    this.$refs.myson.changeColor()
}
        }
        }

    const app=new Vue({
            el:'#app',
            components:{
                father
            }
        })
    </script>
</body>

    子访问父
        $parent方法,访问到父组件。

<body>
    <div id="app">
        <father></father>

    </div>
    <!-- 各个模板的书写 -->
    <template id="son">
        <div >
            Son
            <button @click="get">点击我得到父级元素的属性</button>
        </div>
        
    </template>

    <template id="father">
        <div>
            Father
            <son></son>
   
        </div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let son = {
            template: '#son',
            methods: {
                get(){
                    console.log(this.$parent.money)  //$parent 访问父组件
                }
            },
       
        }
  

        let father = {
            template: '#father',
            components: {
                son
            },
            data(){
                return{
                    money:111234
                }
            }
           
        }

        const app = new Vue({
            el: '#app',
            components: {
                father
            }
        })
    </script>
</body>

总结:
常见使用场景可以分为三类:

父子通信: 父向子传递数据是通过 props,子向父是通过 events( $emit);通过父链 / 子链也可以通信( $parent / $children);ref 也可以访问组件实例;provide / inject API; $attrs/$listeners

兄弟通信: Bus;Vuex

跨级通信: Bus;Vuex;provide / inject API、 $attrs/$listeners

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放学后J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值