JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
阅读目录
正文
前言:转眼距离上篇 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><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)"> 1.创建组件构造器</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> myComponent </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue.extend({ template: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"><div id="bComponent">我是自定义组件的内容</div></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }); </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">2.注册组件到vue里面</span>
Vue.component('b-component', myComponent)
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
得到效果:
整个过程不难理解,主要分为三个大的步骤:
- 定义一个组件构造器,声明组件要渲染的 html 内容
- 将组件构造器注册到 Vue 的组件系统里面,使其成为 Vue 的一个组件,给组件取一个名称,比如 b-component
- 在 Vue 的实例里面使用组件。因为上面两步定义了 Vue 的组件,既然是 Vue 的组件,那么要使用组件,首先得有一个 Vue 的实例,组件必须要在 Vue 的实例里面使用。
在网上找到一张图可以清晰地解释组件的整个渲染过程。
其实有时为了简便,我们常将 1、2 步合并,代码如下:
<div style="text-align:center;margin-top:200px;" id="app"> <!-- 2. 在 Vue 实例里面使用组件--> <b-component></b-component> </div><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">1.创建组件构造器,注册组件到vue里面</span>
Vue.component('b-component', {
template: '<div id="bComponent"> 我是自定义组件的内容 </div>'
})</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
得到的结果和上述相同。
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><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">b-component</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">b-component</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">b-component2</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">b-component2</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">定义组件</span>
Vue.component('b-component', {
template: '<div id="bComponent"> 我是全局组件,任何 Vue 实例都可使用 </div>'
})</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, components: { </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">b-component2</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">: { template: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"><div id="bComponent">我是局部组件,只能在app这个div里面使用</div></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> } } }); </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app2</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</body>
得到结果:
(2)组件的传值
组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。这段话怎么理解呢?我们先来看几个例子。
- 静态 Prop
我们先来看看下面的一段简单的代码
<body> <div style="text-align:center;margin-top:50px;" id="app"> <b-component componentmessage="你好"></b-component> </div><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue.component(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">b-component</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, { template: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"><div>{{componentmessage}}</div></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, props: [</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">componentmessage</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">], }) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</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'], })</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, data: { name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Jim</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">28</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> } }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</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><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue.component(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">b-component</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, { template: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#slottest</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, }) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, data: { name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Jim</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">28</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> } }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</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><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/jquery-1.9.1.min.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/bootstrap/js/bootstrap.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/bootstrap-table/bootstrap-table.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue/dist/vue.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="Content/vue-component/vue.bootstrapTable.js"</span><span style="color: rgba(0, 0, 255, 1)">></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> testData </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> [ { Name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Jim</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">30</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Remark: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">鸡母格林</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }, { Name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Kate</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">28</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Remark: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">凯特</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }, { Name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Lucy</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">20</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Remark: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">露西</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }, { Name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Uncle Wang</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Age: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">45</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, Remark: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">严厉的王老师</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> } ]; </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Vue({ el: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">#app</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, data: { tableParam: { data: testData, columns: [ { field: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Name</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, title:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">姓名</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }, { field: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Age</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, title: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">年龄</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }, { field: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">Remark</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, title: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">备注</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> }] }, } }); </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">></span>
</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(</span>'bootstrap-select'<span style="color: rgba(0, 0, 0, 1)">, { template: </span>'#bootstrapSelect'<span style="color: rgba(0, 0, 0, 1)">, props: [</span>'myDatasource', 'myMultiple', 'mySearch'<span style="color: rgba(0, 0, 0, 1)">], </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">组件渲染之前</span> created: <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () { }, </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">组件渲染之后</span> mounted: <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {</span><span style="color: rgba(0, 0, 0, 1)"> } });
})(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/
欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利