Vue组件应用
Vue的组件是可复用的 Vue 实例,且带有一个名字 。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用。因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
一 创建组件
Vue提供了三种不同的方式来定义组件,分别是:全局组件,私有组件,单文件组件。接下来就让我一一道来。
1,全局组件
注册全局组件非常简单,也是很常用的一种方式。
Vue.component('myCom',{
template:'<div><p>我是一个全局<span>组件</span></p></div>'
});
Vue.component()方法需要两个参数:
第一个,组件名称;
第二个,实例(初始化)对象,可以包含所有使用new方式创建Vue实例时提供的所有属性,除了el。
注意:组件的实例对象必须提供一个template属性,用作该组件的HTML代码模板,且在该模板中有且只能有一个根元素。全局组件的注册必须在创建Vue实例之前。
小技巧:由于在编写JS时,一般没有HTML代码提示,创建组件模板代码会很不方便,所有可以在HTML文件中使用<template>元素创建模板,然后在组件的template属性中使用id选择器引用该模板。
注意:<template>元素必须在new Vue实例接管的根元素外部。
<template id="tem">
<div>
<p>我是组件内的p</p>
<span>我是组件中的span</span>
</div>
</template>
<!-- 在HTML中 -->
Vue.component('myCom',{
template:'#tem'
});
//在组件中
2,私有组件
全局创建的组件在所有Vue实例中均可以使用,有时候这并不符合我们的需求。你可以通过以下方式定义Vue实例的私有组件,这些组件只能在该Vue实例根元素内部使用。
var vm = new Vue({
el:'#app',
components:{
mycom:{
template:'#tem'
}
}
});
通过Vue实例的components属性可以定义私有组件,该属性绑定一个对象,对象的属性名是组件名,属性值是组件实例对象。
3,单文件组件
Vue的单文件组件是一个以.vue为后缀名的文件。由于HTML和JavaScrip不能识别.vue文件,所以不能直接使用这种方式的组件,必须配合webpack或vue-cli工具才能正确解析.vue文件。这里的重点是Vue单文件组件,所以有兴趣的同学请移步webpack中文网。
<tempalte>
//HTML模板
</template>
<script>
//JS代码
</script>
<style>
//CSS代码
</style>
.vue文件的名称就是组件的名称,其结构非常简单、清晰:
<template>标签是组件的HTML模板;
<script>标签是逻辑代码;
<style>标签中是样式代码。
二 组件的使用
不管以哪种方式创建Vue组件,我们最终的目的是在HTML页面中展示出来。本节将详细介绍Vue组件使用方式。
1,组件标签
要把我们创建的Vue组件添加到页面中去,只需要把组件名当做标签来使用即可。
Vue.component('myCom',{
template:"#tem"
});
var vm = new Vue({
el:"#app"
});
//JS部分
<div id="app">
<my-com></my-com>
</div>
<!-- HTML部分 -->
小技巧:注册组件时,建议使用全小写形式命名,因为HTML标签要求使用小写字母。如果你一定要遵守小驼峰命名规则,那么你应该在使用组件时用“-”短横线把单词分隔开。
2,组件复用
Vue的组件可以重复使用。
<div id="app">
<my-com></my-com>
<my-com></my-com>
<my-com></my-com>
</div>
当然,全局组件可以在任何地方使用,而私有组件只能在实例接管元素内部使用。
组件不仅可以简单的重复使用,还可以嵌套。
var vm = new Vue({
el:'#app',
compontents:{
mycom1:{
template:'<div>组件一 <mycom2></mycom2></div>'
},
mycom2:{
template:'<div>组件二</div>'
}
}
});
3,另一种使用方式
var mycom = {
tempalte:'<div id="app2">hello</div>'
};
var vm = new Vue({
el:'#app',
render:function(createEl){
return createEl(mycom);
}
});
使用render方式渲染组件:给Vue实例添加render属性,该属性值是一个接收一个方法作为参数的函数。参数用于创建Vue组件,return该组件将替代Vue实例接管的#app元素。最终的表现是:页面上将不再出现#app的div,取而代之的是#app2的div。
这种方式一般配合单文件组件使用,如果要渲染多个组件,只需要创建多个Vue实例即可。
三 数据传递(通信)
1,props传递数据(父组件 --> 子组件)
通过在子组件绑定props属性,实现父组件向子组件传递数据。props属性值是一个数组,数组元素被定义用来接收父组件传递来的数据,然后通过v-bind指令指定数组元素接收哪些数据。子组件通过访问props数组元素就可以访问到父组件传递过来的数据了,就如同访问data里面的值。
<div id="app">
<mycom :fromFatherMsg="toSonMsg"></mycom>
</div>
<!-- HTML部分 -->
Vue.component({
template:"<div>{{fromFatherMsg}}</div>",
props:["fromFatherMsg"]
});
var vm = new Vue({
el:'#app',
data:{
toSonMsg:'这是给子组件的数据'
}
});
//JS部分
通过上面的例子,我们可以将这个过程简单的分为三步:
第一步,在子组件上添加一个数组属性props,在数组中定义用来接收数据的变量(以字符串形式存储);
第二步,使用子组件时通过v-bind指令,绑定预先定义的接收变量和父组件将要传递过来的值;
第三步,在子组件中,如同访问data中的数据一样,访问props数组元素接收到的数据。
2,$emit传递方法(父组件 --> 子组件)
父组件向子组件传递方法,是通过自定义事件来实现的。
监听(同时注册)自定义事件有两种方式:组件上使用v-on指令、实例的$on()方法。这里我们将使用第一种方式来做演示。
子组件通过实例的$emit()方法触发自定义事件,这里的事件名将成为$emit()方法的第一个参数。
<div id="app">
<mycom @fromFatherFun="toSonFun"></mycom>
</div>
<!-- HTML部分 -->
Vue.component({
template:"<div><button @click="myFun">点击执行来自父组件的方法</button></div>",
methods:{
myFun:function(){
this.$emit('fromFatherFun');
}
}
});
var vm = new Vue({
el:'#app',
methods:{
toSonFun(){
console.log( "这是给子组件的方法");
}
});
//JS部分
注意:和传递数据一样,子组件不能直接使用父组件的方法。子组件需要通过实例的$emit()方法间接执行来自父组件的方法。
这一过程也可以分为三步:
第一步,使用子组件时,通过v-on指令自定义一个事件;
第二步,绑定自定义事件和父组件需要传递的方法(指定回调函数);
第三步,通过子组件的$emit()方法(通过实参指定需要触发的自定义事件)触发父组件的方法执行;
3,子组件抛出值(子组件 --> 父组件)
子组件在通过$emit()触发自定义事件时,可以同时利用方法的第二个参数,向外抛出一个值。回调函数(上面父组件传递下来的方法)需要定义一个形参来接收这个子组件抛出的值。
//接上面的例子
Vue.component({
template:"<div><button @click="myFun">点击执行来自父组件的方法</button></div>",
data(){
return {name:'ren'};
},
methods:{
myFun:function(){
this.$emit('fromFatherFun',this.name);
}
}
});
var vm = new Vue({
el:'#app',
data:{
nameFromSon:null
}
methods:{
toSonFun(data){
this.nameFromSon = data;
},
});
子组件抛出一个值的原理和父组件给子组件传递方法原理是一样的,只不过是不同的用法而已。虽然有点绕,但有用哦。
4,获取子组件的引用
在使用子组件时,通过绑定ref属性,父组件可以通过Vue实例的$refs属性拿到子组件的引用,然后就可以直接访问子组件的属性或方法了。
<div id="app">
<mycom ref="sonCom"></mycom>
<button @click="printMsgFromSon">点击打印子组件的信息</button>
</div>
<!-- HTML部分 -->
Vue.component('mycom',{
data:function(){return {name:'ren'}}
});
var vm = new Vue({
el:'#app',
methods:{
printMsgFromSon:function(){
console.log(this.$refs.sonCom.name);
}
}
});
//JS部分
小技巧:ref属性不仅可以用在组件上,也可以用在其他标准HTML标签上,这样Vue实例就可以获取到原生的DOM对象了。
注意:即使子组件是Vue实例的私有组件,实例也不能直接使用组件的相关数据,还是需要通过$refs等属性来间接访问。
5,兄弟组件间传值
兄弟组件间实现通信也是采用自定义事件的形式。不过,这一般需要一个空的Vue实例作为中介,配合使用$on()和$emit()实现兄弟组件间的传值。
<div id="app">
<com1></com1>
<com2></com2>
</div>
<template id="com1">
<div>
<p>com1组件:{{name}}</p>
<button @click="send">将数据发送给com2</button>
</div>
</template>
<template id="com2">
<div>
<p>com2组件:{{name}}</p>
</div>
</template>
<!-- HTML部分 -->
var event = new Vue();
var vm = new Vue({
el:'#app',
components:{
com1:{
template:'#com1',
data(){
return{name:'ren'};
},
methods:{
send(){
event.$emit('sendMsg',this.name);
}
}
},
com2:{
template:'#com2',
data(){
return {name:null};
},
created(){//因为不知道什么时候会被触发,所以一般选择在生命周期钩子中监听
event.$on('sendMsg',name => {this.name = name;})
//这里需要使用箭头函数,使其内部的this指向com2
}
}
}
});
//JS部分
四 其他事项
1,单独的data
经过上面的学习,你可能已经发现了一个问题:组件中的data属性是一个函数返回的对象。
Vue.component("mycom",{
template:"",
data(){
return { //some code };
}
});
//这是ES6的写法,等同于data:function(){return {some code};}
由于data属性绑定的是一个对象,而对象是一个引用类型,为了保证为每个组件维护一份独立的数据,组件的data属性必须是一个函数。
2,插槽<slot>
当你读到这里时,你可能会有一个疑问:既然我们可以用标签形式使用Vue组件,那么是否可以在开始标签和结束标签之间填些内容呢?如果可以的话,该如何做呢?Vue的答案是肯定的。
首先请看下面的例子:
<div id="app">
<com>我是插槽内容</com>
</div>
<!-- HTML部分 -->
Vue.compenent('com',{
template:'<div><p>我是组件</p><slot>我是默认值<slot></div>'
});
var vm = new Vue({
el:'#app'
});
//JS部分
"我是插槽内容"将替换com组件中<slot>元素。
注意:如果在使用子组件时没有提供插槽值,那么<slot>元素中的默认值将会生效,前提是你已经定义了这些值。
上面的例子中,组件最终渲染的HTML结构如下:
<div>
<p>我是组件</p>
我是插槽内容
</div>
注意:插槽的内容不仅可以是文本内容,还可以是HTML代码,甚至另一个组件。
如果你需要在一个组件中定义多个插槽,那么你应该需要用到<slot>元素的name属性,来指定每个插槽应该拥有怎么样的模板。
<div>
<com>
<template v-slot:"header">
<!-- 单独的HTML模板 -->
</template>
<div><p>我是默认的模板</p></div>
<template v-slot:"footer">
<!-- 单独的HTML模板 -->
</template>
</com>
</div>
<!-- HTML部分 -->
Vue.component('com',{
tempalte:'<div><slot name="header"></slot><slot></slot><slot name="footer"></slot></div>'
});
var vm = new Vue({
el:'#app'
});
具名的插槽需要在使用组件时,用<template>元素单独定义模板,并通过v-slot指令以参数的形式指定:“我是xxx插槽的模板”。
其他所有没有包裹在<template>元素内的模板,将自动归为匿名的<slot>元素下面。
3,特殊的嵌套元素
有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。要怎样才能在这些元素中正确的渲染组件呢?幸好,Vue提供了is特性:
<table>
<tr is="mycom"></tr>
</table>
注意:如果你使用字符串定义组件模板(例如:template: '...')、或者单文件组件(.vue)、或者<script>标签(<script type="text/x-template">),那么你完全可以忽略掉这个限制。
Vue组件应用的更多相关文章
- vue组件
分享出来让思路更成熟. 首先组件是 Vue.js 最强大的功能之一. 可以减少很多的工作量,提高工作效率. 编写一个可复用性的组件,虽然官网上也有.... 编写可复用性的vue组件 具备一下的几个要求 ...
- vue组件的配置属性
vue组件的声明语法: Vue.component('component-name',{ template:'<p>段落{{prop1}} {{prop2}}</p>', da ...
- vue组件,撸第一个
实现此例您可以学到: vue-cli的基本应用 父组件如何向子组件传递值 单文件组件如何引入scss v-on和v-for的基础应用 源码下载 一.搭建vue开发环境 更换镜像到cnpmnpm ins ...
- vue组件最佳实践
看了老外的一篇关于组件开发的建议(强烈建议阅读英文原版),感觉不错翻译一下加深理解. 这篇文章制定一个统一的规则来开发你的vue程序,以至于达到一下目的. 1.让开发者和开发团队更容易发现一些事情. ...
- JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
前言:转眼距离上篇 JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue ...
- vue组件大集合 component
vue组件分为全局组件.局部组件和父子组件,其中局部组件只能在el定义的范围内使用, 全局组件可以在随意地方使用,父子组件之间的传值问题等. Vue.extend 创建一个组件构造器 template ...
- 【Vue】详解Vue组件系统
Vue渲染的两大基础方式 new 一个Vue的实例 这个我们一般会使用在挂载根节点这一初始化操作上: new Vue({ el: '#app' }) 注册组件并使用—— 全局注册 通过Vue.comp ...
- 关于vue组件的一个小结
用vue进行开发到目前为止也有将近一年的时间了,在项目技术选型的时候隔壁组选 react的时候我们坚持使用vue作为前端的开发框架.虽然两者思想上的差异不大,但是vue的语法在代码的可读性以及后期的维 ...
- Vue组件基础用法
前面的话 组件(Component)是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.根据项目需求,抽象出一些组件,每个组件里包含了展现.功能和样式.每个页面,根据自己所需, ...
- Vue组件模板形式实现对象数组数据循环为树形结构
数据结构为数组中包含对象--树形结构,用Vue组件的写法实现以下的效果: 树形列表,缩进显示层级,第5级数据加底色,数据样式显色,点击展开折叠数据.本文为用Vue实现方式,另有一篇为用knockout ...
随机推荐
- JavaSE语法(中)
6.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 是值传递.Java语言的方法调用支持参数的值传递.当一个对象实例作为一个 ...
- 小白学 Python(20):迭代器基础
人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...
- Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗 ...
- JVM初体验
一.设计堆内存溢出异常:OutOfMemoryError: public class Main { public static void main(String[] args) { List<D ...
- linux下 驱动模块编译步骤
本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂.之所以要写这篇文章,主要是因为从书本上学的话,可能要花更长的时间才能学会整个过程,因为 ...
- 2、Linux基础练习题
题目 答案 1.答案 [root@centos7 ~]# date +'%F %T' 2019-07-23 10:21:35 2.答案 [root@centos7 ~]# date +%A -d '- ...
- 03-MyBatis拦截器机制
目录 MyBatis拦截器介绍 拦截器的使用 拦截器介绍及配置 源码分析 总结 本文转载自MyBatis拦截器原理探究 MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽 ...
- C#:转义字符 \n 和 \r 的区别
1.\n,换行符,作用是换行符之后的字符换到下一行: 例如:1234/n567 得出的结果是1234 567 2.而\r,回车符,作用是回车符之后的字符会回到当前行的最前面,把回车符之前的字符覆 ...
- hdu 5901 Count primes (meisell-Lehmer)
Count primes Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot ...
- nyoj 66-分数拆分 (Java,暴力)
66-分数拆分 内存限制:64MB 时间限制:3000ms 特判: No 通过数:7 提交数:9 难度:1 题目描述: 现在输入一个正整数k,找到所有的正整数x>=y,使得1/k=1/x+1/y ...