深入浅出学习组件(一):组件基础知识梳理


组件(Component)是Vue.js最核心的功能,也是整个框架设计最精彩的部分。首先,我们对组件的相关知识进行梳理,为实战项目的完成打好基础。

一、组件化的概念、特征、优点

1、组件化的概念:

web中的组件是页面组成的一部分,就像电脑的元件,它们具有独立的逻辑和功能,但是又因为接口规则可以相互融合,使我们可以方便地使用。页面就是一个个类似的组件组成,比如导航、表单、下拉菜单等等,而页面就是它们这些组件的容器,组件可以在里面自由的组合,如果想改动、替换或者删除,可以修改组件或者直接删除,不会影响整个应用的运行。

2、组件化的特征:

1)组件化具有高内聚、低耦合的特性,既保证自身功能的完整性,又不会跟项目中的其它代码发生冲突。

2)每一个组件都有自己明缺的功能和职责,并且较低的耦合使单元测试和重复使用带来了方便。

3、组件化的优点:

  • 提高开发效率
  • 方便重复使用
  • 简化调试步骤
  • 提升整个项目的可维护性
  • 便于协同开发

二、Vue.js中的组件构成以及组件用法

1、Vue组件的构成

  • 样式及结构
  • 行为逻辑
  • 数据

2、组件用法
通常一个应用会以一棵嵌套的组件树的形式来组织:
组件的嵌套
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。

1)全局注册:

Vue.component('my-component-name', {
  // ... options ...
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。上面的代码中,my-component就是注册的组件自定义标签名称,推荐使用小写加减号分割的形式命名。

2)全局注册组件的使用

<div id="app">
    <my-component></my-component>
</div>
<script>
    Vue.component('my-component-name', {
      // ... options ...
    });
    var app = new Vue({
        el:'#app'
    })
</script>

这个时候注册的组件中没有任何内容,页面是空白的,可以在组件选项中添加template,以达到显示组件内容的目的,示例代码如下:

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

增加的是一个被html元素包裹的DOM结构,放在组件的template中就可以被渲染成:

<div id="app">
   <div>这里是组件的内容</div>
</div>

3)局部注册

在Vue实例中,使用components选项可以注册局部组件,注册后的组件只有在该实例作用域下有效。组件中也可以使用components选项来注册组件,使组件嵌套。示例代码如下:

<div id="app">
    <my-component></my-component>
</div>
<script>
    var Child = {
        template:'<div>局部注册组件的内容</div>';
    }
    var app = new Vue({
        el:'#app',
        components:{
            'my-component':Child
        }
    })
</script>

三、组件的复用

除了template选项外,组件中还可以像Vue实例那样使用其他的选项,比如data、compute、methods等,但是在使用data时,和实例稍有区别,data必须是函数,然后将数据return出去。

<div id="app">
   <first></first>
</div>
<script>
    Vue.component('first',{
        data:function () {
            return{
                msg:'hello'
            }
        },
        template:'<div>{{msg}}</div>'

    });

    var app = new Vue({
        el:'#app'
    })
</script>

JavaScript对象是引用关系,如果return出的对象引用了外部的一个对象,那这个对象就是共享的,任何一方修改都会同步,比如说:

<div id="app">
  	<counter></counter>
    <counter></counter>
    <counter></counter>
</div>
<script>
    Vue.component('counter',{
        template:'<button  @click="counter++">这个按钮被点击了{{counter}}次</button>',
        data:function(){
            return data;
        }
    });
	var app = new Vue({
        el:'#app',
     	data:{
            counter:0
        }
    })
</script>

组件使用了3次,但是点击任意一个按钮,3个数字都会加1,那是因为组件的data引用的是外部的对象,但是我们需要的是三个独立的按钮,所以给组件返回一个新的data对象来独立,示例代码如下:

<div id="app">
  	<counter></counter>
    <counter></counter>
    <counter></counter>
</div>
<script>
    Vue.component('counter',{
    data:function () {
        return{
            counter:0
        }
    },
    template:'<button  @click="counter++">这个按钮被点击了{{counter}}次</button>'
});
	var app = new Vue({
        el:'#app'
    })
</script>

这样,点击3个按钮就互不影响了,完全达到复用的目的。

所以得出结论:一个组件的 data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。

四、使用props由父组件向子组件传递数据

创建一个博文组件的时候。有一个问题,如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这就涉及到了组件间的通信,也正是 prop 的由来。

props的基本用法

由父组件向子组件正向传递数据的过程就是通过props来实现的,在组件中,使用选项props来声明需要从父级接收的数据,props的值可以是两种,一种是字符串数组,一种是对象。

1)字符串数组写法

我们构造一个数组,接收一个来自父级的数据message,并把它在组件模板中渲染,示例代码如下:

<div id="app">
    <my-component message="来自父组件的数据"></my-component>
    <!--数据message就是通过props从父级传递过来的,在组件的自定义标签上直接写该props的名称-->
</div>
<script>
    Vue.component('my-component',{
        props:['message'],
        template:'<div>{{message}}</div>'
    });
    var app = new Vue({
        el:'#app'
    })
</script>

渲染后的结果为:

<div id="app">
    <div>来自父组件的数据</div>
</div>

props中声明的数据与组件data函数return的数据主要区别就是:

  • props的数据来自父级
  • data中的是组件自己的数据,作用域是组件本身

这两种数据都可以在模板template及计算属性compute和方法methods中使用。如果想传递多个数据,在props数组中添加项即可。

由于HTML特性不区分大小写,当使用DOM模板时,驼峰命名(camelCase)的props名称要转化为短横分隔命名(kebab-case)。

2)对象写法(数据校验)

当props需要验证时,需要对象写法。

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}

验证的type类型可以是:

  • String

  • Number

  • Boolean

  • Object

  • Array

  • Function

当prop验证失败时,比如某个数据必须是数字类型,如果传入字符串,在开发版本下会在控制台抛出一条警告。

下面举一个面包屑导航的例子:

<div id="app">
    <bread-crumb :first="index"  :second="second" :third="third"></bread-crumb>
</div>
.bread-crumb  li {
    display: block;
    width: 80px;
    float: left;
}
li+li:before{
    display: inline-block;
    content: '/';
}
<script>
    Vue.component('bread-crumb', {
       props:{
            first:{
                type:String,
                default:'主页'
            },second:{
                type:String,
                default:'主模块'
            },third:{
                type:String,
                default:'小模块'
            }
        },
        template: '<ol class="bread-crumb">' +
        '<li><a href="index.html">{{first}}</a></li>' +
        '<li>{{second}}</li>' +
        '<li>{{third}}</li>' +
        '</ol>'
    });
    var app = new Vue({
            el:'#app',
            data:{
                index:'主页',
                second:'主模块',
                third:'小模块'
            }
        })
</script>

五、组件举例

最后做一个星级评价的例子:

<div id="app">
    <div class="evaStar">
        <ul>
            <li v-for="(cls,index) in classes" class="star-item" :class="cls" @click="handleClick(index)"></li>
        </ul>
    </div>
</div>
 .evaStar {
            padding-top: 2px;
        }

        .star-item {
            display: inline-block;
            background-repeat: no-repeat;
            width: 10px;
            height: 10px;
            margin-left: 3px;
            background-size: 100%;
        }

        .star-item.on {
            background-image: url(../../../img/star.png);
        }

        .star-item.off {
            background-image: url(../../../img/empty.png);
        }

<script>
    ***
     * 1. 样式替换
     * **/
      var app = new Vue({
        el:'#app',
        data:{
            classes:[
                'on','on','on','off','off'
            ]
        },
          methods:{
            handleClick:function (index) {

                var stars = [];
                var count = index+1
                this.classes = stars;

              // console.log(index);
             for (var i=0;i<count;i++){
                 this.classes.push('on');
              }
            }
        }
    })
  </script>

下一部分我们会讲组件的通信,敬请期待!

发布了17 篇原创文章 · 获赞 15 · 访问量 866

猜你喜欢

转载自blog.csdn.net/abc701110/article/details/104993884