首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue组件传值与插槽详解

vue组件传值与插槽详解

作者头像
生南星
发布2019-07-22 14:31:09
2.1K0
发布2019-07-22 14:31:09
举报
文章被收录于专栏:生南星生南星
  1. 父向子传值 父向子传值,需要使用props属性 通过props属性,实现 父==>子 传递数据, 数据流是单向的,父组件的数据发生改变影响子组件的值,但是子组件的值发生修改,父组件的值不变.

*子组件实例里写props对象,绑定属性,属性里可设置传入的数据类型和无数据传入时的默认值

*子组件里绑定属性接受父组件传来的数据

*将数据展示在页面中

//body
 <div id="app">
     <h2>这是app组件</h2>
      <child1 :child1msg="msg1" :child1-obj="obj"></child1>
</div>

<template id="child1">
        <fieldset>
            <legend><h2>这是child1组件</h2></legend>
            <p>父组件传入的值是:{{child1msg}}</p>
            <ul>
                <li v-for="(v,k) in child1Obj">{{v+'---'+k}}</li>
            </ul>
            <button @click="useParentFunc">点击调用父组件的方法</button>
        </fieldset>
</template>

//script
let child1 = {
            template:"#child1",
            props:{
                //props里属性名建议全小写字母,可以写成驼峰,但是驼峰的属性名在使用时,所有的单词首字母小写,中间加 - .
                child1msg:{
                    type:String,
                    default:"无"
                },
                child1Obj:{
                    type:Object,
                    default(){
                        return {
                            name:'你好',
                            age:0,
                            sex:'未知'
                        }
                    }
                },
            },
            methods: {
                useParentFunc(){
                    /*
                    * 子组件如何获取父组件的方法(实例)?
                    * 1. $parent: 访问当前组件的父组件实例
                    * 2. $root: 访问根组件实例
                    * */
                    console.log(this.$parent, this.$root);
                    console.log(this.$parent.sendMsg());
                }
            }
        };
        
let app = new Vue({
           el:'#app',
           data:{
                msg1:"app的msg1数据",
               obj:{
                   name:'卡卡西',
                   age:27,
                   sex:'男'
               }
           },
           methods:{
               sendMsg(){
                   return '这是父组件sendMsg方法返回的数据';
               }
           },
           components:{
               child1
           }

2. 子向父传值

Vue里, 子组件向父组件传值 使用的是事件发送和事件监听 子组件里发送事件,父组件里监听对应的子组件事件接收数据

父组件里获取child1的实例, 通过 $refs属性获取对应组件里的子组件

*在点击事件里通过$emit自定义事件,将要传递的参数传给监听器

*在子组件里绑定自定义事件,并定义方法接受收子组件传来的数据,方法里有形参.

*在父组件里定义该方法,参数为子组件传来的数据,在父组件里定义一个变量接收子组件传来的数据

//2.
<template id="child1">
        <fieldset>
            <legend><h2>这是child1组件</h2></legend>
            <button @click="sendMsgToApp">点击按钮向父组件发送消息</button>
        </fieldset>
</template>

//1.
let child1 ={
          template:'#child1',
            data(){
              return {
                  child1Msg: "这是child1的msg数据"
              }
            },
            methods: {
                sendMsgToApp(){
                    //发送消息, 事件名不能写成驼峰结构
                    this.$emit("child1-event",this.child1Msg);
                },
            }
        };
        
//3.
let app = new Vue({
           el:'#app',
           data:{
               appMsg:'',
               randomNum:0
           },
            methods:{
                getMsg(data){
                    console.log(data);
                    this.appMsg=data;
                },
            },
            components:{
                child1
            }
        });

3. 兄弟之间传值--中间人模式

1). 子向父传值

2). 父向子传值

上代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>兄弟组件传值_中间人模式</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <child1 @child-event="getChild1($event)"></child1>
        <child2 :child2msg="appMsg"></child2>
    </div>
    
    <template id="child1">
        <fieldset>
            <legend><h2>这是child1组件</h2></legend>
            <button @click="sendMsgToC2">点击向child2组件发送数据</button>
        </fieldset>
    </template>

    <template id="child2">
        <fieldset>
            <legend><h2>这是child2组件</h2></legend>
            <p>这是child1组件传递的数据: {{child2msg}}</p>
        </fieldset>
    </template>
    <script type="text/javascript">
        let child1={
            template:'#child1',
            data(){
                return {
                    child1Msg:'这是child1的msg数据'
                }
            },
            methods: {
                sendMsgToC2(){
                    this.$emit('child-event',this.child1Msg)
                }
            }
        };
        let child2={
            template:'#child2',
            data(){
                return {}
            },
            props:{
                child2msg:{
                    type:String,
                    default:'无数据'
                }
            }
        };
        let app = new Vue({
           el:'#app',
           data:{
                appMsg:''
           },
            methods:{
                getChild1(data){
                    this.appMsg=data;
                }
            },
            components:{
               child1,
                child2
            }
        });
</script>
</body>
</html>

4. 兄弟组件传值--消息发送

新建一个Vue实例,利用该实例发送消息,还利用该实例接收消息

* 在传递数据的子组件child1里定义点击事件,绑定事件,监听数据

* 在接收数据的子组件child2组件创建完毕之后(created)里监听自定义事件,并创建函数回调child1传递来的数据

* 将创建的函数写进child2的方法里,并定义变量接收数据. 显示在页面中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>兄弟组件传值_消息发送</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <child1></child1>
        <child2></child2>
    </div>

    <template id="child1">
        <fieldset>
            <legend><h2>这是child1组件</h2></legend>
            <button @click="sendMsgToChild2">点击向child2组件发送数据</button>
        </fieldset>
    </template>

    <template id="child2">
        <fieldset>
            <legend><h2>这是child2组件</h2></legend>
            <p>这是child1组件传递的数据: {{child2Msg}}</p>
        </fieldset>
    </template>
    <script type="text/javascript">
        //新建一个vue实例
        let totalVue = new Vue();
        let child1={
            template:'#child1',
            data(){
                return {
                    child1Msg:'这是child1里的数据msg',
                }
            },
            methods: {
                sendMsgToChild2(){
                    totalVue.$emit("child1-event",this.child1Msg);
                }
            }
        };
            let child2={
            template:'#child2',
            //在child2组件实例化完毕之后历可监听child1-event事件
            created(){
                totalVue.$on("child1-event",this.getChild1Msg)
            },
                data(){
                return {
                    child2Msg:''
                }
                },
            methods:{
                getChild1Msg(data){
                    console.log(data)
                    this.child2Msg=data
                }
            }
        };
        let app = new Vue({
           el:'#app',
           data:{
           
           } ,
            methods:{
            
            },
            components:{
                child1,
                child2
            }
        });
</script>
</body>
</html>

5. Vue插槽

插槽slot: slot的作用: 用来接收写在组件里的内容,这些内容会进入到slot里进行显示

5.1 普通插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>普通插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
       <child1>
            <ul>
                <li>这是列表项1</li>
            </ul>
        </child1>
    </div>
    
    <template id="child1">
        <fieldset>
            <legend><h2>这是child1组件</h2></legend>
            <p>这是child1的p标签</p>
            <slot></slot>
        </fieldset>
    </template>
    <script type="text/javascript">
        let child1={
            template:'#child1',
            data(){
                return {}
            }
        };
        
        let app = new Vue({
           el:'#app',
           components:{
               child1,
            }
        });
</script>
</body>
</html>

5.2 具名插槽

给模板里的slot组件添加name属性,表示插槽的名字,在传入的内容标签设置slot属性,值相同进入对应的slot. 凡是没有设置slot属性的标签统统会进入到没有设置name属性的slot组件里

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>具名插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
       <child2>
            <h3 slot="content">这是内容的h2</h3>
            <h3 slot="foot">这是尾部的h2</h3>
            <h3 slot="head">这是头部的h2</h3>
        </child2>
    </div>
    
    <template id="child2">
        <fieldset>
            <legend><h2>这是child2组件</h2></legend>
            <slot name="head"></slot>
            <slot name="content"></slot>
            <slot name="foot"></slot>
        </fieldset>
   </template>
    <script type="text/javascript">
        let child2={
            template: '#child2'
        };
        
        let app = new Vue({
           el:'#app',
           components:{
               child2,
            }
        });
</script>
</body>
</html>

自 Vue2.6.0 起 v-slot 指令被引入,提供更好的支持 slot 和 slot-scope 特性的 API 替代方案.具体写法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>具名插槽新写法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
       <child1>
            <template v-slot:header>
                <h1>Here might be a page title</h1>
            </template>
    
            <p>A paragraph for the main content.</p>
            <p>And another one.</p>
            
            <!--简写-->
            <template #footer>
                <p>Here's some contact info</p>
            </template>
        </child1>
    </div>
    
    <template id="child1">
        <div class="container">
            <header>
                <slot name="header"></slot>
            </header>
            <main>
                <slot></slot>
            </main>
            <footer>
                <slot name="footer"></slot>
            </footer>
        </div>
    </template>
    <script type="text/javascript">
        let child1={
            template:'#child1'
        };
        
        let app = new Vue({
           el:'#app',
           components:{
               child1,
            }
        });
</script>
</body>
</html>

5.3 作用域插槽

默认情况下,组件里的内容要绑定数据,其作用域是父级的作用域,如果想让器对应组建的作用域起效果需要使用作用域插槽写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>作用域插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
       <child3>
            <!--slot-scope 用来接收插槽的属性-->
            <template slot-scope="data">
                <p>这是p元素, 姓名是:{{data.c3Name}}, 年龄是:{{data.c3Age}}</p>
            </template>
        </child3>
    </div>
    
    <template id="child3">
        <fieldset>
            <legend><h2>这是child3组件</h2></legend>
            <slot :c3-name="name" :c3-age="age"></slot>
        </fieldset>
    </template>
    <script type="text/javascript">
        let child3={
            template: '#child3',
            data(){
                return {
                    name:'漩涡鸣人',
                    age:16
                }
            }
        };
        
        let app = new Vue({
           el:'#app',
           components:{
               child3,
            }
        });
</script>
</body>
</html>

自 Vue2.6.0 起在<template>上使用特殊的 slot-scope 特性可以接收传递给插槽的prop(把这里提到过的 <slot-example> 组件作为示例):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>作用域插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
       <child2>
            <template v-slot:default="slotProps">
                <p>名字是: {{slotProps.user.name}}</p>
                <p>类型是: {{slotProps.user.type}}</p>
            </template>
        </child2
    </div>
    
    <template id="child2">
        <div>
            <h2>这是child2</h2>
            <slot :user="child2Obj"></slot>
        </div>
    </template>
    <script type="text/javascript">
        let child2={
            template:'#child2',
            data(){
                return {
                    child2Obj:{
                        name:'child2',
                        type:'组件'
                    }
                }
            }
        };
        
        let app = new Vue({
           el:'#app',
           components:{
               child2,
            }
        });
</script>
</body>
</html>

用到更多:

* vue实例.$emit('自定义事件名',要传送的数据);

触发当前实例上的事件,要传递的数据会传给监听器;

* vue实例.$on('事件名',callback)---callback回调$emit要传送的数据; 监听当前实例上自定义事件;

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生南星 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档