强大Vue.js组件浅析


Posted in Javascript onSeptember 12, 2016

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

如何注册组件?

需要使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。Vue.extend方法格式如下: 

var MyComponent = Vue.extend({
 // 选项...后面再介绍
})

如果想要其他地方使用这个创建的组件,还得个组件命个名: 

Vue.component('my-component', MyComponent) 

命名之后即可在HTML标签中使用这个组件名称,像使用DOM元素一样。下面来看看一个完整的组件注册和使用例子。

html代码: 

<div id="example">
 <my-component></my-component>
</div>

js代码: 

// 定义
var MyComponent = Vue.extend({
 template: '<div>A custom component!</div>'
})

// 注册
Vue.component('my-component', MyComponent)

// 创建根实例
new Vue({
 el: '#example'
})

输出结果:

<div id="example">
 <div>A custom component!</div>
</div

嵌套组件
组件本身也可以包含组件,下面的parent组件就包含了一个命名为child-component组件,但这个组件只能被parent组件使用: 

var child = Vue.extend({
 template: '<div>A custom component!</div>'
});
var parent = Vue.extend({

 template: '<div>Parent Component: <child-component></child-component></div>',
 components: {
 'child-component': child
 }
});
Vue.component("parent-component", parent);

上面的定义过程比较繁琐,也可以不用每次都调用Vue.component和Vue.extend方法: 

// 在一个步骤中扩展与注册
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})

// 局部注册也可以这么做
var Parent = Vue.extend({
 components: {
 'my-component': {
  template: '<div>A custom component!</div>'
 }
 }
})

动态组件

多个组件可以使用同一个挂载点,然后动态的在他们之间切换。使用保留的<component>元素,动态地绑定到它的is特性。下面的列子在同一个vue实例下挂了home、posts、archive三个组件,通过特性currentView动态切换组件显示。

html代码: 

<div id="dynamic">
 <button id="home">Home</button>
 <button id="posts">Posts</button>
 <button id="archive">Archive</button>
 <br>
 <component :is="currentView"></component>
</div>

js代码: 

var vue = new Vue({
 el:"#dynamic",
 data: {
 currentView: "home"
 },
 components: {
 home:{
  template: "Home"
 },
 posts: {
  template: "Posts"
 },
 archive: {
  template: "Archive"
 }
 }
});
document.getElementById("home").onclick = function(){
vue.currentView = "home";
};
document.getElementById("posts").onclick = function(){
vue.currentView = "posts";
};
document.getElementById("archive").onclick = function(){
vue.currentView = "archive";
};

组件和v-for 
<my-component v-for="item in items"></my-component> 

不能传递数据给组件,因为组件的作用域是独立的。为了传递数据给组件,应当使用props: 

<my-component
v-for="item in items"
:item="item"
:index="$index">
</my-component>

不自动把 item 注入组件的原因是这会导致组件跟当前 v-for 紧密耦合。显式声明数据来自哪里可以让组件复用在其它地方。

 深入响应式原理

在组件绑定数据时,如何绑定才能够有效,并且可动态修改、添加属性?看看下面的原理介绍。

如何追踪变化:把一个不同对象传给vue实例作为data的选项,vue.js将遍历它的属性,用Object.defineProperty将它转换为getter/setter。这是ES5特性,所有vue.js不支持IE8或更低版本。

模板中每个指令/数据绑定都有一个对应的watcher对象,在计算过程中它把属性记录为依赖。之后当依赖的setter被调用时 ,会触发watcher重新计算。流程如下所示: 

强大Vue.js组件浅析

变化检测问题:vue.js不能检测到对象属性的添加或删除,属性必须在data上才能让vue.js转换它为getter/setter模式,才能有响应。例如: 

var data = { a: 1 };
var vm = new Vue({
data: data
});
// `vm.a` 和 `data.a` 现在是响应的
vm.b = 2
// `vm.b` 不是响应的
data.b = 2
// `data.b` 不是响应的

不过,也有办法在实例创建后添加属性并且让它是相应的。可以使用set(key,value)实例方法: 

vm. set('b', 2)
// `vm.b` 和 `data.b` 现在是响应的 

对于普通对象可以使用全局方法:Vue.set(object, key, value):
Vue.set(data, 'c', 3)
// `vm.c` 和 `data.c` 现在是响应的 

初始化数据:尽管Vue.js提供动态的添加相应属性,还是推荐在data对象上声明所有的相应属性。

不这么做: 

var vm = new Vue({
 template: '<div>{{msg}}</div>'
})
// 然后添加 `msg`
vm.$set('msg', 'Hello!')

应该这么做: 

var vm = new Vue({
 data: {
 // 以一个空值声明 `msg`
 msg: ''
 },
 template: '<div>{{msg}}</div>'
})
// 然后设置 `msg`
vm.msg = 'Hello!'
 

组件完整案例
下面介绍的例子实现了模态窗口功能,代码也比较简单。

html代码:

<!-- 实现script定义一个模板 -->
<script type="x/template" id="modal-template">
 <!--模板是否显示通过v-show="show"来设置, transition设置动画效果-->
 <div class="modal-mask" v-show="show" transition="modal">
 <div class="modal-wrapper">
  <div class="modal-container">
  <div class="modal-header">
   <!--slot 相当于header占位符-->
   <slot name="header">
   default header
   </slot>
  </div>
  <div class="modal-body">
   <!--slot 相当于body占位符-->
   <slot name="body">
   default body
   </slot>
  </div>
  <div class="modal-footer">
   <!--slot 相当于footer占位符-->
   <slot name="footer">
   default footer
   </slot>
   <button class="modal-default-button" @click="show = false">OK</button>
  </div>
  </div>
 </div>
 </div>
</script>
<div id="app">
 <!--点击按钮时设置vue实例特性showModal的值为true-->
 <button id="show-modal" @click="showModal = true">show modal</button>
 <!--modal是自定义的一个插件,插件的特性show绑定vue实例的showModal特性-->
 <modal :show.sync="showModal">
 <!--替换modal插件中slot那么为header的内容-->
 <h3 slot="header">Custom Header</h3>
 </modal>
</div>

 js代码: 

//定义一个插件,名称为modal
Vue.component("modal", {
 //插件的模板绑定id为modal-template的DOM元素内容
 template: "#modal-template",
 props: {
 //特性,类型为布尔
 show:{
  type: Boolean,
  required: true,
  twoWay: true
 }
 }
});
//实例化vue,作用域在id为app元素下,
new Vue({
 el: "#app",
 data: {
 //特性,默认值为false
 showModal: false
 }
});

css代码: 

.modal-mask {
 position: fixed;
 z-index: 9998;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 background-color: rgba(0, 0, 0, .5);
 display: table;
 transition: opacity .3s ease;
}

.modal-wrapper {
 display: table-cell;
 vertical-align: middle;
}

.modal-container {
 width: 300px;
 margin: 0px auto;
 padding: 20px 30px;
 background-color: #fff;
 border-radius: 2px;
 box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
 transition: all .3s ease;
 font-family: Helvetica, Arial, sans-serif;
}

.modal-header h3 {
 margin-top: 0;
 color: #42b983;
}

.modal-body {
 margin: 20px 0;
}

.modal-default-button {
 float: right;
}

/*
* the following styles are auto-applied to elements with
* v-transition="modal" when their visiblity is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/

.modal-enter, .modal-leave {
 opacity: 0;
}

.modal-enter .modal-container,
.modal-leave .modal-container {
 -webkit-transform: scale(1.1);
 transform: scale(1.1);
}

本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

由于自己在项目中还没怎么深入使用组件的功能,所以自己对组件的理解也不深入,介绍的比较肤浅,谢谢大家的阅读。

Javascript 相关文章推荐
JavaScript 模拟用户单击事件
Dec 31 Javascript
JavaScript 类型的包装对象(Typed Wrappers)
Oct 27 Javascript
JS遍历Json字符串中键值对先转成JSON对象再遍历
Aug 15 Javascript
jQuery插件jRumble实现网页元素抖动
Jun 05 Javascript
Js动态设置rem来实现移动端字体的自适应代码
Oct 14 Javascript
详解JavaScript RegExp对象
Feb 04 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
May 10 Javascript
VueJs组件prop验证简单介绍
Sep 12 Javascript
JavaScript函数节流和函数去抖知识点学习
Jul 31 Javascript
laypage+SpringMVC实现后端分页
Jul 27 Javascript
如何使用jQuery操作Cookies方法解析
Sep 08 jQuery
微信小程序自定义胶囊样式
Dec 27 Javascript
超详细的JS弹出窗口代码大全
Apr 18 #Javascript
使用JS实现图片展示瀑布流效果的实例代码
Sep 12 #Javascript
关于javascript的一些知识以及循环详解
Sep 12 #Javascript
基于AngularJS实现iOS8自带的计算器
Sep 12 #Javascript
Javascript6中字符串的四个新用法分享
Sep 11 #Javascript
JavaScript制作简单分页插件
Sep 11 #Javascript
关于vue.js弹窗组件的知识点总结
Sep 11 #Javascript
You might like
php变量作用域的深入解析
2013/06/03 PHP
php查询mysql数据库并将结果保存到数组的方法
2015/03/18 PHP
php框架CodeIgniter使用redis的方法分析
2018/04/13 PHP
jQuery中文入门指南,翻译加实例,jQuery的起点教程
2007/01/13 Javascript
超级给力的JavaScript的React框架入门教程
2015/07/02 Javascript
js实现的动画导航菜单效果代码
2015/09/10 Javascript
ECMA5数组的新增方法有哪些及forEach()模仿实现
2015/11/03 Javascript
利用jquery制作滚动到指定位置触发动画
2016/03/26 Javascript
jQuery Mobile 和 Kendo UI 的比较
2016/05/05 Javascript
浅析angularJS中的ui-router和ng-grid模块
2016/05/20 Javascript
JavaScript实现使用Canvas绘制图形的基本教程
2016/10/27 Javascript
easyUI实现(alert)提示框自动关闭的实例代码
2016/11/07 Javascript
JavaScript实现点击按钮复制指定区域文本(推荐)
2016/11/25 Javascript
详解vue-router 2.0 常用基础知识点之router-link
2017/05/10 Javascript
利用Angular.js编写公共提示模块的方法教程
2017/05/28 Javascript
JavaScript 中定义函数用 var foo = function () {} 和 function foo()区别介绍
2018/03/01 Javascript
JS实现电商商品展示放大镜特效
2020/01/07 Javascript
[00:49]完美世界DOTA2联赛10月28日开团时刻:随便打
2020/10/29 DOTA
简明 Python 基础学习教程
2007/02/08 Python
Python中的类与对象之描述符详解
2015/03/27 Python
解决python3 urllib中urlopen报错的问题
2017/03/25 Python
Python实现返回数组中第i小元素的方法示例
2017/12/04 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
把vgg-face.mat权重迁移到pytorch模型示例
2019/12/27 Python
Django 解决distinct无法去除重复数据的问题
2020/05/20 Python
分享一个H5原生form表单的checkbox特效代码
2018/02/26 HTML / CSS
HTML5安全介绍之内容安全策略(CSP)简介
2012/07/10 HTML / CSS
Wiggle中国:英国骑行、跑步、游泳 & 铁三运动装备专卖网店
2016/08/02 全球购物
伊芙丽官方旗舰店:中国淑女一线品牌
2017/12/01 全球购物
总裁办公室主任职责
2014/01/02 职场文书
《满井游记》教学反思
2014/02/26 职场文书
安全生产工作汇报
2014/10/28 职场文书
给老婆的保证书怎么写
2015/05/08 职场文书
2015年财务部年度工作总结
2015/05/19 职场文书
退休教师欢送会致辞
2015/07/31 职场文书
python实现批量移动文件
2021/04/05 Python