• Vue组件基础用法


    一:组件的基本用法

    组件和创建Vue实例类似,需要先注册后才能使用,Vue组件注册方式分为全局注册和局部注册,全局注册的组件在任何使用Vue的地方均可使用,局部注册的组件只能在实例作用于范围内使用。

    全局注册:

    Vue.component('my-component', {
        template : '<div>这是组件中的内容</div>'
    });

     或者使用局部注册:

    var myTemplateContent = {
       template : '<div>这是组件中的内容</div>'
    };
    
    new Vue({
       el : '#app',
       components : {
          'my-component' : this.myTemplateContent
       }
    });

     使用组件:

    <div id="app">
       <my-component></my-component>
    </div>
    → 组件自定义标签名使用全小写加-符号的格式(如上例中的my-component)
    → 组件template中的DOM结构必须仅被一个元素包围,例如上面的template : '<div>这是组件中的内容</div>'如果写成template : '这是组件中的内容'或者写成template : '<div>这是组件中的内容</div><div>这是组件另一个的内容</div>'会无法渲染或者渲染不全。
    → 自定义的组件标签在有些时候使用会受到限制,例如:如果直接在<table>标签中使用<my-component>标签是无效的,解决方法是使用is属性来挂载组件:
    <div id="app">
        <table>
            <tbody is='my-component'></tbody>
        </table>
    </div>
     二:组件的选项
    组件和Vue实例一样,也可以有data,computed,methods选项,与Vue实例不同的是,data选项必须是一个函数,且将数据return出去(至于为什么要这样做,是因为组件是可以复用的,每个组件实例的数据应该互相独立互不影响,使用return返回一个数据对象可以保证每个组件的实例的数据都是独立的)。
    <body>
     <div id="app">
     <my-component></my-component>
     </div>
     <script>
        var myTemplateContent = {
            template : '<div>{{message}}</div>',
            data : function(){
                return {message : '这是组件中的内容'}
            }
        };
    
    
        new Vue({
            el : '#app',
            components : {
                'my-component' : this.myTemplateContent
            }
        })
     </script>
    </body>

    三:使用props在组件之间传递数据

    组件可以进行层级嵌套,父组件的data是不能直接被子组件访问的,需要通过props参数来传递数据,传递的值可以是一个字符串数组或者对象。

    使用字符串数组传递数据:
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <my-component message="来自父组件的数据"></my-component>
    11         </div>
    12 
    13         <script>
    14 
    15             var myTemplateContent = {
    16                 props : ['message'],
    17                 template : '<div>{{message}}</div>'
    18             };
    19 
    20             new Vue({
    21                 el : '#app',
    22                 components : {
    23                     'my-component' : this.myTemplateContent
    24                 }
    25             })
    26         </script>
    27     </body>
    28 </html>
    View Code

    在上述示例中,<my-component message="来自父组件的数据"></my-component>的message属性值可以是v-bind动态绑定的数据,当绑定的数据更新时,模板内容也会动态更新:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset=utf-8>
            <title>Test page</title>
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body>
            <div id="app">
                <input type="text" v-model='inputValue'>
                <my-component :message='inputValue'></my-component>
            </div>
    
            <script>
    
                var myTemplateContent = {
                    props : ['message'],
                    template : '<div>{{message}}</div>'
                };
    
                new Vue({
                    el : '#app',
                    components : {
                        'my-component' : this.myTemplateContent
                    },
                    data : {
                        inputValue : ''
                    }
                })
            </script>
        </body>
    </html>
    View Code

     上述代码示例中,当在input输入框中输入值时,会更新data中的inputValue,因此my-component组件的message属性值也会动态更新,组件的内容也随之动态更新。

    组件之间除了可以进行数据通信,还可以进行组件之间的事件调用,从而完成消息发送和接收。

    四:使用自定义事件从子组件向父组件传递数据

    类似观察者模式,在Vue中,子组件使用$emit()来触发事件,父组件使用$on()来监听子组件的事件。

    在下面的例子中,子组件my-component有两个按钮,handleIncrease和handleReduce分别用于增加和减少模板的data组件的counter值,然后使用$emit()方法通知父组件的increase和reduce方法。$emit()方法的第一个参数是自定义事件的名称,后续参数是要传递的数据。父组件使用handleGetTotal方法将接收到的参数赋值给自身的total值上。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset=utf-8>
            <title>Test page</title>
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body>
            <div id="app">
                <p>总数:{{total}}</p>
                <my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component>
            </div>
    
            <script>
    
                var myTemplateContent = {
                    template : '
                    <div>
                        <button @click="handleIncrease">+1</button>
                        <button @click="handleReduce">-1</button>
                    </div>',
                    data : function (){
                        return {counter : 0}
                    },
                    methods : {
                        handleIncrease : function(){
                            this.counter++;
                            this.$emit('increase', this.counter);
                        },
                        handleReduce : function(){
                            this.counter--;
                            this.$emit('reduce', this.counter);
                        }
                    }
                };
    
                new Vue({
                    el : '#app',
                    components : {
                        'my-component' : this.myTemplateContent
                    },
                    data : {total : 0},
                    methods : {
                        handleGetTotal : function(total){
                            this.total = total;
                        }
                    }
                })
            </script>
        </body>
    </html>
    View Code
    五:非父子组件之间的通信——中央事件总线bus
    在Vue.js 1.x版本中,使用$dispath()和$broadcast()两个方法来向上级或者下级派发广播事件,这两种方法发出的事件,任何组件都是可以接收到且根据就近原则,事件会在第一次被接收到后停止冒泡,除非处理事件的方法又再一次返回true。
    在Vue.js 2.x版本中,使用一个空的Vue对象作为中央事件总线,从而实现了任何组件之间的通信,包括父子组件、兄弟组件、跨级别组件,示例代码:
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <p>{{message}}</p>
    11             <my-component ></my-component>
    12         </div>
    13 
    14         <script>
    15             //空的Vue对象作为"中介"
    16             var bus = new Vue();
    17 
    18             var myTemplateContent = {
    19                 template : '<button @click="handleEvent">传递事件</button>',
    20                 methods : {
    21                     handleEvent : function(){
    22                         bus.$emit('on-message', '来自my-component组件中的内容')
    23                     }
    24                 }
    25             };
    26 
    27             new Vue({
    28                 el : '#app',
    29                 components : {
    30                     'my-component' : this.myTemplateContent
    31                 },
    32                 data : {message : ''},
    33                 mounted : function(){
    34                     var that = this;
    35                     //Vue实例初始化时,监听来自bus的事件
    36                     bus.$on('on-message', function(msg){
    37                         that.message = msg;
    38                     })
    39                 }
    40             })
    41         </script>
    42     </body>
    43 </html>
    View Code
    上面的代码,首先创建一个名为bus的空Vue实例,然后定义组件my-component,这个组件中有个按钮,按钮会触发bus组件的on-message方法,在app初始化mounted阶段监听bus的on-message事件,并在回调中完成自己的业务逻辑。
    除了使用中央事件总线,还可以使用父链或者子组件索引两种方式来完成组件通信。

    六:组件之间的通信——父链和子组件索引

    在子组件中,可以使用this.$parent来直接访问组件的父组件,父组件也可以用this.$children来访问它的所有子组件,且可以向上/向下无线递归访问,直到实例根元素或者最内层元素。实例代码:

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <p>{{message}}</p>
    11             <my-component ></my-component>
    12         </div>
    13 
    14         <script>
    15             //空的Vue对象作为"中介"
    16             var bus = new Vue();
    17 
    18             var myTemplateContent = {
    19                 template : '<button @click="handleEvent">通过父链直接修改数据</button>',
    20                 methods : {
    21                     handleEvent : function(){
    22                         this.$parent.message = '来自组件my-component的内容';
    23                     }
    24                 }
    25             };
    26 
    27             new Vue({
    28                 el : '#app',
    29                 components : {
    30                     'my-component' : this.myTemplateContent
    31                 },
    32                 data : {message : ''}
    33             })
    34         </script>
    35     </body>
    36 </html>
    View Code
    建议的做法,父子组件之间还是使用props和emit来传递数据,子组件应避免直接修改父组件的数据。
    在父组件中,如果通过使用this.$children得到子组件,然后通过遍历获取所需要的子组件是比较困难的,可以使用ref属性来为子组件指定索引名称,这样可以通过this.$refs.myRef来指定访问myRef这个子组件。
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <button @click="handleRef">通过ref获取子组件实例</button>
    11             <my-component ref="comMy"></my-component>
    12         </div>
    13 
    14         <script>
    15             var myTemplateContent = {
    16                 template : '<div>子组件</div>',
    17                 data : function(){
    18                     return {
    19                         message : '子组件内容'
    20                     }
    21                 }
    22             };
    23 
    24             new Vue({
    25                 el : '#app',
    26                 components : {
    27                     'my-component' : this.myTemplateContent
    28                 },
    29                 methods : {
    30                     handleRef : function(){
    31                         //通过refs访问指定的子组件实例
    32                         var msg = this.$refs.comMy.message;
    33                         console.log(msg)
    34                     }
    35                 }
    36             })
    37         </script>
    38     </body>
    39 </html>
    View Code

    $refs只在组件渲染完成后填充,并不是响应式的,应避免在模板和计算属性中使用$refs。

    七:使用slot插槽分发内容
      任何一个复杂的Vue组件都是由props传递数据、events触发事件和slot内容分发这三个部分构成的。当需要组合使用不同的组件,混合父组件的内容和子组件的模板时,就需要使用slot,这个过程叫内容分发。
      关于父子组件的作用域:父组件模板的内容在父组件作用域中编译,子组件模板的内容在子组件作用域中编译。
      slot分发的内容,作用域是在父组件上的,如下面的示例说明: 
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <!--这里的showChild绑定的是父组件的数据-->
    11             <my-component v-show="showChild"></my-component>
    12         </div>
    13         <script>
    14             var myTemplateContent = {
    15                 template : '<div>子组件</div>'
    16             };
    17             new Vue({
    18                 el : '#app',
    19                 components : {
    20                     'my-component' : this.myTemplateContent
    21                 },
    22                 data : {
    23                     showChild : true
    24                 }
    25             })
    26         </script>
    27 
    28         <div id="app2">
    29             <my-component ></my-component>
    30         </div>
    31         <script>
    32             var myTemplateContent = {
    33                 //这里的showChild绑定的是子组件的数据
    34                 template : '<div v-show="showChild">子组件</div>',
    35                 data : function(){
    36                     return {
    37                         showChild : true
    38                     }
    39                 }
    40             };
    41             new Vue({
    42                 el : '#app2',
    43                 components : {
    44                     'my-component' : this.myTemplateContent
    45                 }
    46             })
    47         </script>
    48     </body>
    49 </html>
    View Code

    (一)单个Slot插槽的用法 

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <child-component>
    11                 <p>分发的内容</p>
    12                 <p>更多分发的内容</p>
    13             </child-component>
    14         </div>
    15         <script>
    16             var myTemplateContent = {
    17                 template : '
    18                 <div>
    19                     <slot>
    20                         <p>如果父组件没有插入内容,此行文字将作为默认内容</p>
    21                     </slot>
    22                 </div>'
    23             };
    24             new Vue({
    25                 el : '#app',
    26                 components : {
    27                     'child-component' : this.myTemplateContent
    28                 }
    29             })
    30         </script>
    31     </body>
    32 </html>
    View Code
    (二)具名插槽的用法
    给slot指定name属性可以分发多个内容:
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <child-component>
    11                 <h2 slot="header">标题</h2>
    12                 <p>分发的内容</p>
    13                 <p>更多分发的内容</p>
    14                 <div slot="footer">底部信息</div>
    15             </child-component>
    16         </div>
    17         <script>
    18             var myTemplateContent = {
    19                 template : '
    20                 <div class="container">
    21                     <div class="header">
    22                         <slot name="header"></slot>
    23                     </div>
    24                     <div class="main">
    25                         <slot></slot>
    26                     </div>
    27                     <div class="footer">
    28                         <slot name="footer"></slot>
    29                     </div>
    30                 </div>'
    31             };
    32             new Vue({
    33                 el : '#app',
    34                 components : {
    35                     'child-component' : this.myTemplateContent
    36                 }
    37             })
    38         </script>
    39     </body>
    40 </html>
    View Code
    (三)作用域插槽的用法
    作用域插槽使用一个(可复用的)模板来代替已渲染的元素,示例:
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <child-component>
    11                 <template scope="props">
    12                     <p>来自父组件的内容</p>
    13                     <p>{{props.msg}}</p>
    14                 </template>
    15             </child-component>
    16         </div>
    17         <script>
    18             var myTemplateContent = {
    19                 template : '
    20                 <div class="container">
    21                     <slot msg="来自子组件的内容"></slot>
    22                 </div>'
    23             };
    24             new Vue({
    25                 el : '#app',
    26                 components : {
    27                     'child-component' : this.myTemplateContent
    28                 }
    29             })
    30         </script>
    31     </body>
    32 </html>
    View Code

    子组件的模板中,<slot msg="来自子组件的内容"></slot>向插槽传递了一个msg,父组件使用了template元素,且有一个scope="props"的属性,然后在template内部就可以使用props.msg来访问子组件传递过来的数据了。(注意到这里的scope="props"中的props只是一个临时变量,可以为任意名字)

    (四)访问slot
    在Vue.js 2.x中,可以使用$slots来访问被slot分发的内容。
     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset=utf-8>
     5         <title>Test page</title>
     6         <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
     7     </head>
     8     <body>
     9         <div id="app">
    10             <child-component>
    11                 <h2 slot="header">标题</h2>
    12                 <p>分发的内容</p>
    13                 <p>更多分发的内容</p>
    14                 <div slot="footer">底部信息</div>
    15             </child-component>
    16         </div>
    17         <script>
    18             var myTemplateContent = {
    19                 template : '
    20                 <div class="container">
    21                     <div class="header">
    22                         <slot name="header"></slot>
    23                     </div>
    24                     <div class="main">
    25                         <slot></slot>
    26                     </div>
    27                     <div class="footer">
    28                         <slot name="footer"></slot>
    29                     </div>
    30                 </div>',
    31                 mounted : function(){
    32                     var header = this.$slots.header;
    33                     var main = this.$slots.default;
    34                     var footer = this.$slots.footer;
    35                     console.log({
    36                         header,
    37                         main,
    38                         footer
    39                     })
    40                 }
    41             };
    42             new Vue({
    43                 el : '#app',
    44                 components : {
    45                     'child-component' : this.myTemplateContent
    46                 }
    47             })
    48         </script>
    49     </body>
    50 </html>
    View Code
  • 相关阅读:
    【IoT】IDEA 编译出错 Error running xxx : Command line is too long.Shorten command line
    【可视化】地震剖面道数据可视化绘制思路
    【IoT】使用MQTTBox.exe发送消息到Thingsboard3.3.3上
    【IoT】thingsboard3.3.3测试,使用nodemqtt发送消息
    【IoT】thingsboard3.3.3编译问题解决
    【Postgres】Postgres12帮助手册
    【IoT】发布启动thingsboard3.3.3
    【前端开发】Webpack mars3dvue2electron打包问题
    【可视化】地震数据体Segy文件inline、xline道数据计算获取
    【IoT】thingsboard3.3.3运行启动
  • 原文地址:https://www.cnblogs.com/zheng-hong-bo/p/12263133.html
Copyright © 2020-2023  润新知