前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少。经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博主都没什么太大的关系,博主还是老老实实研究自己的技术吧。技术之路还很长,且行且研究吧。

本文原创地址:http://www.cnblogs.com/landeanfen/p/6518679.html

一、为什么组件很重要

前两天,看到一篇关于 汇总vue开源项目 的文章,资源非常丰富,不得不感叹开源社区的强大。随便点进去看了几个UI组件,基本都不是原生的html用法,如果你不懂Vue的组件相关概念,看到一些“稀奇古怪”的标签写法,可能会使用,但肯定无法理解为什么可以这么写。比如我们随便找了一个名叫IView的来看看:

<i-input type="text" :value.sync="formInline.user" placeholder="Username">
<Icon type="ios-person-outline" slot="prepend"></Icon>
</i-input>

这样一段代码就能得到如下效果:

博主好奇心重,打算一探究竟,今天就和大家一起来看一看这些“古怪”写法的出处。希望通过本文,让你有一种“哦,原来是这样,不过如此嘛!”的感觉!

二、Vue里面的组件基础知识

1、组件的概念

官方定义:组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

博主理解:Vue里面的组件可以理解为通过对普通html标签的封装,得到一套独立而且可以通用的html标签,我们在页面里面使用这些标签传入相应的参数即可调用封装好的组件。通过下面这张图相信可以一目了然。

由普通的html标签form、input、button、label组成了一个新的元素集合,我们命名为i-form,这个i-form就是vue里面组件的概念。我们在页面里面使用<i-form></i-form>时,通过vue的组件渲染机制,在浏览器里面最终就可以显示成为普通的html标签form、input、button、label。

2、组件原理

通过上图我们知道,vue里面的组件实际上就是一些普通html元素的集合。那么,它是如何将这些自定义标签转换为普通html标签的呢?在介绍组件原理之前,还是先来看一个最简单的组件实例。

  <div style="text-align:center;margin-top:200px;" id="app">
<!-- 3. 在Vue实例里面使用组件-->
<b-component></b-component>
</div> <script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript">
// 1.创建组件构造器
var myComponent = Vue.extend({
template: '<div id="bComponent">我是自定义组件的内容</div>'
}); //2.注册组件到vue里面
Vue.component('b-component', myComponent) new Vue({
el: '#app',
}); </script>

得到效果:

整个过程不难理解,主要分为三个大的步骤:

  1. 定义一个组件构造器,声明组件要渲染的html内容
  2. 将组件构造器注册到Vue的组件系统里面,使其成为Vue的一个组件,给组件取一个名称,比如b-component
  3. 在Vue的实例里面使用组件。因为上面两步定义了Vue的组件,既然是Vue的组件,那么要使用组件,首先得有一个Vue的实例,组件必须要在Vue的实例里面使用。

在网上找到一张图可以清晰地解释组件的整个渲染过程。

其实有时为了简便,我们常将1、2步合并,代码如下:

  <div style="text-align:center;margin-top:200px;" id="app">
<!-- 2. 在Vue实例里面使用组件-->
<b-component></b-component>
</div> <script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript">
//1.创建组件构造器,注册组件到vue里面
Vue.component('b-component', {
template: '<div id="bComponent">我是自定义组件的内容</div>'
}) new Vue({
el: '#app',
}); </script>

得到的结果和上述相同。

3、组件使用

上述解释了下组件的定义和原理,关于组件的简单实用,我们主要介绍以下几个方面。

(1)组件的作用域

这个应该不难理解,组件分为全局组件和局部组件,也就是说,你可以在页面上面定义一个全局组件,页面上面的任何Vue实例都可使用;而对于局部组件,是和具体的Vue实例相关的,只能在当前Vue实例里面使用组件。还有一点需要说明:组件必须在Vue的实例里面使用,在Vue实例之外使用组件无效。通过下面一个例子即可清晰说明它们的区别。

<body>
<div style="text-align:center;margin-top:50px;" id="app">
<b-component></b-component>
<b-component2></b-component2>
</div>
<div style="text-align:center;margin-top:50px;" id="app2">
<b-component></b-component>
<b-component2></b-component2>
</div> <b-component></b-component>
<b-component2></b-component2> <script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript"> //定义组件
Vue.component('b-component', {
template: '<div id="bComponent">我是全局组件,任何Vue实例都可使用</div>'
}) new Vue({
el: '#app',
components: {
'b-component2': {
template: '<div id="bComponent">我是局部组件,只能在app这个div里面使用</div>'
}
}
});
new Vue({
el: '#app2',
}); </script>
</body>

得到结果:

(2)组件的传值

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。这段话怎么理解呢?我们先来看几个例子。

  • 静态Prop

我们先来看看下面的一段简单的代码

<body>
<div style="text-align:center;margin-top:50px;" id="app">
<b-component componentmessage="你好"></b-component>
</div> <script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component('b-component', {
template: '<div>{{componentmessage}}</div>',
props: ['componentmessage'],
}) new Vue({
el: '#app'
});
</script>
</body>

通过在组件里面使用props属性,将外部的值传入组件模板。最终渲染到页面上面就得到“<div>你好</div>”这么一段html

  • 动态Prop

在多数情况下,我们在使用Vue实例的时候,一般通过data属性传入模型,比如

    new Vue({
el: '#app',
data: {
name: 'Jim',
Age: '28'
}
});

这个时候,我们的name和age如何传到组件实例里面呢?

<body>
<div style="text-align:center;margin-top:50px;" id="app">
<b-component v-bind:my-name="name" v-bind:my-age="Age"></b-component>
</div>
<script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component('b-component', {
template: '<div>姓名:{{myName}},年龄:{{myAge}}</div>',
props: ['myName', 'myAge'],
}) new Vue({
el: '#app',
data: {
name: 'Jim',
Age: '28'
}
});
</script>
</body>

得到结果

需要说明几点:

  • 在使用标签<b-component>的时候,通过v-bind命令,将Vue实例里面的name、Age属性以别名my-name、my-age的形式传入组件实例。
  • 为什么my-name、my-age传到组件里面就变成了['myName', 'myAge']呢?这是因为在子组件中定义prop时,使用了camelCase命名法。由于HTML特性不区分大小写,camelCase的prop用于特性时,需要转为 kebab-case(短横线隔开)。
  • 很多情况下,v-bind可以简写为冒号(:),所以上述代码也可以这么写: <b-component :my-name="name" :my-age="Age"></b-component> 。效果也是一样。
  • 这里很恶心的还有一点,在Props里面定义的必须要使用所谓“驼峰式”的方式来定义变量,否则会因为一个变量名大小写搞死你。比如props:["myName"]这样可以正确,但是如果props:["myname"]这样的话就错误,使用myname取值会是undefined。博主第一次玩这个玩意找了好半天,新手一定注意,大坑,大坑,大坑!慎入!

在封装组件里面,props属性使用非常多,更多props用法可参见文档https://vuefe.cn/v2/guide/components.html#Prop

(3)组件的插槽

在使用组件的时候,我们经常需要在组件实例向组件模板传入html元素,这个时候我们就需要在组件的模板标签里面留一些占位符(俗称“坑”),然后在具体的组件实例里面传入标签来填“坑”,在Vue里面这些“坑”也叫插槽,使用<slot>来解决。对于开发人员来说,这个其实不陌生,从原来的母版页到现在的layout页面,基本都是使用的这种原理。

<body>
<div style="text-align:center;margin-top:50px;" id="app">
<b-component>
<h1 slot="header">这里可能是一个页面标题</h1>
<h2 slot="content">姓名:{{name}},年龄:{{Age}}</h2>
<h1 slot="footer">尾部</h1>
</b-component>
</div>
<template id="slottest">
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="content"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template> <script src="Content/vue/dist/vue.js"></script>
<script type="text/javascript"> Vue.component('b-component', {
template: '#slottest',
}) new Vue({
el: '#app',
data: {
name: 'Jim',
Age: '28'
}
});
</script>
</body>

得到结果

上述代码应该不难理解,就是一个“挖坑”和“填坑”的过程。顺便要提一笔的是,Vue的组件支持使用<templete>的模式来定义标签模板,使用更加灵活和方便。

三、封装自己的Component

以上讲了这么多,都是关于Vue里面Component组件的一部分主要知识点,其他还有很多都没有展开说,因为这方面的文档也是相当丰富,园子里面keepfool的博文关于Vue组件的部分就介绍得非常详细,再者,Vue中文文档也是有很详细的用法说明。接下来,博主打算通过几个实例来说明使用组件给我们前端开发带来的好处。

1、使用Component封装bootstrapTable

对于项目里面的表格展示,可以基于Vue可以自己开发一套,但是说实话,这个工程量还是蛮大的,并且如果要做好,要兼容很多表格的功能,从零开始去重复造轮子实在是有点太耗时。博主项目里面大部分的表格用的bootstrapTable组件,于是博主一直在想能不能封装一套基于Vue的bootstrapTable的用法。网上也找不到类似的封装示例,大部分使用vue的框架都会自己去实现一套自己的表格样式。于是打算自己动手试试,正好也可以熟悉下component的用法。

首先新建一个js文件命名为vue.bootstrapTable.js。博主直接将代码贴出来,如果有不完善的地方,希望大家斧正。

(function ($) {
//表格初始化的默认参数
var defaults = {
method: 'get',
toolbar: '#toolbar',
striped: true,
cache: false,
pagination: true,
};
//注册bootstrapTable组件
Vue.component('bootstrap-table', {
template: '<table></table>',
props: {
'tableParam': { type: Object }
},
//组件渲染之前
created: function () {
//debugger; },
//组件渲染之后
mounted: function () {
debugger;
var params = $.extend({}, defaults, this.tableParam || {});
this.bootstraptable = $(this.$el).bootstrapTable(params);
}
}); })(jQuery);

然后再界面上面

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<link href="Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
<link href="Content/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<bootstrap-table :table-param="tableParam"></bootstrap-table>
</div> <script src="Content/jquery-1.9.1.min.js"></script>
<script src="Content/bootstrap/js/bootstrap.js"></script>
<script src="Content/bootstrap-table/bootstrap-table.js"></script>
<script src="Content/vue/dist/vue.js"></script>
<script src="Content/vue-component/vue.bootstrapTable.js"></script>
<script type="text/javascript">
var testData = [
{ Name: 'Jim', Age: 30, Remark: '鸡母格林' },
{ Name: 'Kate', Age: 28, Remark: '凯特' },
{ Name: 'Lucy', Age: 20, Remark: '露西' },
{ Name: 'Uncle Wang', Age: 45, Remark: '严厉的王老师' }
]; new Vue({
el: '#app',
data: {
tableParam: {
data: testData,
columns: [
{
field: 'Name',
title:'姓名'
}, {
field: 'Age',
title: '年龄'
}, {
field: 'Remark',
title: '备注'
}]
},
}
}); </script>
</body>

最后测试结果:

纵观这数十行代码,基本原来其实很简单,通过组件的props功能将<bootstrap-table>实例中的初始化参数传到组件模板里面,然后再组件加载完成之后初始化bootstrapTable,最后将bootstrapTable的实例给到组件,这样在就可以通过Vue的实例通过子组件调用到当前初始化的bootstrapTable对象。

2、封装select

关于select的封装,还是打算基于第三方组件来做。同样的,我们新建一个js文件,命名为vue.bootstrapSelect.js,其代码如下:

(function ($) {
$("body").append('<template id="bootstrapSelect">' +
'<select class="selectpicker" v-if="myMultiple" v-bind:data-live-search="mySearch" multiple>' +
'<option v-for="item in myDatasource" v-bind:value="item.value">{{item.text}}</option>'
+'</select>' +
'<select class="selectpicker" v-else v-bind:data-live-search="mySearch">' +
'<option v-for="item in myDatasource" v-bind:value="item.value">{{item.text}}</option>'
+'</select>' +
'</template>'); Vue.component('bootstrap-select', {
template: '#bootstrapSelect',
props: ['myDatasource', 'myMultiple', 'mySearch'],
//组件渲染之前
created: function () {
},
//组件渲染之后
mounted: function () {
}
}); })(jQuery);

页面使用

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<link href="Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
<link href="Content/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
<link href="Content/bootstrap-select/css/bootstrap-select.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<bootstrap-select :my-datasource="selectOptions.data"
:my-multiple="selectOptions.multiple"
:my-search="selectOptions.search">
</bootstrap-select>
</div>
<script src="Content/jquery-1.9.1.min.js"></script>
<script src="Content/bootstrap/js/bootstrap.js"></script>
<script src="Content/bootstrap-table/bootstrap-table.js"></script>
<script src="Content/bootstrap-select/js/bootstrap-select.js"></script>
<script src="Content/bootstrap-select/js/i18n/defaults-zh_CN.js"></script>
<script src="Content/vue/dist/vue.js"></script>
<script src="Content/vue-component/vue.bootstrapSelect.js"></script>
<script type="text/javascript">
$(function () {
var vm = new Vue({
el: '#app',
data: {
selectOptions:{
multiple: false,//多选
search: true,//搜索
data: [
{ text: "北京市", value: 1 },
{ text: "上海市", value: 2 },
{ text: "重庆市", value: 3 },
]
}
},
});
});
</script>
</body>
</html>

得到效果:

然后可配置多选,将初始化参数multiple设置为true即可。

为什么模板里面会有两个select标签?原因就在于那个multiple,因为只要标签里面出现了multiple,select就自动多选,把multiple的值设置为任何属性都不好使,这不做了一个if判断,如果哪位有更好的方法,欢迎指出,不胜感激!

3、查看其他Vue框架源码

现在再来看文章的开头那段html

<i-input type="text" :value.sync="formInline.user" placeholder="Username">
<Icon type="ios-person-outline" slot="prepend"></Icon>
</i-input>

结合Vue组件的文档,其实上述就是一个对input标签做的封装。

当然,以上只是component的基础,组件的封装还得结合很多其他的东西,要读懂那些框架的源码还需要学习一些其他知识,但至少通过本文希望能够让你了解这些东西的由来。

四、总结

本篇到此结束,通过本文,相信你对Vue的component有了一个大概的了解。接下来如果有时间将结合webpack介绍Vue的一些高级用法。

最近打算做点自己的东西出来,将博客里面的一些好的技术(包括vue)融合进去。有项目合作的小伙伴赶快联系博主吧!

本文原创出处:http://www.cnblogs.com/landeanfen/

欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利

JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)的更多相关文章

  1. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

  2. C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有(二)

    前言:上篇 C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有 介绍了下组件的两个功能,说不上特色,但确实能解决我们项目中的一些实际问题,这两天继续研究了下这个组件,觉得有些功能用 ...

  3. C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有

    前言:最近项目里面有一些对Excel操作的需求,博主想都没想,NPOI呗,简单.开源.免费,大家都喜欢!确实,对于一些简单的Excel导入.导出.合并单元格等,它都没啥太大的问题,但是这次的需求有两点 ...

  4. C#组件系列———又一款日志组件:Elmah的学习和分享

    前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇.最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛.一如既往,园子里每年这个时候 ...

  5. C#组件系列——又一款日志组件:Elmah的学习和分享

    前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇.最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛.一如既往,园子里每年这个时候 ...

  6. JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

    前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己 ...

  7. JS组件系列——再推荐一款好用的bootstrap-select组件,亲测还不错

    前言:之前分享过两篇bootstrap下拉框的组件:JS组件系列——两种bootstrap multiselect组件大比拼  和 JS组件系列——Bootstrap Select2组件使用小结 ,收 ...

  8. 【转】JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

    前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己 ...

  9. [转]JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐

    本文转自:https://www.cnblogs.com/landeanfen/p/5461849.html#_label3 阅读目录 一.时间组件 1.效果展示 2.源码说明 3.代码示例 二.自增 ...

随机推荐

  1. 【翻译】使用Visual Studio在Azure上部署Asp.Net Core Web应用

    配置运行环境 Install the latest Azure SDK for Visual Studio. The SDK installs Visual Studio if you don't a ...

  2. 图像切换器(ImageSwitcer)的功能与用法

    ImageSwitcher继承了VewSwitcher,因此它具有与ViewSwitcher相同的特征,可以在切换View组件时使用动画效果.ImageSwitcher继承了ViewSwitcher并 ...

  3. CRS-2800 CRS-4000

    I was installing Clusterware using ASM on VMware shared disks.  When I created the independent persi ...

  4. Windows Server 2008 R2 允许远程桌面连接这台计算机是灰色解决办法

    发现在给"远程协助"打钩时,是灰色的没法钩上,也就没办法开启.这是因为Windows Server 2008 R2的安全性已经被微软设计的很高,默认刚安装上Windows Serv ...

  5. Mangos笔记

    $lt.$lte.$gt.$gte和$ne $in.$nin.$or $mod.$not $exists 条件句式内层文档的键,修改器是外层文档的键,一个键可以有多个 条件,但是一个键不能对应多个更新 ...

  6. 初识Dapper

    16年年底开发一个项目,拍卖的项目,对于我这个不入流的程序员来说,雪微是个挑战.程序猿这个行业就是学到老用到老吧.个人比较喜欢sql原生的写法,对EF 还是不怎么感冒,EF 虽然强大,但是用起来还不怎 ...

  7. 基于MAC OS 操作系统安装、配置mysql

    $ sudo mv mysql-5.1.45-osx10.6-x86_64 /usr/local/mysql$ cd /usr/local$ sudo chown -R mysql:mysql mys ...

  8. 《JAVASCRIPT高级程序设计》Ajax与Comet

    Ajax,是Asynchronous JavaScript + XML的简写,这一技术能向服务器请求额外的技术而无需卸载页面,会带给用户更好的体验.Ajax的核心是XMLHttpRequest对象.为 ...

  9. 微信jsSDK公众号开发时网页提示 invalid signature错误的解决方法

    微信公众号开发jsSDK,链接地址不能加?参数,可以通过#传递参数. 不然.页面wx.ready()时就会报错,用 wx.error(function (res) { alert("接口验证 ...

  10. Unity编程标准导引-2.2Unity中的基本概念

    2.2Unity中的基本概念 上述介绍提到了几个概念:游戏对象.场景.资源.相机,这个小节我们来深入了解,同时进行一些实践性操作.不过首先,我们需要大概了解一下Unity的工程文件夹. 2.2.1工程 ...