• vue组件的一个总结


    用vue进行开发到目前为止也有将近一年的时间了,在项目技术选型的时候隔壁组选 react的时候我们坚持使用vue作为前端的开发框架。虽然两者思想上的差异不大,但是vue的语法在代码的可读性以及后期的维护成本更加的适合,而且最近看到Apache对react的相关许可限制;这里不讨论react和vue的对比哪个好,技术框架没有最好的,只有适合项目才是最好的。

    进入主题。。。。。。。

    组件,是vue的核心之一。


    我们可以把页面各个子模块看成一个组件,可以独立拆分出来。这样不仅维护变得简单了,而且代码复用性也高。

    vue组件分为全局组件和局部组件。组件中属性和vue实例基本类似,基本可以使用其所有属性如computed,methods,components,filter,directive.....但data属性不同,在组件中data是函数,而且数据需要return出来;因为组件可能会被引用多次,就会创建多次实例,如果data是个对象的话那引用到这个组件的地方都将公用一个data这样就回造成了数据的污染。如果使用data属性函数返回一个对象的话就可以解决这个问题,每次引入到这个组件实例的时候就可以在data函数中返回一个初始的数据对象。

    组件的介绍

    全局组件

    使用Vue.component进行全局注册,所有vue实例都会共享此组件

     1   <div id="app">
     2         {{msg}}
     3         <const-comp></const-comp>
     4     
     5     </div>
     6     <script>
     7         
     8         Vue.component('constComp', {
     9             template: "<h3>我是全局组件</h3>"
    10 
    11         });
    12 
    13         new Vue({
    14             el: "#app",
    15             data: {
    16                 msg: "hello component"
    17             }
    18         });
    19 
    20     </script>

    局部组件

    局部组件只能在引入当前的vue实例中有效,在当前vue实例中components属性加上引入进来的组件实例即可

        <div id="app">
            {{msg}}
            <!-- <const-comp></const-comp> -->
            <local-comp></local-comp>
        </div>
        <script>
            
            /*Vue.component('constComp', {
                template: "<h3>我是全局组件</h3>"
    
            });*/
            let localComp = {
                template: "<div>我是局部组件</div>"
            };
            new Vue({
                el: "#app",
                data: {
                    msg: "hello component"
                },
                components: {
                    localComp
                }
            });
    
        </script>    

    单文件组件(xxx.vue)

    其实就是将写在js中的组件提出到一个vue文件中写而已,这样组件更加的好维护以及阅读性也会好,提取出来了相应的引入即可,不会显得文件很多行很长。

    其主要有<template></template><script></script><style></style>这三个标签,每个标签做自己的事。template就像我们在html中写dom,script写js代码当前的组件实例,style写组件样式,注意:加上scoped即可使当前样式只在当前组件生效,组件渲染的时候此组件的dom会加上data-v-xxx属性来选择当前组件样式。如果没加上scoped的话当前组件的样式就会在引入这个组件的实例中造成影响

    如我写的一个found.vue文件demo

     1 <template>
     2     <div>
     3         <div class="saerchDiv">
     4             <Search
     5             @result-click="resultClick"
     6             @on-change="changeResult"
     7             :results="results"
     8             v-model="searchVal"
     9             position="absolute"
    10             auto-scroll-to-top
    11             top="46px"
    12             @on-focus="onFocus"
    13             @on-cancel="onCancel"
    14             @on-submit="onSubmit"
    15              ref="search"></Search>
    16         </div>
    17 
    18     </div>
    19 </template>
    20 <script>
    21 import {Search} from 'vux';
    22 
    23 export default {
    24     name:"found",
    25     data() {
    26         return {
    27             msg:"found page",
    28             // searchVal:"寻找更多好文章",
    29             searchVal:"",
    30             results:[]
    31         }
    32     },
    33     components:{
    34         Search
    35     },
    36     methods:{
    37         resultClick(item) { //选中搜索
    38             console.log(item.title);
    39         },
    40         changeResult(val) { //获取搜索关键字
    41             console.log(val);
    42             /*this.$http.get('').then(res => {
    43 
    44             }).catch(err => {
    45 
    46             });*/
    47 
    48             this.results = this.getResults(val);
    49         },
    50         onFocus(){
    51             console.log("on focus");
    52             // this.searchVal = ""
    53         },
    54         onCancel(){
    55             console.log("点击取消按钮");
    56         },
    57         onSubmit(){
    58             console.log("on submit");
    59         },
    60         getResults(keyword) { //暂时获取假数据
    61             let rsArr = [];
    62             for(let i = 0; i < 6; i++) {
    63                 rsArr.push({
    64                     title:keyword + (i+1),
    65                     other:i //文章id
    66                 });
    67             }
    68             return rsArr;
    69         }
    70 
    71     }
    72 }
    73 </script>
    74 <style scoped>
    75 
    76     .saerchDiv {
    77         height: .75rem;
    78         font-size: .27rem;
    79     }
    80 
    81 </style>
    View Code

    组件的通信

    vue组件的通信是vue组件的核心,组件不仅仅是要把模板的内容进行复用;更主要的是组件间要进行通信;组件之间的通信数据传递是组件的生命力之一。

    props单向数据流,父组件向子组件传递数据

    props可以是一个数据类型也可以是一个数组,也可以是对象,对象下的数据有3个属性type,default,require。其中default,require值都是布尔类型值。type有Number,String,Boolean,Array,Object,Function,Symbol。如果props数据是对象或数组时默认值default必须是一个函数来返回初始化数据。而且因为对象或数据是引用类型,指向的是同一个内存空间所以当props数据是这两个类型时,数据改变时子组件内改变是会影响父组件的。

     props数据类型及相关样例

     1 // props: ['propsDataA'],
     2         props: {
     3             propA: {
     4                 type: String,
     5                 default: "",
     6                 require: true
     7             },
     8             propB: {
     9                 type: Number,
    10                 default: 1,
    11                 require: false
    12             },
    13             propC: {
    14                 type: Array,
    15                 default: function() {
    16                     return [];
    17                 },
    18                 require: true
    19             },
    20             propD: {
    21                 type: Object,
    22                 default: function() {
    23                     return {};
    24                 },
    25                 require: true
    26             },
    27             propE: {
    28                 type: Function,
    29                 fn: function(val) { //一个时间未满两位数前面补零验证
    30                     return val > 9 ? val : '0' + val;
    31                 },
    32                 require: true
    33             },
    34             propF: {
    35                 type: Boolean,
    36                 default: false,
    37                 require: true
    38             },
    39             propG: [String, Number],
    40             propH: Number
    41         }
    View Code

    这里稍微改动一下局部组件的代码,父组件向子组件传递数据;

     1    <div id="app">
     2         {{msg}}
     3         <!-- <const-comp></const-comp> -->
     4         <local-comp :props-a="info"></local-comp>
     5     </div>
     6     <script>
     7         
     8         /*Vue.component('constComp', {
     9             template: "<h3>我是全局组件</h3>"
    10 
    11         });*/
    12         let localComp = {
    13             template: "<div>我是局部组件<p>父组件传过来的数据为-->{{propsA}}</p></div>",
    14             props: {
    15                 propsA: {
    16                     type: String,
    17                     default: "",
    18                     require: true
    19                 }
    20             }
    21         };
    22         new Vue({
    23             el: "#app",
    24             data: {
    25                 msg: "hello component",
    26                 info: "hello props"
    27             },
    28             components: {
    29                 localComp
    30             }
    31         });
    32 
    33     </script>

    自定义事件$emit,子组件向父组件通信

    这里还是在原来的基础上改,子组件使用$emit自定义一个send事件向父组件发送数据

     1    <div id="app">
     2         {{msg}}
     3         <!-- <const-comp></const-comp> -->
     4         <div>子组件数据为---->{{fromChildData}}</div>
     5         <local-comp :props-a="info" @send="getChildData"></local-comp>
     6     </div>
     7     <script>
     8         
     9         /*Vue.component('constComp', {
    10             template: "<h3>我是全局组件</h3>"
    11 
    12         });*/
    13         let localComp = {
    14             template: "<div>我是局部组件
    15                     <p>父组件传过来的数据为-->{{propsA}}</p>
    16                     <button @click='sendMsg'>使用$emit子组件向父组件传递事件</button>
    17                 </div>",
    18             props: {
    19                 propsA: {
    20                     type: String,
    21                     default: "",
    22                     require: true
    23                 }
    24             },
    25             data() {
    26                 return {
    27                     msg: "子组件数据"
    28                 }
    29             },
    30             methods: {
    31                 sendMsg(evt) {
    32                     this.$emit('send', this.msg);
    33                 }
    34             }
    35         };
    36         new Vue({
    37             el: "#app",
    38             data: {
    39                 msg: "hello component",
    40                 info: "hello props",
    41                 fromChildData: ""
    42             },
    43             components: {
    44                 localComp
    45             },
    46             methods: {
    47                 getChildData(val) {
    48                     this.fromChildData = val
    49                 }
    50             }
    51         });
    52 
    53     </script>

    非子父组件通信,使用一个空的Vue实例作为一个事件总线监听数据变化

    这种场景用于组件之间不为子父层级关系的时候相关通信,我们使用的那个空vue实例里也可以放vue的属性。用这个空的vue实例来$emit自定义一个事件然后再用这个实例来$on监听自定义事件,从而达到非子父组件之间的通信。(PS:这里暂时不讨论vuex),看demo代码。demo例子使用了ref组件索引。

        <div id="app">
            {{message}}
            <component-a ref="a"></component-a>
            <component-a ref="b"></component-a>
        </div>
        <script>
            const bus = new Vue({});
    
            Vue.component('component-a', {
                data () {
                    return {
                        msg: 1
                    }
                },
                template: '<button @click="handleEvent">传递事件</button>',
                methods: {
                    handleEvent () {
                        bus.$emit('on-message', '来自组件 com-a 的内容');
                    }
                }
            });
    
    
            const app = new Vue({
                el: '#app',
                data: {
                    message: ''
                },
                mounted () {
                    bus.$on('on-message', (msg) => {
                        this.message = msg;
                    });
    
                    this.$children.msg = 2;
    
                }
            })
        </script>

    slot组件内容分发

    单个就默认slot,多个使用具名slot,$slots访问对应slot,vue2.0新增;因为vue2使用render函数来渲染,所以需要使用this.$slots来访问slot。this.$slots.xxx访问具体的slot,即slot中name指定的值 值类型{ [name: string]: ?Array<VNode> }

    如果需要给slot添加默认内容的时候直接在slot上写就可以了,这个时候默认的slot内容所在的作用域就是其所在的组件实例,可以根据其所在的组件来控制slot默认的内容展示如:<slot>{{msg}}</slot>。如果没有指定默认数据的话slot内容根据其父组件所在的作用域。

    当 vue 组件中当需要组件混合使用的时候需要用到内容分发,内容不确定的时候需要用到slot内容分发。

    看demo代码;

     1        <div id="app">
     2         <com-out>
     3             <div slot="b">{{msgB}}</div>
     4             <div slot="a">{{msgA}}</div>
     5             
     6         </com-out>
     7     </div>
     8     <template id="co">
     9         <div>
    10             hello 
    11             <slot name="a"></slot> 
    12             <slot name="b"></slot>
    13         </div>
    14     </template>
    15     <script>
    16         Vue.component('com-out', {
    17             template: "#co",
    18             mounted() {
    19                 console.log("com-out slot" + this.$slots.a[0]);
    20             }
    21         });
    22         new Vue({
    23             el: "#app",
    24             data: {
    25                 msgA: '父组件数据a',
    26                 msgB: '父组件数据b'
    27             }
    28         })
    29     </script>    

    递归组件

    递归组件要记住两点:

    1.递归组件必须要给组件设置name。

    2.要在一个合适的时间(条件)跳出递归否则会报栈溢出异常。

     1 <div id="app">
     2         <com :count="1"></com>
     3     </div>
     4     <template id="cr">
     5         <div><com :count="count + 1" v-if="count < 3"></com>{{count}}</div>
     6     </template>
     7     <script>
     8         Vue.component('com', {
     9             name: 'comr',
    10             template: "#cr",
    11             props: {
    12                 count: {
    13                     type: Number,
    14                     default: 1
    15                 }
    16             }
    17         })
    18         new Vue({
    19             el: '#app'
    20         })
    21 
    22 
    23     </script>

    动态组件

    vue动态组件其实就是在组件中使用:is属性根据值来判断显示哪个组件。

     1 <div id="app">  
     2         <button @click="changeCom">点击让子组件显示</button>  
     3         <com v-bind:is="activeCom"></com>  
     4     </div>  
     5 <script>  
     6     new Vue({  
     7         el: '#app',  
     8         data: {  
     9             activeCom: "comA"  
    10         },  
    11         methods: {  
    12             changeCom: function () {   
    13                 let arr = ["comA", "comB", "comC"], index; 
    14                 index = Math.ceil(Math.random()*arr.length);
    15                 this.activeCom = arr[index];
    16             }  
    17         },  
    18         components: {  
    19             comA: {  
    20                 template: "<div>组件comA</div>"  
    21             },  
    22             comB: {   
    23                 template: "<div>组件comB</div>"  
    24             },  
    25             comC: {   
    26                 template: "<div>组件comC</div>"  
    27             },  
    28         }  
    29     });  
    30 </script>  

    异步组件

    异步组件在性能上有一定的优势,不仅加快了渲染时间也减少了不必要的加载;在路由中经常用到

    看demo;

    <div id="app">
            <child-component></child-component>
            
        </div>
        <script>
            Vue.component('child-component', function (resolve, reject) {
                window.setTimeout(function () {
                    resolve({
                        template: '<div>异步组件的内容</div>'
                    })
                }, 2000)
            });
            new Vue({
                el: '#app'
            })
        </script>

     在路由中异步组件可以这样用:

    1 {
    2     path:"/路由地址",
    3     name:"routeName",
    4     component: resolve => require(["../components/xxx.vue"],  resolve)
    5 }

    组件相关属性

    $nextTick  虚拟dom完成后触发回调。进行dom操作。不过相关dom操作一般都建议放在指令中,或者自己自定义指令来进行操作,用合适的方式来做合适的事效果才能达到最优。

    $ref当组件使用ref来作为索引时$ref获取当前组件

  • 相关阅读:
    媒介管理系统权限设计方案
    document.ready和window.onload区别,顺带jQuery的ready方法
    nvm管理node版本
    async await一些小结
    Git学习
    详解JavaScript中的正则表达式
    JavaScript中的事件循环机制跟函数柯里化
    前端面试遇到的问题
    ES6在工作中会用到的核心知识点讲解
    JavaScript中的事件委托机制跟深浅拷贝
  • 原文地址:https://www.cnblogs.com/leungUwah/p/7257947.html
Copyright © 2020-2023  润新知