• vue 基础-->进阶 教程(3):组件嵌套、组件之间的通信、路由机制、slot传值


    前面的nodejs教程并没有停止更新,因为node项目需要用vue来实现界面部分,所以先插入一个vue教程,以免不会的同学不能很好的完成项目。

    本教程,将从零开始,教给大家vue的基础、高级操作、组件封装等,再配合前面的Nodejs后台,实现一个完整的项目。

    组件嵌套


    在组件中使用components定义子组件,可以定义多个,定义好以后,就可以在组件的模板中使用子组件了。看下面示例:具体解释在注释中

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
    
    <div id="box">
        <aaa></aaa>
    </div>
    
    <!--模板可以使用 template标签写到外面,然后在 componets里面调用-->
    <template id="temA">  
        <div>
            <h3>我是:{{msg}}</h3>
            <bbb></bbb>  <!-- 调用子组件 -->
        </div>
    </template>
    
    <script>
        var vm=new Vue({
            el:'#box',
            components:{
                'aaa':{
                    data:function(){
                        return{
                            msg:'父组件'
                        }
                    },
                    methods:{
                        test:function(){
                            alert("我是父组件")
                        }
                    },
                    template:'#temA',/*父组件的模板*/
                    components:{
                        'bbb':{
                            template:"<h3>我是子组件</h3>"
                        }
                    }
                }
            }
        })
    </script>
    </body>
    </html>

    父子组件之间的通信

    使用 v-bind:  (或直接用冒号) 传递数据,使用props接收数据,先看如下代码

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
    
    <div id="box">
        <aaa></aaa> <!--父组件的调用-->
    </div>
    
    <template id="temA">  <!--模板可以使用 template标签写到外面,然后在 componets里面调用-->
        <div>
            <h3>我是:{{msg}},子集显示 ==>{{msg2.text}}</h3>
            <bbb :m1="msg1" :m2="msg2"></bbb>   <!--调用子组件,使用  :键名=值(对应父组件data中的值)  去传参数-->
        </div>
    </template>
    
    <script>
        var vm=new Vue({
            el:'#box',
            components:{
                'aaa':{
                    data:function(){
                        return{
                            msg:'父组件',
                            msg1:"父级的共享数据1",
                            msg2:{             /*父组件往子组件传的一般只不能子集修改,只有传对象格式,子集中就可以修改了,父组件也同时改了*/
                                text:"父级的共享数据2",
                                style:{
                                    height:"100px",
                                    background:"orange"
                                }
                            }
                        }
                    },
                    methods:{
                        test:function(){
                            console.log("父组件的方法已调用");
                        }
                    },
                    template:'#temA',/*当前组件里调用子组件*/
                    components:{
                        'bbb':{
                            props:["m1","m2"],   /* 需要使用的数据,使用数组参入 ,和函数的形参很像,然后在调用的地方使用 v-bind传入 */
                            template:"<div><h3 @click='showMsg'>我是bbb组件,我使用的父级数据 ==>{{m1}},{{m2.text}} </h3></div>",
                            methods:{
                                showMsg:function(){
                                    this.m2.text = "值被子组件修改了";
                                    this.$parent.test();
                                }
                            }
    
                        }
                    }
                }
            }
        })
    </script>
    </body>
    </html>

    解释一下数据的传递流程(以msg2为例):在父组件中的数据中有个msg2数据,在模板中调用子组件的时候 以名为 m2 传递给了子组件 ,然后在子组件中就可以通过props接收到,这样在子组件中就可以使用变量 this.m2访问到 父组件的 msg2对应的值了。(如果传的值是对象,则传递引用指针,如果传递的是基本类型,则直接将值传递过去)

    运行:

    当点击子组件的h3标签,触发子组件的showMsg方法,在方法中,我们通过 this.m2.text改变了父级的msg2.text的值。通过  this.$parent.方法名    可以直接访问父组件里的方法。

    点击bbb后


    非父子组件之间的通信

    上面我们使用props只能解决父子组件之间的通信,当两个兄弟关系的组件,就不能这样传递了

    兄弟节点之间需要使用 事件的触发方法 $emit去实现

    先看代码:具体解释在注释中

    代码中,我们声明了一个独立的空Vue公用实例,用来触发通讯的事件。在a组件中使用 $emit触发事件,在 c组件中使用on监听事件,就可以实现数据的传递了。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
       <div id="box">
           <com-a></com-a> <!-- 调用com-a组件 -->
           <com-c></com-c><!-- 调用com-c组件 -->
       </div>
    <script>
       var Event=new Vue();  // 声明一个独立的空Vue公用实例,用来触发通讯的事件
    
        var a={
            template:'<div><span>我是a组件,我的数据内容是{{msga}}</span><br><input type="button" value="我要发送数据" @click="send"></div>',
            data(){
                return{
                 msga:'我是a数据,我要发送给兄弟组件'
                }
            },
            methods:{
                send(){
                    Event.$emit('a-msg',this.msga)  //触发前面 Event 公用示例的方法,那么别的地方就可以想办法监听接收这个事件。参数(事件名,传输的值)
                }
            }
        };
        var c={
            template:"<div><h3>这是C组件</h3><span>我从A里面接受的数据:{{a}}</span></div>",
            data(){
                return{
                    a:''
                }
            },
            mounted(){    //这里的mouted表示当组件和页面挂载完成的时候,需要执行的函数
                var _this = this;  //因为在Event.on内部的this是指向 Event实例的,所以这里,先使用 _this将this存起来,后面就可以使用了。
                Event.$on('a-msg',function (a) {  //使用on监听事件 a-msg,这样当a组件中使用 emit主动触发了 Event实例的a-msg事件之后,这里就可以接收到
                    alert('触发了接收');
                    _this.a = a;
                })
            }
        };
        new Vue({
            el:'#box',
            components:{
                'com-a':a,
                'com-c':c
            }
        })
    
    
    </script>
    
    </body>
    </html>

     当点击发送数据按钮,数据就传输给了c组件。


    路由


     路由可以让我们在页面中加载不同的模板内容,

    使用vue的路由,需要借助vue-router.js

        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

    我们使用路由配置一个tab切换,点击首页和列表分别显示不同内容,并且点击的时候,url中的路径会发生对应的改变。

    代码如下:代码解释在注释中。

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>
    <body>
        <div id="box">
            <div>
                <router-link to="/home">首页</router-link> <!-- 会被vue识别,自动显示成a标签-->
                <router-link to="/List">列表</router-link> <!-- 会被vue识别,自动显示成a标签-->
            </div>
            <div>
                <router-view></router-view>    <!-- 点击上面的link标签由,需要显示模板的地方 -->
            </div>
        </div>
    </body>
    <script>
        /*组件*/
        var Home = {
            template:"<h3>我是主页的内容</h3>"
        };
        var List = {
            template:"<h3>我是文章列表</h3>"
        };
    
        //配置路由
        var routerArr=[
            {
                path:"/home", /* router-link 的 to跳转的地址 */
                component:Home  /* 路径对应的组件 */
            },
            {
                path:"/List", /* router-link 的 to跳转的地址 */
                component:List  /* 路径对应的组件 */
            },
            {path:"*",component:Home}  /*其他的所有情况,都跳转到首页*/
        ];
    
        //生成路由示例
        var router= new VueRouter({
            routes:routerArr
        });
    
        //vue实例
        var vm=new Vue({
            el:'#box',
            data:{},
            /* 示例挂载路由 */
            router:router
        })
    </script>
    </html>

    二级路由:具体解释在注释中

    注:

    二级路由使用children来配置 ,内部配置和一级路由一样

    tab切换中的当前选项标签会自动添加 router-link-active类,我们只需要设置该类的样式,就可以实现当前选中的样式了。

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            body{
                padding: 30px;
            }
            ul, li{
                display: inline-block;
                list-style: none;
            }
            #box a{
                text-decoration: none;
                color: #2479dc;
                padding: 5px 15px;
            }
            #box .router-link-active{
                background: #2479dc;
                color: #fff;
            }
        </style>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>
    <body>
        <div id="box">
            <div>
                <router-link to="/home">首页</router-link> <!-- 会被vue识别,自动显示成a标签-->
                <router-link to="/List">列表</router-link>
                <router-link to="/users">用户</router-link>
            </div>
            <div>
                <router-view></router-view>    <!-- 点击上面的link标签由,需要显示模板的地方 -->
            </div>
        </div>
    
        <!-- 模板 temUser -->
        <template id="temUser">
            <div>
    
                <h3>用户信息</h3>
                <hr/>
                <ul>
                    <li><router-link to="/users/xiaoming">小明</router-link></li>
                    <li><router-link to="/users/xiaohong">小红</router-link></li>
                </ul>
                <div>
                    <router-view></router-view>    <!-- 点击上面的link标签由,需要显示模板的地方 -->
                </div>
            </div>
        </template>
    
    </body>
    <script>
        /*组件*/
        var Home = {
            template:"<h3>我是主页的内容</h3>"
        };
        var List = {
            template:"<h3>我是文章列表</h3>"
        };
        //用户
        var users = {
            template:"#temUser"
        };
    
        var xiaoming = {
            template:"<h3>我是小明</h3>"
        }
        var xiaohong = {
            template:"<h3>我是小红</h3>"
        }
    
        //配置路由
        var routerArr=[
            {
                path:"/home", /* router-link 的 to跳转的地址 */
                component:Home  /* 路径对应的组件 */
            },
            {
                path:"/List", /* router-link 的 to跳转的地址 */
                component:List  /* 路径对应的组件 */
            },
            {
                path:"/users", /* router-link 的 to跳转的地址 */
                component:users,  /* 重定向到首页 */
                children:[        /* 二级路由使用children来配置 ,内部配置和一级路由一样 */
                    {path:"xiaoming",component:xiaoming},
                    {path:"xiaohong",component:xiaohong}
                ]
            },
            {path:"*",component:Home}  /*其他的所有情况,都跳转到首页*/
        ];
    
        //生成路由示例
        var router= new VueRouter({
            routes:routerArr
        });
    
        var vm=new Vue({
            el:'#box',
            data:{},
            /* 示例挂载路由 */
            router:router
        })
    </script>
    </html>


     url参数传递


     在配置路由的时候,路径名前面加 冒号,就表示此路径为参数

    然后在模板中就可以使用 $route.params去访问到这个值了

    完整示例代码如下:

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            body{
                padding: 30px;
            }
            ul, li{
                display: inline-block;
                list-style: none;
            }
            #box a{
                text-decoration: none;
                color: #2479dc;
                padding: 5px 15px;
            }
            #box .router-link-active{
                background: #2479dc;
                color: #fff;
            }
        </style>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>
    <body>
        <div id="box">
            <div>
                <router-link to="/home">首页</router-link> <!-- 会被vue识别,自动显示成a标签-->
                <router-link to="/List">列表</router-link>
                <router-link to="/users">用户</router-link>
            </div>
            <div>
                <router-view></router-view>    <!-- 点击上面的link标签由,需要显示的内容 -->
            </div>
        </div>
    
        <template id="temUser">
            <div>
    
                <h3>用户信息</h3>
                <hr/>
                <ul>
                    <li><router-link to="/users/2/xiaoming/哈哈">小明</router-link></li>
                    <li><router-link to="/users/xiaohong/15">小红</router-link></li>
                </ul>
                <div>
                    <router-view></router-view>    <!-- 点击上面的link标签由,需要显示的内容 -->
                </div>
            </div>
        </template>
    
    </body>
    <script>
        /*组件*/
        var Home = {
            template:"<h3>我是主页的内容</h3>"
        };
        var List = {
            template:"<h3>我是文章列表</h3>"
        };
        //用户
        var users = {
            template:"#temUser"
        };
    
        var xiaoming = {
            template:"<h3>我是小明-{{$route.params.sysId}}{{$route.params.Id}}</h3>"
        }
        var xiaohong = {
            template:"<h3>我是小红-{{$route.params.sysId}}</h3>"
        }
    
        //配置路由
        var routerArr=[
            {
                path:"/home", /* router-link 的 to跳转的地址 */
                component:Home  /* 路径对应的组件 */
            },
            {
                path:"/List", /* router-link 的 to跳转的地址 */
                component:List  /* 路径对应的组件 */
            },
            {
                path:"/users", /* router-link 的 to跳转的地址 */
                component:users,  /* 重定向到首页 */
                children:[
                    {path:":Id/xiaoming/:sysId",component:xiaoming},
                    {path:"xiaohong/:sysId",component:xiaohong}
                ]
            },
            {path:"*",component:Home}  /*其他的所有情况,都跳转到首页*/
        ];
    
        //生成路由示例
        var router= new VueRouter({
            routes:routerArr
        });
    
        var vm=new Vue({
            el:'#box',
            data:{},
            /* 示例挂载路由 */
            router:router
        })
    </script>
    </html>

     点击  用户 -->  小红 ,然后可以看到我们url中的 "15",就传递到了模板中显示出来了。

     

    补充讲一个概念:槽/slot      用来接收标调用时传入的内部内容

    直接上代码,解释在注释中

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            *{
                margin: 0;
                padding: 0;
            }
            body{
                line-height: 30px;
                padding: 10px;
            }
        </style>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
    
    <div id="box">
        <who-h>
            <p>插入slot的值</p>  <!--  在组件调用的时候,标签内部的内容,会被放到template中定义的槽slot标签中 -->
            <ul>
                <li>ssss</li>
                <li>ssss</li>
                <li>ssss</li>
            </ul>
        </who-h>
    </div>
    
    <template id="temp01">  <!-- template 用来定义模板,需要指定一个id -->
        <div>               <!--  模板中的内容,只能包裹在唯一一个标签中  (最外层不能有多个标签) -->
            <h3>{{msg}}</h3>
            <slot></slot>  <!-- 用来接收标调用时传入的内部内容-->
        </div>
    
    </template>
    
    <script>
    
        var item = Vue.extend({
            data:function(){
                return {
                    msg:"示例的值"
                }
            },
            template:'#temp01'
        });
    
        var vm = new Vue({
            el:"#box",
            data:{},
            components:{  //可以配置多个内部组件
                "who-h":item    //组件命名的时候,最好都用引号引起来(当然,单个单词的时候不用也不报错)
            }
        })
        
    </script>
    
    </body>
    </html>

     显示结果我们可以看到,原来 slot所在的地方被传入的p和ul标签替代了

    上面是一个slot的情况,当如果我们要多个slot分开传值,我们就需要给slot指定名字,并且给传入的标签指定slot

    示例如下:具体的解释在注释中

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            *{
                margin: 0;
                padding: 0;
            }
            body{
                line-height: 30px;
                padding: 10px;
            }
        </style>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
    
    <div id="box">
        <who-h>
            <p slot="slot01">插入slot的值1(p)</p>  <!--  在组件调用的时候,标签内部的内容,会被放到template中定义的槽slot标签中,使用slot属性去指定插入哪个slot,如果不指定slot名,就插入没有名字的slot中 -->
            <ul slot="slot02">
                <li>插入slot的值2(ul)</li>
            </ul>
            <span>插入slot的值3(span)</span>
        </who-h>
    </div>
    
    <template id="temp01">  <!-- template 用来定义模板,需要指定一个id -->
        <div>               <!--  模板中的内容,只能包裹在唯一一个标签中  (最外层不能有多个标签) -->
            <h3>{{msg}}</h3>
            <slot></slot>  <!-- 用来接收标调用时传入的内部内容-->
            <slot name="slot01"></slot>
            <slot name="slot02"></slot>
        </div>
    
    </template>
    
    <script>
    
        var item = Vue.extend({
            data:function(){
                return {
                    msg:"示例的值"
                }
            },
            template:'#temp01'
        });
    
        var vm = new Vue({
            el:"#box",
            data:{},
            components:{  //可以配置多个内部组件
                "who-h":item    //组件命名的时候,最好都用引号引起来(当然,单个单词的时候不用也不报错)
            }
        })
        
    </script>
    
    </body>
    </html>

     结果如下,三个传入的值 分别插入到了对应的位置

    今天就讲到这里,vue就讲这么多,下次更新的时候,就是vue+nodejs的项目了。

    关注公众号,博客更新即可收到推送

  • 相关阅读:
    Bottle python
    mongodb python pymongo
    Directory常用
    File类常用
    Path类的常用方法
    winfrom的单例模式
    325工厂模式和面向对象知识点总结(有点乱凑合看)
    音乐播放器自动播放下一首歌记录
    c#分页类(转)
    c# 简历生成器
  • 原文地址:https://www.cnblogs.com/chengduxiaoc/p/7099552.html
Copyright © 2020-2023  润新知