Vue组件通讯or插槽

组件通讯

父子组件的通讯

父组件通过props向子组件传递数据

写法一:

写法二:

<div id="app">
    // 在使用组件的时候绑定
    // 不支持驼峰命名  cMovies要写成c-movies
    <cpm :c-movies="movies" :c-message="message"></cpn>
</div>

<template id="cpn">
    <div>
        <li v-for="item in cMovies">{{item}}</li>
        <h2>{{cMessage}}</h2>
    </div>
</template>


const cpn = {
    template: '#cpn',
    // 把数组里的当变量来看了
    props: {
        // 类型限制 
        // cMovies: Array,
        // cMeesage: String,
        
        // 类型限制 + 提供一些默认值 or  required表示必传值,不然报错
        cMessage: {
            type: String,
            default: '哈',
            required: true
        },  
        cMovies: {
            type: Array, // 对象or数组类型的时候, 默认值必须是个函数
            default() {
                return {}
            }
        }
    }
    data () {
        return {}
    }
}

const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈',
        movies: ['哈喽', '嗨', '哟哟']
    },
    components: {
        cpn
    }
})

子组件通过事件向父组件发送数据

// 父组件模板
<div id="app">
    // 2.父组件监听一个事件
    // 不能写驼峰
    <cpm @itemclick="cpnClick"></cpn>
</div>

// 子组件模板
<template id="cpn">
    <div>
        <button v-for="item in categories" 
                @click="btnClick(item)">
            {{item.name}}
        </button>
    </div>
</template>


// 子组件
const cpn = {
    template: '#cpn',
    data() {
        return {
            categories: [
                {id: 'aaaa', name: '热门推荐'},
                {id: 'bbbb', name: '手机数码'},
                {id: 'cccc', name: '家用家电'},
                {id: 'dddd', name: '电脑办公'},
            ]
        }
    },
    methods: {
        btnClick(item) {
            // 要把item传给父组件
            // 1. 发送一个事件 (自定义事件)
            // 会把item当成默认的传到父组件去
            this.$emit('itemclick', item)
        ]
    }
}

// 父组件
const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈'
    },
    components: {
        cpn
    },
    methods: {
        // 3. 父组件监听的事件 
        cpnClick(item) {
            console.log('成功了', item);
        }
    }
})

父子组件通讯-双向绑定

  • $children: 拿所有子组件
  • $refs: 拿指定的子组件
// this.$children是一个数组类型, 它包含所有子组件对象  
// 通过遍历, 取出所有子组件的message状态  

<div id="app">
    <cpm></cpn>
    <cpm></cpn>
    // 使用$refs的时候, 在想要访问的子组件上添加ref属性
    <cpm ref="aaa"></cpn>
    <buttun @click="btnClick">按钮</button>
</div>

<template id="cpn">
    <div>
        我是子组件
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈'
    },
    methods: {
        btnClick() {
            cosole.log(this.$children);
            // $children 的使用方法, 一般用的少, 下标不固定
            // this.$children[0].showMessage();
            // this.$children[0].name;
            
            //for (let c of this.$children) {
            //    console.log(c.name); // 我是子组件的name
            //    c.showMessage(); // showMessage
            //}
            
            // $refs 的使用方法 => 对象类型, 默认是一个空的对象
            console.log(this.$refs.aaa.name); // 我是子组件的name
        }
    }
    components: {
        cpn: {
            template: "#cpn",
            data() {
                return {
                    name: '我是子组件的name'
                }
            },
            methods: {
                showMessage() {
                    cosole.log('showMessage');
                }
            }
        }
    }
})

子组件访问父组件

  • $parent: 上一级父组件
  • $root: 根组件
<div id="app">
    <cpm></cpn>
</div>

<template id="cpn">
    <div>
        <ccpn></ccpn>
    </div>
</template>

<template id="ccpn">
    <div>
        <h2>我是子组件</h2>
        <button @click="btnClick">按钮</button>
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈'
    },

    components: {
        cpn: {
            template: "#cpn",
            data() {
               return {
                   name: '我是cpn的name'
               } 
            },
            conmponents: {
                ccpn: {
                    template: '#ccpn',
                    btnClick() {
                        // 1. 访问父组件$parent
                        // 不建议这么写, 一层套一层 复用性太差
                        console.log(this.$parent);  
                        console.log(this.$parent.name);  // 我是cpn的name
                        
                        // 2. 访问根组件 $root
                        console.log(this.$root.meassage);   // 哈哈哈
                    } 
                }
            }
        }
    }
})

插槽slot:

作用:
组件的插槽是为了让我们封装的组件更加具有扩展性
让使用者可以决定组件内部的一些内容到底展示什

基本使用

  1. 插槽的基本使用
  2. 插槽的默认值 button
  3. 如果有多个值同时放入到组件进行替换时, 一起作为替换元素
<div id="app">
    // 使用默认值替换
    <cpm></cpn>
    // 插槽替换的元素
    <cpm><span>这是替换的内容呀</span></cpn>
    // 多个元素
    <cpm>
        <div>第一个元素</div>
        <p>第二个元素</p>
    </cpn>
</div>

<template id="cpn">
    <div>
        <div>这个是标题</div>
        <p>这个是内容</p>
        // 放入插槽
        <slot>默认值元素</slot>
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈'
    },
    components: {
        cpn: {
            template: '#cpn'
        }
    }
})

具名插槽:

<slot name='aa'></slot> 使用name属性给插槽命名
                使用 <template v-slot:aa></template> 标签和v-slot指令来使用

<div id="app">
    <cpm></cpn>
    <cpm><button slot="left">返回</button></cpn>
    <cpm><span slot="center">中间标题</span></cpn>
</div>

<template id="cpn">
    <div>
        <slot name="left"><span>左边</span></slot>
        <slot name="center"><span>中间</span></slot>
        <slot name="right"><span>右边</span></slot>
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        meassage: '哈哈哈'
    },
    components: {
        cpn: {
            template: '#cpn'
        }
    }
})

作用域插槽:父组件模板所有的东西都在父级作用域内编译, 子组件模板的所有东西会在子级作用域内编译!

<div id="app">
    <cpm v-show="isShow">我是一</cpn> // true
</div>

<template id="cpn">
    <div>
        <p v-show="isShow">我是二</p> // false
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        isShow: true // Vue实例中的属性
    },
    components: {
        cpn: {
            template: '#cpn',
            data() {
                return {
                     isShow: false // 子组件中的属性
                }
            }
        }
    }
})

作用域插槽使用:

父组件替换插槽的标签, 但是内容由子组件来提供

<div id="app">
    <cpm></cpn> 
    <cpm>
        // 2. 获取子组件中的num
        <template slot-scope="slot">
            // 根据之前的起名来取  如 slot.aaa
            <span  v-for="item in slot.data">{{item}}</span>
        </template>
    </cpn> 
    <cpm></cpn> 
</div>

<template id="cpn">
    <div>
        // 1. slot定义  'data'可以随便起名 如 :aaa="num"
        <slot :data="num">
            <ul>
                <li v-for="item in num">{{item}}</li>
            </ul>
        </slot>
    </div>
</template>

const app = new Vue({
    el: '#app',
    data: {
        message: '哈哈哈'
    },
    components: {
        cpn: {
            template: '#cpn',
            data() {
                return {
                    num: ['1', '2', '3', '4', '5']
                }
            }
        }
    }
})

        喜欢的小伙伴点个赞吧,关注博主受益多多 !!!        

下篇vuex

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值