zoukankan      html  css  js  c++  java
  • Vue组件应用

      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单文件组件,所以有兴趣的同学请移步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传递方法(父组件 --> 子组件)

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

      监听(同时注册)自定义事件有两种方式:组件上使用v-on指令、实例的$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">),那么你完全可以忽略掉这个限制。

  • 相关阅读:
    uva-712 S-Trees
    Liunx下文件权限详解
    uva-699 The Falling Leaves
    Oracle sql loader 使用案例
    设计模式学习--迭代器模式(Iterator Pattern)和组合模式(Composite Pattern)
    XML 简单介绍
    UVA 11107(Life Forms-后缀数组+二分)
    SRM 212 Div II Level One: YahtzeeScore
    HDU 5695 Gym Class 拓扑排序
    HDU 5694 BD String 迭代
  • 原文地址:https://www.cnblogs.com/ruhaoren/p/11990288.html
Copyright © 2011-2022 走看看