欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue组件应用

程序员文章站 2022-03-21 17:25:19
Vue的组件是可复用的 Vue 实例,且带有一个名字 。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用。因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周... ......

  vue的组件是可复用的 vue 实例,且带有一个名字 。我们可以在一个通过 new vue 创建的 vue 根实例中,把这个组件作为自定义元素来使用。因为组件是可复用的 vue 实例,所以它们与 new vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 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单文件组件,所以有兴趣的同学请移步。

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传递方法(父组件 --> 子组件)

  父组件向子组件传递方法,是通过自定义事件来实现的。

  监听(同时注册)自定义事件有两种方式:组件上使用v-bind、实例的$on()。这里我们将使用第一种方式来做演示。

  子组件通过实例的$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()触发自定义事件时,可以同时利用方法的第二个参数,向外抛出一个值。回调函数(上面父组件传递下来的方法)需要定义一个形参来接收这个子组件抛出的值。

 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等属性来间接访问。

 

  5,兄弟组件间传值

   兄弟组件间实现通信也是采用自定义事件的形式。不过,这一般需要一个空的vue实例作为中介,配合使用$on()和$emit()实现兄弟组件间的传值。

 1 <div id="app">
 2     <com1></com1>
 3     <com2></com2>
 4 </div>
 5 <template id="com1">
 6   <div>
 7     <p>com1组件:{{name}}</p>
 8     <button @click="send">将数据发送给com2</button>
 9   </div>
10 </template>
11 <template id="com2">
12   <div>
13     <p>com2组件:{{name}}</p>
14   </div>
15 </template>
16 <!-- html部分 -->

 

 1 var event = new vue();
 2 var vm = new vue({
 3     el:'#app',
 4     components:{
 5         com1:{
 6             template:'#com1',
 7             data(){
 8                 return{name:'ren'};
 9             },
10             methods:{
11                 send(){
12                     event.$emit('sendmsg',this.name);
13                 }
14             }
15         },
16         com2:{
17             template:'#com2',
18             data(){
19                 return {name:null};
20             },
21             created(){//因为不知道什么时候会被触发,所以一般选择在生命周期钩子中监听
22                 event.$on('sendmsg',name => {this.name = name;})
23                 //这里需要使用箭头函数,使其内部的this指向com2
24             }
25         }
26     }
27 });
28 //js部分

 

 

四  其他事项

 

  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">),那么你完全可以忽略掉这个限制。