Vue组件应用
任风来去匆匆 人气:1 Vue的组件是可复用的 Vue 实例,且带有一个名字 。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用。因为组件是可复用的 Vue 实例,所以它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
一 创建组件
Vue提供了三种不同的方式来定义组件,分别是:全局组件,私有组件,单文件组件。接下来就让我一一道来。
1,全局组件
注册全局组件非常简单,也是很常用的一种方式。
1 Vue.component('myCom',{ 2 template:'<div><p>我是一个全局<span>组件</span></p></div>' 3 });
Vue.component()方法需要两个参数:
第一个,组件名称;
第二个,实例(初始化)对象,可以包含所有使用new方式创建Vue实例时提供的所有属性,除了el。
注意:组件的实例对象必须提供一个template属性,用作该组件的HTML代码模板,且在该模板中有且只能有一个根元素。全局组件的注册必须在创建Vue实例之前。
小技巧:由于在编写JS时,一般没有HTML代码提示,创建组件模板代码会很不方便,所有可以在HTML文件中使用<template>元素创建模板,然后在组件的template属性中使用id选择器引用该模板。
注意:<template>元素必须在new Vue实例接管的根元素外部。
1 <template id="tem"> 2 <div> 3 <p>我是组件内的p</p> 4 <span>我是组件中的span</span> 5 </div> 6 </template> 7 <!-- 在HTML中 -->
1 Vue.component('myCom',{ 2 template:'#tem' 3 });
4 //在组件中
2,私有组件
全局创建的组件在所有Vue实例中均可以使用,有时候这并不符合我们的需求。你可以通过以下方式定义Vue实例的私有组件,这些组件只能在该Vue实例根元素内部使用。
1 var vm = new Vue({ 2 el:'#app', 3 components:{ 4 mycom:{ 5 template:'#tem' 6 } 7 } 8 });
通过Vue实例的components属性可以定义私有组件,该属性绑定一个对象,对象的属性名是组件名,属性值是组件实例对象。
3,单文件组件
Vue的单文件组件是一个以.vue为后缀名的文件。由于HTML和JavaScrip不能识别.vue文件,所以不能直接使用这种方式的组件,必须配合webpack或vue-cli工具才能正确解析.vue文件。这里的重点是Vue单文件组件,所以有兴趣的同学请移步webpack中文网。
1 <tempalte> 2 //HTML模板 3 </template> 4 <script> 5 //JS代码 6 </script> 7 <style> 8 //CSS代码 9 </style>
.vue文件的名称就是组件的名称,其结构非常简单、清晰:
<template>标签是组件的HTML模板;
<script>标签是逻辑代码;
<style>标签中是样式代码。
二 组件的使用
不管以哪种方式创建Vue组件,我们最终的目的是在HTML页面中展示出来。本节将详细介绍Vue组件使用方式。
1,组件标签
要把我们创建的Vue组件添加到页面中去,只需要把组件名当做标签来使用即可。
1 Vue.component('myCom',{ 2 template:"#tem" 3 }); 4 var vm = new Vue({ 5 el:"#app" 6 }); 7 //JS部分
1 <div id="app"> 2 <my-com></my-com> 3 </div> 4 <!-- HTML部分 -->
小技巧:注册组件时,建议使用全小写形式命名,因为HTML标签要求使用小写字母。如果你一定要遵守小驼峰命名规则,那么你应该在使用组件时用“-”短横线把单词分隔开。
2,组件复用
Vue的组件可以重复使用。
1 <div id="app"> 2 <my-com></my-com> 3 <my-com></my-com> 4 <my-com></my-com> 5 </div>
当然,全局组件可以在任何地方使用,而私有组件只能在实例接管元素内部使用。
组件不仅可以简单的重复使用,还可以嵌套。
1 var vm = new Vue({ 2 el:'#app', 3 compontents:{ 4 mycom1:{ 5 template:'<div>组件一 <mycom2></mycom2></div>' 6 }, 7 mycom2:{ 8 template:'<div>组件二</div>' 9 } 10 } 11 });
3,另一种使用方式
1 var mycom = { 2 tempalte:'<div id="app2">hello</div>' 3 }; 4 var vm = new Vue({ 5 el:'#app', 6 render:function(createEl){ 7 return createEl(mycom); 8 } 9 });
使用render方式渲染组件:给Vue实例添加render属性,该属性值是一个接收一个方法作为参数的函数。参数用于创建Vue组件,return该组件将替代Vue实例接管的#app元素。最终的表现是:页面上将不再出现#app的div,取而代之的是#app2的div。
这种方式一般配合单文件组件使用,如果要渲染多个组件,只需要创建多个Vue实例即可。
三 数据传递(通信)
1,props传递数据(父组件 --> 子组件)
通过在子组件绑定props属性,实现父组件向子组件传递数据。props属性值是一个数组,数组元素被定义用来接收父组件传递来的数据,然后通过v-bind指令指定数组元素接收哪些数据。子组件通过访问props数组元素就可以访问到父组件传递过来的数据了,就如同访问data里面的值。
1 <div id="app"> 2 <mycom :fromFatherMsg="toSonMsg"></mycom> 3 </div> 4 <!-- HTML部分 -->
1 Vue.component({ 2 template:"<div>{{fromFatherMsg}}</div>", 3 props:["fromFatherMsg"] 4 }); 5 var vm = new Vue({ 6 el:'#app', 7 data:{ 8 toSonMsg:'这是给子组件的数据' 9 } 10 }); 11 //JS部分
通过上面的例子,我们可以将这个过程简单的分为三步:
第一步,在子组件上添加一个数组属性props,在数组中定义用来接收数据的变量(以字符串形式存储);
第二步,使用子组件时通过v-bind指令,绑定预先定义的接收变量和父组件将要传递过来的值;
第三步,在子组件中,如同访问data中的数据一样,访问props数组元素接收到的数据。
2,$emit传递方法(父组件 --> 子组件)
父组件向子组件传递方法,是通过自定义事件来实现的。子组件通过实例的$emit()方法调用,这里的事件名将成为$emit()方法的参数。
1 <div id="app"> 2 <mycom @fromFatherFun="toSonFun"></mycom> 3 </div> 4 <!-- HTML部分 -->
1 Vue.component({ 2 template:"<div><button @click="myFun">点击执行来自父组件的方法</button></div>", 3 methods:{ 4 myFun:function(){ 5 this.$emit('fromFatherFun'); 6 } 7 } 8 }); 9 var vm = new Vue({ 10 el:'#app', 11 methods:{ 12 toSonFun(){ 13 console.log( "这是给子组件的方法"); 14 }, 15 }); 16 //JS部分
注意:和传递数据一样,子组件不能直接使用父组件的方法。子组件需要通过实例的$emit()方法间接执行来自父组件的方法。
这一过程也可以分为三步:
第一步,使用子组件时,通过v-on指令自定义一个事件,事件名用来接收父组件传递来的方法;
第二步,绑定自定义事件和父组件需要传递的方法;
第三步,通过子组件的$emit()方法(通过实参指定需要触发的自定义事件)触发父组件的方法执行;
3,子组件抛出值(子组件 --> 父组件)
子组件在通过$emit()触发父组件的方法时,可以同时利用$emit()的第二个参数,来向父组件的方法(传递给子组件的那个方法)抛出一个值。父组件的方法需要定义一个形参来接收这个子组件抛来的值。
1 //接上面的例子 2 Vue.component({ 3 template:"<div><button @click="myFun">点击执行来自父组件的方法</button></div>", 4 data(){ 5 return {name:'ren'}; 6 }, 7 methods:{ 8 myFun:function(){ 9 this.$emit('fromFatherFun',this.name); 10 } 11 } 12 }); 13 var vm = new Vue({ 14 el:'#app', 15 data:{ 16 nameFromSon:null 17 } 18 methods:{ 19 toSonFun(data){ 20 this.nameFromSon = data; 21 }, 22 });
子组件抛出一个值的原理和父组件给子组件传递方法原理是一样的,只不过是不同的用法而已。虽然有点绕,但有用哦。
4,获取子组件的引用
在使用子组件时,通过绑定ref属性,父组件可以通过Vue实例的$refs属性拿到子组件的引用,然后就可以直接访问子组件的属性或方法了。
1 <div id="app"> 2 <mycom ref="sonCom"></mycom> 3 <button @click="printMsgFromSon">点击打印子组件的信息</button> 4 </div> 5 <!-- HTML部分 -->
1 Vue.component('mycom',{ 2 data:function(){return {name:'ren'}} 3 }); 4 5 var vm = new Vue({ 6 el:'#app', 7 methods:{ 8 printMsgFromSon:function(){ 9 console.log(this.$refs.sonCom.name); 10 } 11 } 12 }); 13 //JS部分
小技巧:ref属性不仅可以用在组件上,也可以用在其他标准HTML标签上,这样Vue实例就可以获取到原生的DOM对象了。
注意:即使子组件是Vue实例的私有组件,实例也不能直接使用组件的相关数据,还是需要通过$refs等属性来间接访问。
四 其他事项
1,单独的data
经过上面的学习,你可能已经发现了一个问题:组件中的data属性是一个函数返回的对象。
1 Vue.component("mycom",{ 2 template:"", 3 data(){ 4 return { //some code }; 5 } 6 }); 7 //这是ES6的写法,等同于data:function(){return {some code};}
由于data属性绑定的是一个对象,而对象是一个引用类型,为了保证为每个组件维护一份独立的数据,组件的data属性必须是一个函数。
2,插槽<slot>
当你读到这里时,你可能会有一个疑问:既然我们可以用标签形式使用Vue组件,那么是否可以在开始标签和结束标签之间填些内容呢?如果可以的话,该如何做呢?Vue的答案是肯定的。
首先请看下面的例子:
1 <div id="app"> 2 <com>我是插槽内容</com> 3 </div> 4 <!-- HTML部分 -->
1 Vue.compenent('com',{ 2 template:'<div><p>我是组件</p><slot>我是默认值<slot></div>' 3 }); 4 var vm = new Vue({ 5 el:'#app' 6 }); 7 //JS部分
"我是插槽内容"将替换com组件中<slot>元素。
注意:如果在使用子组件时没有提供插槽值,那么<slot>元素中的默认值将会生效,前提是你已经定义了这些值。
上面的例子中,组件最终渲染的HTML结构如下:
1 <div> 2 <p>我是组件</p> 3 我是插槽内容 4 </div>
注意:插槽的内容不仅可以是文本内容,还可以是HTML代码,甚至另一个组件。
如果你需要在一个组件中定义多个插槽,那么你应该需要用到<slot>元素的name属性,来指定每个插槽应该拥有怎么样的模板。
1 <div> 2 <com> 3 <template v-slot:"header"> 4 <!-- 单独的HTML模板 --> 5 </template> 6 <div><p>我是默认的模板</p></div> 7 <template v-slot:"footer"> 8 <!-- 单独的HTML模板 --> 9 </template> 10 </com> 11 </div> 12 <!-- HTML部分 -->
1 Vue.component('com',{ 2 tempalte:'<div><slot name="header"></slot><slot></slot><slot name="footer"></slot></div>' 3 }); 4 var vm = new Vue({ 5 el:'#app' 6 });
具名的插槽需要在使用组件时,用<template>元素单独定义模板,并通过v-slot指令以参数的形式指定:“我是xxx插槽的模板”。
其他所有没有包裹在<template>元素内的模板,将自动归为匿名的<slot>元素下面。
3,特殊的嵌套元素
有些 HTML 元素,诸如 <ul>
、<ol>
、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>
、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。要怎样才能在这些元素中正确的渲染组件呢?幸好,Vue提供了is特性:
1 <table> 2 <tr is="mycom"></tr> 3 </table>
注意:如果你使用字符串定义组件模板(例如:template: '...'
)、或者单文件组件(.vue)、或者<script>标签(<script type="text/x-template">),那么你完全可以忽略掉这个限制。
加载全部内容