后端开发者的Vue学习之路(三)

首发日期:2019-01-26vue


上节内容回顾

  • 数据绑定:v-model
  • 样式绑定:v-bind:class,v-bind:style
  • 事件:v-on
  • Vue指令
  • 数组操做(知道哪些数组操做是能被vm层监听到并能响应式更新到视图上的)
  • Vue的元素复用问题(不使用key时会尽可能复用)

组件


【官方的话】组件系统是 Vue 的另外一个重要概念,由于它是一种抽象,容许咱们使用小型、独立和一般可复用的组件构建大型应用。仔细想一想,几乎任意类型的应用界面均可以抽象为一个组件树:webpack

小菜鸟的话:定义组件就好像定义了一堆“带名字”的模板,好比说可能会有叫作“顶部菜单栏”的组件,咱们能够屡次复用这个“顶部菜单栏”而省去了大量重复的代码。web


什么是组件

  • 在之前的多页面开发的时候,咱们可能会常常须要一个“顶部菜单栏”,因而咱们在每一个html文件中都要加上关于“顶部菜单栏”的代码。可能你会想这份代码可以“复用”就行了。而组件能够定义模板,从而达到复用代码的做用。
  • 组件能够大大提升咱们构建页面的效率。
  • 你能够将组件进行任意次数的复用
    下面用代码来演示一下"复用效果":
<body>
      <div id="app">
        <my-template></my-template><!-- 利用组件名来使用定义的“模板” -->
        <my-template></my-template>
      </div>
      
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('my-template',{ // 第一个参数是组件名,第二个参数是模板的内容
          template: '<div><span>个人模板</span></div>'  
        })
        var vm = new Vue({
          el: '#app'
        })
    </script>

代码效果:
vuex


组件注册

组件注册就是“定义模板”,只有注册了的组件,Vue才可以了解怎么渲染。npm


全局注册组件

  • 全局注册的组件能够用在其被注册以后的任何 (经过 new Vue) 新建立的 Vue 实例中,也包括其组件树中的全部子组件的模板中。【一个Vue应用只有一个根实例,但还容许有其余的实例。在 Vue 里,一个组件本质上是一个拥有预约义选项的一个 Vue 实例。】
  • 全局注册的行为必须在根 Vue 实例 (经过 new Vue) 建立以前发生
  • 全局注册的组件能够在另外一个组件中使用。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <div id="app">
            <ol>
              <!-- 使用组件 -->
              <todo-item></todo-item>
              <todo-item></todo-item>
              <todo-item></todo-item>
            </ol>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        //全局定义组件,第一个参数是组件名,template的值是组件的内容
        Vue.component('todo-item', {
          template: '<li>这是个待办项</li>'
        })
        // 实例化是必须的,要把使用组件的区域交给vue管理
       var app = new Vue({
                  el: '#app',
                })
    </script>
</html>


局部注册组件


全局注册每每是不够理想的。好比,若是你使用一个像 webpack 这样的构建系统,全局注册全部的组件意味着即使你已经再也不使用一个组件了,它仍然会被包含在你最终的构建结果中。这形成了用户下载的 JavaScript 的无谓的增长。数组

在这些状况下,你能够经过一个普通的 JavaScript 对象来定义组件:浏览器

<body>
      <div id="app">
        <my-component></my-component><!-- 利用组件名来使用组件 -->
        <my-component></my-component>
      </div>
      
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var ComponentA = { // 定义一个组件
          template: '<div><span>个人模板</span></div>'            
        }
        var vm = new Vue({
          el: '#app',
          components: {  // 而后在实例中声明要使用这个组件,key是在这个实例中的组件名,value是组件
            'my-component': ComponentA
          }
        })
    </script>


上面的全局注册说了容许在组件中使用其余组件,但注意局部注册的组件要声明使用其余组件才可以嵌套其余组件。例如,若是你但愿 ComponentA 在 ComponentB 中可用,则你须要这样写:缓存

<body>
      <div id="app">
        <my-component></my-component>
        <my-component-b></my-component-b>
      </div>
      
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        var ComponentA = { // 1.定义一个组件
          template: '<div><span>个人模板</span></div>'            
        }
        var ComponentB = { // 2.定义一个组件
          components: { //3.声明使用A组件
            'my-component': ComponentA
          },
          template: '<my-component></my-component>'    // 4.须要在组件的template中写上另外一个组件        
        }
        var vm = new Vue({
          el: '#app',
          components: {  
            'my-component': ComponentA,
            'my-component-b': ComponentB
          }
        })
    </script>


使用细节


组件注册的命名规范:

组件名可使用类my-component-name(kebab-case (短横线分隔命名))或MyComponentName的格式(PascalCase 首字母大写命名法),使用组件的时候能够<my-component-name><MyComponentName>,但在有些时候首字母大写命名法定义组件的是不行的,因此一般推荐使用<my-component-name>【当你使用首字母大写命名法来定义组件的时候,不能直接在body中直接写组件名,而要求写在template中,以下例】。app


<body>
      <div id="app">
        <my-component></my-component>
        <my-component-demo></my-component-demo>
        
      </div>
      
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('my-component',{
          template: '<div><span>个人模板A</span></div>'        
        })
        Vue.component('my-component-demo',{ // 这个是用来测试第二种命名法定义组件的,首字母大写时要写在字符串模板中才能显示(否则显示不了)
          template: '<MyComponentB></MyComponentB>'        
        })
        Vue.component('MyComponentB',{
          template: '<div><span>个人模板B</span></div>'        
        })
        var vm = new Vue({
          el: '#app'
        })
    </script>


组件中只有一个根元素

每一个组件必须只有一个根元素!!
因此下面是不合法的:

若是你确实要有多个元素,那么要有一个根元素包裹它们:


组件也是一个实例


组件也是一个实例,因此组件也能够定义咱们以前在根实例中定义的内容:data,methods,created,components等等。
但一个组件的 data 选项必须是一个函数,所以每一个实例能够维护一份被返回对象的独立的拷贝


组件在某些元素中渲染出错

在一些html元素中只容许某些元素的存在,例如tbody元素中要求有tr,而不能够有其余的元素(有的话会被提到外面)。下面是一个元素被提到外面的例子【而ul并无太严格,因此咱们在前面的todo-list的例子中可以演示成功】

下图能够看的出来div被提到table外面了:

这是为何呢?目前来讲,咱们在页面中实际上是先通过html渲染再通过vue渲染的(后面项目话后是总体渲染成功再展现的),当html渲染时,它就发现了tr里面有一个“非法元素”,因此它就把咱们自定义的组件提到了table外面。
解决方案:
使用tr元素,元素里面有属性is,is的值是咱们要使用的组件名

<body>
        <div id="app">
            <table>
                <tr is='mtr'></tr>
            </table>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('mtr', {
            template: `<tr><td>123</td></tr>` // 这个成功的检测要使用检测元素来看
        });
       var app = new Vue({
                    el: '#app'
                })
    </script>



但不会在一下状况中出错:

  1. 定义组件的时候,template中包含自定义的组件
  2. 单文件组件,也就是说引用vue文件来注册一个组件的时候(这个东西会在后面讲)。
  3. <script type="text/x-template">



组件间的数据传递


在上面定义的组件中使用的数据都是固定的数据,一般咱们都但愿模板能根据咱们传入的数据来显示


父子组件传递数据

(子组件的意思是当前组件的直接子组件,在目前的单个html文件为例时,你能够仅认为是当前页面的非嵌套组件。后面讲到多个组件的合做时因为多个组件之间的嵌套,就造成了组件的父子、祖孙、兄弟关系
要给子组件传递数据主要有两个步骤

  1. 定义组件时,使用props:['数据名'] (能够有多个数据名) 来声明来传入的数据的名字
  2. 使用组件时,给组件中名为"数据名"的属性赋值


演示代码以下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <div id="app">
            <ol>
              <!-- 2.给数据赋值 -->
              <todo-item todo="第一个值"></todo-item>
              <todo-item todo="第二个值"></todo-item>
              <todo-item :todo="msg"></todo-item> 
              <!-- 传入的数据能够是父组件实例中定义的数据。注意要用:来绑定,否则不会识别成实例数据,而是一个字符串 -->
            </ol>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('todo-item', {
          props: ['todo'], // 1.使用props来定义这个组件支持传的参数
          template: '<li>{{ todo }}</li>' // 3.这里演示一下在组件中使用这个传入的参数
        })
       var app = new Vue({
                    el: '#app',
                    data: {
                      msg: 'hello world'
                    }
                })
    </script>
</html>

代码效果:很明显的,咱们的值成功传给子组件了。


子组件向父组件传输数据

  • 咱们能够在子组件中使用emit来触发事件,而后在使用这个组件的时候绑定这个事件就能够监听到这个事件的发生(这时候调用的函数是父组件的处理函数),从而使得父组件接受到子组件传递的消息了。
    要给父组件传递数据主要有两个步骤
  1. 在定义组件时,定义一个包含触发事件的元素,这个事件触发时将会调用emit来触发事件【例如能够在按钮上定义一个onclick事件,这个onclick事件触发时将会调用emit】
  2. $emit()能够有多个参数,第一个参数是触发的事件的名称,后面的参数都是随着这个事件向外抛出的参数。
  3. 使用组件时,对组件进行事件监听,监听的事件与组件内抛出的事件一致
  4. 定义处理目标事件的函数,函数的参数是随事件向外抛出的多个参数。


演示代码以下:

<body>
        <div id="app" >
            <my-component-c v-on:change-color="doSomething"></my-component-c>
            <!-- 2.使用组件的时候监听一下事件,这里将会调用父组件的函数来处理事件 -->
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('my-component-c', {
          template: `
          <button @click="$emit('change-color','hello')">改变颜色</button> 
          ` // 1.定义组件,在组件内定义一个能触发click事件的按钮,onclick事件发生时将会调用emit来向外抛出事件【这里触发的事件不能使用驼峰命名法。推荐使用短横线命名法】
          // 【第一个参数是自定义事件名称,第二个和后续的参数能够用于向组件抛出值,这些值会做为事件响应函数的参数】
        })
       var app = new Vue({
                    el: '#app',
                    data: {
                      msg: 'hello world'
                    },
                    methods: {
                    // 3.将会调用下面的函数来处理事件
                      doSomething: function(value){ // 这里的value是从子组件中抛出的。
                        console.log(value) // 打印一下
                      }
                    }
                })
    </script>

【小tips:上面有多重字符串的使用,普通的双引号和单引号已经不足以嵌套使用了,在外层可使用反引号` ` `【esc下面那个键】来包裹,它也能够达到字符串包裹的效果,特别的是它支持多行字符串。】


非父子组件之间的传值

祖孙组件传数据、兄弟组件传数据都属于非父子组件之间的传值。

  1. 【若是是祖孙组件传数据,可使用父组件传给子组件,子组件传给孙组件。但这是一个费事的作法。】
  2. 通常都会使用vuex,vuex就像一个变量存储器,咱们能够把一些多个组件都须要用到数据存储到vuex的store中。【这个因为内容较重要,留到后面再讲】
  3. 只有少许组件使用某个数据的时候也可使用bus模式,bus至关于给每个组件都加上“同一个”新的vue实例,因为bus是实例之间共享的,当数据发生改变时,能够利用这个vue实例来调用emit方法来抛出新值,而其余组件监听bus中的事件就能够获取到新的值,这样就实现了非父子组件之间的传值。


使用bus传输数据的步骤:

  1. 在Vue的原型上定义vue:Vue.prototype.bus = new Vue()
  2. 当数据发生变化时,调用emit:this.bus.$emit('change',当前组件的数据)
  3. 在组件上监听bus的事件:this.bus.$on('change',一个用于赋值的函数)
  4. 在函数中获取事件触发带过来的参数,赋给当前组件,从而实现两边数据同步。

下面的代码是点击某个组件发生数据变化时,另外一个组件的数据也发生变化:

<body>
        <div id="app">
              <child-a></child-a>
              <child-a></child-a>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        // 1. 给Vue的原型添加一个bus,bus是一个Vue实例
        Vue.prototype.bus = new Vue()
        Vue.component('child-a', {
            data: function() {
                return {
                    content: 0
                }
            },
            methods: {
                // 2.定义一个函数,可以在数据发生变化时调用emit(这里定义一个点击事件的响应函数)
                handleClick: function() { 
                    this.content+=1
                    this.bus.$emit('change',this.content)
                }
            },
            mounted: function(){
                var this_= this // 这里要有一个这样的赋值,下面不能直接使用this,由于在函数中this指向的已经不是当前对象了,而用_this保存的才是当前对象
                // 3. 在组件中对bus中触发的事件进行监听。(当emit触发事件时会调用)
                this.bus.$on('change',function(msg){ // 4.函数中的参数是emit触发事件带的参数。
                    this_.content = msg  // 5.修改当前组件中的数据
                })
            },
            template: `<div @click='handleClick'>{{ content }}</div>`
        });
       var app = new Vue({
                    el: '#app'
                })
    </script>


单向数据流

  • 单向数据流:props使得父组件的数据可以传输到子组件,并且传输的源数据发生改变时,子组件也会发生改变。但若是在子组件中更改prop,这是不行的,会报警告。
  • 每次父级组件发生更新时,子组件中全部的 prop 都将会刷新为最新的值。若是容许你在子组件中修改父组件传入的数据的话,使用了父组件的这个数据的全部子组件的数据都会被修改(这样就下降了组件的复用效果,致使数据流行不肯定,难以肯定这个数据是在哪一个组件中修改的,并且是一个相对危险的行为)
  • 你不该该在一个子组件内部改变 prop。若是你这样作了,Vue 会在浏览器的控制台中发出警告。【这就是单向数据流】
  • 若是你确实须要修改:
    • 那么你应该建立一个子组件内部的数据,这个内部数据由传入的prop的数据进行初始化。(也就是进行数据拷贝)
    • 又或者你可使用计算属性。



Props属性


命名规范:

大小写问题

【有个建议,建议写属性名的时候都使用kebab-case (短横线分隔命名) 命名,由于这个的兼容效果最好】
HTML 中的特性名是大小写不敏感的,因此浏览器会把全部大写字符解释为小写字符。若是你在props中使用了驼峰命名法,那你在定义属性的时候须要使用kebab-case (短横线分隔命名) 命名才能正确传输数据【由于短横线后面的字符能够识别成大写,从而可以匹配到】。

若是在属性中也使用驼峰命名法命名属性的时候会报这样的错:Prop "mycontent" is passed to component , but the declared prop name is "myContent". Note that HTML attributes are case-insensitive and camelCased props need to use their kebab-case equivalents when using in-DOM templates. You should probably use "my-content" instead of "myContent"

<body>
        <div id="app">
            <!--下面这里会报错 -->
            <child myContent='hello-1'></child>
            <!-- 下面会正常 -->
            <child my-content='hello-2'></child>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('child', {
            props:['myContent'],
            template: `<div>{{myContent}}</div>` 
        });
       var app = new Vue({
                    el: '#app'
                })
    </script>

一样的,若是在组件的template属性中使用驼峰命名法的属性,那么这个限制就不存在了。


参数校验

限制props的类型

有时候须要使用第三方的组件的时候,因此会须要传输数据给这个组件来渲染。但如何限制传入的数据的类型呢?

  • 可用于限制数据类型的类型:
    • String:字符串
    • Number:数字
    • Boolean:布尔值
    • Array:数组
    • Object:对象
    • Date:日期
    • Function
    • Symbol


格式:

props: {
// 数据名:数据类型
  title: String,
  likes: Number,
  ...
}


若是传入的类型不对,那么会报Invalid prop: type check failed for prop "xxx". Expected String with value "xxx", got Number with value xxx.的错误。


若是容许多种值,能够定义一个数组:

props: {
  content: [String,Number]
}


设置默认值

咱们也能够给props中的数据设置默认值,若是使用default设置值,那么没有传某个数据时默认使用这个数据。

props: {
  content: {
  type:[String,Number],
  default:'个人默认值'
  }
}

若是使用default给数组或对象类型的数据赋默认值,那么要定义成一个函数。


要求数据必传

若是要求某个数据必须传给子组件,那么能够为它设置required。
格式:

props: {
    content: {
       type: String,
       required: true
   }
}

若是没传,会报Missing required prop: "xxx"的错。


自定义验证函数:

若是想要更精确的校验,可使用validator,里面是一个函数,函数的第一个参数就是传入的值,当函数内返回true时,这个值才会校验经过。
如下的代码是要求传入的字符串长度大于6位的校验:

Vue.component('child', {
          props: {
            content: {
                type: String,
                validator: function(value) {
                    return (value.length > 6)
                }
            }
          }

若是验证不经过,会报Invalid prop: custom validator check failed for prop "xxx"的错。



传递静态或动态Prop

  • 传递静态或动态的prop意思就是传递的是一个常量仍是变量。
  • 传递常量的时候:
    • 若是是字符串,能够不使用v-bind。
    • 若是是数字,布尔值,数组,对象,那么须要使用vue的v-bind来设置属性,由于使用普通的属性设置会被认为是字符串,使用v-bind的时候会被认为是js表达式(从而成功识别成正确的类型)。
  • 传递变量的时候都要使用v-bind,否则没法识别成一个变量。


补充:



给组件绑定原生的事件


用下面的代码来讲一个问题:

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>demo</title>
</head>
    <body>
      <div id="app">
        <child @click='myFunction'></child>
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('child',{
            template:`
                <button>按钮</button>
            `
        });
        var vm = new Vue({
          el: '#app',
          methods: {
            myFunction: function() {
                console.log('haha')
            }
          }
        })
    </script>
</html>


上面的代码你会发现点击了按钮却没有调用函数。
而下面的按钮按了会打出child。

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>demo</title>
</head>
    <body>
      <div id="app">
        <child @click='myFunction'></child>
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('child',{
            template:`
                <button @click='childFunction'>按钮</button>
            `,
            methods: {
                childFunction: function() {
                    console.log('child')
                }
            }
        });
        var vm = new Vue({
          el: '#app',
          methods: {
            myFunction: function() {
                console.log('haha')
            }
          }
        })
    </script>
</html>


  • 在上面咱们提过了父子数据传递,咱们知道了父组件的数据须要props来传递给子组件,说明了父组件的数据是不跟子组件共享的。
  • 而事件也是这样的,在咱们使用组件的时候,并不能直接监听一些事件的发生。【例如上面的子组件传数据给父组件也须要使用emit。】
  • 对于父组件来讲,这个组件是子组件下的按钮,因此直接点击这个按钮并不会触发事件【或者说你能够认为点击了事件了,可是没有emit出来,因此父组件监听不到】。
  • 而若是但愿点击按钮的时候可以触发出按钮的原生事件(不把它看成子组件下的按钮),那么须要把它绑定成原生事件。咱们可使用.native来修饰事件来讲明监听的是一个原生事件。


下面的代码是使用了emit来达到一样效果的代码:

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>demo</title>
</head>
    <body>
      <div id="app">
        <child @click='myFunction'></child>
      </div>
    </body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('child',{
            template:`
                <button @click="$emit('click')">按钮</button>
            `
        });
        var vm = new Vue({
          el: '#app',
          methods: {
            myFunction: function() {
                console.log('haha')
            }
          }
        })
    </script>
</html>



template

  • template是vue中的一个元素。它是一个不会渲染到页面的元素,一般地它有以下几个用处:
    • 因为不会被渲染处理,能够在template上使用使用v-if,把一个 <template> 元素当作不可见的包裹元素,让成组的元素可以统一被渲染出来。
    • 也可使用v-for,也是把<template> 元素当作不可见的包裹元素
    • 其余特殊的用途:例以下面要说插槽的slot-scope会用到。


在template上使用v-if

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>


使用v-for

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>



插槽

  • 咱们能够用prop来传递数据给子组件,而插槽是用来分发内容的。
  • 咱们有时候但愿在使用子组件的时候顺便传给它一些内容,那么可使用插槽。
  • 【props适合于传输数据,而slot一般用来达到“插入内容”的效果;使用props的话须要子组件声明使用,而slot相较随意】


经过插槽分发内容



具名插槽

插槽也能够分发多份数据。使用指定的插槽名就能够获取指定的插槽数据。


插槽的默认内容

若是没有数据传过来,那么插槽能够定义一个默认的数据用来显示。


做用域插槽

  • 有时候咱们但愿获取组件中的slot的值来进行其余操做。好比,可能须要根据一个值来显示不一样的内容。这时候咱们可使用slot-scope来获取组件中传过来的slot的值。
  • slot-scope的值是能够随意的,它表明做用于插槽的名字。
  • 这时候再也不是插入数据给插槽,而是从插槽中获取数据了。
<body>
        <div id="app">
              <child-a>
                  <template slot-scope='props'> <!--2. slot-scope的属性值是能够随意的,表明做用域插槽的名字 -->
                      <h3>{{props.index}}</h3> <!--3. props.xxx 是传过来的值的名字,值须要绑定到slot中 -->
                  </template>
              </child-a>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.prototype.bus = new Vue()
        Vue.component('child-a', {
            data: function() {
                return {
                    list: [2,4,6,8,10]
                }
            },
            // 1. 绑定属性,名为index,那么做用域插槽就能够获取名为index的数据
            template: `<div>
                        <slot v-for='item of list' :index=item></slot>
                    </div>`
        });
       var app = new Vue({
                    el: '#app'
                })
    </script>



动态组件


is

  • 动态组件是一个有趣的东西,它至关于一张空白的组件,只要你告诉它它是什么组件,它就变成了什么组件。
  • 有时候咱们但愿发生了xxx事件以后,页面的某个组件变成另外一个组件。【你可能会产生以下图的需求:点击按钮,切换登陆方式】

  • 咱们只须要给component元素设置上is属性就能够把component元素渲染成目标组件了。<component :is='组件名'></component>若是改变了is属性的值,那么渲染的组件就会发生变化。
  • is能够是v-bind的,也能够是非v-bind的,若是但愿它是动态可变化的,那么应该使用v-bind:is,这样才能传入一个变量,从而动态渲染组件。【非v-bind的时候传入的值会被认为一个字符串,而后直接把这个字符串认为是组件名】


下面是上图的演示代码:

<body>
      <div id="app">
        <button @click='changeLogin'>切换登陆方式</button>
        <component :is='loginType'></component>
      </div>
</body>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      <script>
        Vue.component('userInfoLogin',{
            template:`
            <div>
                <div>用户名登录:<input type="text"></div>
                <div>请输入密码:<input type="password"></div>
            </div>
            `
        });
        Vue.component('phoneLogin',{
            template:`
            <div>
                <div>请输入手机号:<input type="text"></div>
                <div>请输入验证码:<input type="text"></div>
            </div>
            `
        })
        var vm = new Vue({
          el: '#app',
          data: {
            loginType:'userInfoLogin'
          },
          methods: {
            changeLogin: function() {
                this.loginType = this.loginType === 'userInfoLogin'?'phoneLogin':'userInfoLogin';
            }
          }
        })
    </script>


keep-alive

  • 被keep-alive元素包裹的组件会被缓存,缓存以后组件从新渲染时会直接从缓存中获取,避免了每次组件都从新渲染。

下面以上面的动态组件切换为例:
若是给上面的登陆组件都加上一个created用来显示渲染次数的话,咱们就能够看到是否是每次切换都会从新渲染。
若是加了keep-alive以后再也不重复输出,那么就说明组件被缓存了。

<body>
        <div id="app">
            <button @click='changeLogin'>切换登陆方式</button><!-- 2.屡次点击切换,查看组件渲染状况 -->
            <keep-alive>
                <component :is='loginType'></component> 
                <!-- 4.注意在keep-alive包裹以前和以后的控制台输出状况 -->
            </keep-alive>
        </div>
  </body>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script>
          Vue.component('userInfoLogin',{
              template:`
              <div>
                  <div>用户名登录:<input type="text"></div>
                  <div>请输入密码:<input type="password"></div>
              </div>
              `,
              created: function(){
                console.log('userInfoLogin')// 1.用来讲明渲染了userInfoLogin组件,屡次渲染则屡次输出
              }
          });
          Vue.component('phoneLogin',{
              template:`
              <div>
                  <div>请输入手机号:<input type="text"></div>
                  <div>请输入验证码:<input type="text"></div>
              </div>
              `,
              created: function(){
                console.log('phoneLogin') // 2.用来讲明渲染了phoneLogin组件,屡次渲染则屡次输出
              }
          })
          var vm = new Vue({
            el: '#app',
            data: {
              loginType:'userInfoLogin'
            },
            methods: {
              changeLogin: function() {
                  this.loginType = this.loginType === 'userInfoLogin'?'phoneLogin':'userInfoLogin';
              }
            }
          })
      </script>


补充


$refs


  • 有时候你可能须要获取某个元素来进行操做,在没有学refs以前,你可能须要document.xxx来获取某个元素。
  • 学了refs以后,你可使用refs来获取元素


使用步骤:

1.在元素中使用ref属性给元素起一个有标识意义的名字。
2.this.\(refs能够获取当前组件实例的全部使用了ref的元素,`this.\)refs.名字`表明指定的元素。
3.而后你能够进行dom操做了。

<body>
        <div id="app">
            <div ref='demo'>1</div> <!-- 1. 设置ref -->
            <button @click='changeColor'>+1</button>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
       var app = new Vue({
                    el: '#app',
                    methods: {
                        changeColor:function() { 
                            console.log(this.$refs.demo.innerText) // 获取ref对象,有了dom对象你就能够进行dom操做了。
                            this.$refs.demo.style = 'color:red'
                            this.$refs.demo.innerText+=this.$refs.demo.innerText
                        }
                    }
                })
    </script>


获取组件的引用

refs也能够用在组件上,能够获取组件的数据(但这时候的ref获取的不是一个dom对象,而是一个vue实例对象,因此不能获取innerText这类dom属性)。

<body>
        <div id="app">
            <child ref='demo'></child>
            <button @click='changeColor'>+1</button>
        </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('child',{
            data: function(){
                return {

                msg:'hello world!'
                }
            },
            template:'<div>hello</div>'
        })
       var app = new Vue({
                    el: '#app',
                    methods: {
                        changeColor:function() { 
                            console.log(this.$refs.demo.msg) // 获取组件实例的数据。
                        }
                    }
                })
    </script>



动画效果

若是说前面讲的都是基础,必需要掌握的话,那么动画效果是锦上添花,无关紧要(对于我这些不追求动画效果就不显得重要了),因此这里就不讲了,这里仅仅是为了显示vue能有实现动画效果的功能。
有兴趣的能够看一下官网:
vue官网动画效果直通车

相关文章
相关标签/搜索