5

MVVM模式

MVVM是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对 View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定

一、基础用法

1. 模板语法和指令

普通常用:

v-cloak //vue 未解析之前 一般配合用 [v-cloak] {display: none;}

v-bind 或者缩写 <img :src="src" alt="" />
v-on   或者缩写 <button @click="greet">Greet</button>  

v-text  <span v-text="msg"></span> || <span>{{msg}}</span>
//v-text 权重比{{}}高

v-html  <div v-html="html"></div>

v-ref  //
<child :ref="head"></child> //给子组件一个ref命名
vm.$refs.head //父组件可通过该方法读取修改子组件的属性 和调用子组件的方法

//显不显示 也可以搭配v-else使用
v-show  
    <div v-show="show">aaa</div> 
    <div v-else>bbb</div> 

//宣不渲染 存不存在 条件
v-if  v-else-if v-else  
    <div v-if="status"></div>

v-model  //表单元素,双向绑定
        <input type="text" v-model="mess"/>

v-pre //不编译,当字符串输出
        <span v-pre>{{mess}}</span>

v-once  //内容解析一次,当改变值再改变也不映射修改
         <span v-once>{{mess}}</span>
         

循环v-for Array | Object | Number | String

这个单独拿出来写 更清晰:
一般jsfor in是遍历key,而for of遍历value
一类:
data = {
  title: 'How to do lists in Vue',
  author: 'Jane Doe',
  publishedAt: '2016-04-10'
}
data = [{},{},{}]
<div v-for="(value, index) in data">
    <span>{{value}}</span>
    <span>{{index}}</span>
</div> 


二类:
data={
    "key1":{
        "aa":"1","bb":"2"
    },
    "key2":{
        "aa":"2","bb":"4"
    }
}
<div v-for="(item,key,index) of data">
    <span>{{item}}</span>
    <span>用of就能访问到 key1|key2 :{{key}}</span>
    <span>{{index}}</span>
</div> 

2. 样式绑定
绑定 class
对象:
<div :class="{classNam1: 1 == 1, className2: 1 == 2}"></div>
单个:
<div :class="classObject"></div>

数组:
<div :class="[class1, class2, 'className3', active ? 'className4' : '']"></div>
对应的data
data: {
    class1: 'className1',
    class2: 'className2',
    active: true
}

绑定再方法上:
 <div :class="classObjectComputed"></div>
computed: {
    classObjectComputed: function(){
        return{
            className1: true,
            className2: true
        }
    }
}
---------------------------------------------------
绑定style 
在对象当中,CSS 的属性名要用驼峰式表达:fontSize 解析成 font-size

对象:
 <div :style="{color: color, fontSize: fontSize, backgroundColor: '#ccc'}"></div>
data: {
    color: 'red',
    fontSize: '12px'
}


数组:
<div :style="[styleObject, {backgroundColor: '#ccc'}]"></div>
data: {
    styleObject: {
        color: 'red',
        fontSize: '12px'
    }
}
3. 事件修饰符 .**
<!--阻止事件冒泡.stop  等同于event.stopPropagation()-->
<div id="div1" class="stop" @click.stop="event1(1)">

<!--使用事件捕获模式.capture-->
<div id="div4" class="stop" @click.capture="event1(4)">

<!--事件只作用本身.self,类似于已阻止事件冒泡-->
<div id="div7" class="stop" @click.self="event1(7)">

<!--阻止浏览器默认行为.prevent 等同于event.preventDefault()-->
<a href="https://m.baidu.com" target="_blank" @click.prevent="prevent">dk's github</a>

<!--只作用一次.once-->
<a href="https://m.baidu.com" target="_blank" @click.once="prevent">dk's github</a>

<!--修饰符可以串联.click.prevent.once-->
<a href="https://m.baidu.com" target="_blank" @click.prevent.once="prevent">dk's github</a>

二、Vue实例化时基本属性

1. 实例元素 el

实例化在哪个容器里 如果有多个相同的实例元素则只有第一个起效。

##挂载方式一:
<div id="app"></div>
var vm = new Vue({
   el:"#app" //挂载方式一:常用方式
})
##挂载方式二:
<div id="app"></div>
vm.$mount("#app"); //挂载方式二: 手动进行挂载
console.log(vm.$el) // 可以通过实例获取实例元素   
2. 数据对象 data

M(Model) 数据模型层 映射到V层。

(1) 实例创建之后,vm.$data可访问原始数据对象。Vue实例也代理了 data 对象上所有的 property,因此访问vm.a等价于访问vm.$data.a

(2) 以_或$开头的 property不会被 Vue 实例代理,可使用例如vm.$data._property的方式访问这些 property。

(3) 当一个组件被定义,data必须声明为返回一个初始数据对象的函数,使之创建独立作用域,多次调用同个组件时是个全新副本数据对象不相互影响。

(4) 注意,如果你为data property 使用了箭头函数,则this不会指向这个组件的实例

关于视图不更新怎么解决?
方法一: vm.set()
对象用法:vm.$set(Object, key, value)
数组用法:vm.$set(Array, index, Value)

1.对于对象,如果要给对象添加新的属性,数据变化 视图没变化

Vue在初始化实例时进行双向数据绑定,使用Object.defineProperty()对属性遍历添加 getter/setter 方法,所以setter属性必须在 data 对象上存在时才能进行setter过程,触发视图响应。此时需要用到$set

视图不更新:this.dataform.username = '123'; // 直接赋值 在视图上不显示

视图更新:this.$set(this.dataform, 'username', '123'); //改用 $set 更新可以在视图上显示

2.对于数组,由于 JavaScript 的限制,Vue不能检测以下变动的数组

//以下两操作均无法触发视图更新。其余操作正常,另外如果用到splice删除后引起长度变化 注意
#视图不更新:this.arr[index] = val; 
#视图更新:this.$set(this.arr, index, val);

#视图不更新:this.arr.length = 2;
#视图更新:this.arr.splice(2);

//对于清空数组推荐
this.arr = []; 
方法二:vm.forceUpdate()

可是如果我们不想利用$set去设置,非要按照我们第一种方式去写,可以实现么?答案是可以的,就是利用$forceUpdate了,因为你修改了数据,但是页面层没有变动,说明数据本身是被修改了,但是vue没有监听到而已,用$forceUpdate就相当于按照最新数据给渲染一下。

change: function(index) {
    this.arr[index] = '9';
    this.$forceUpdate();
},
clearLen: function() {
    this.arr.length = 2;
    this.$forceUpdate();
}
3. 事件处理器 methods

元素可以通过事件进行绑定事件。

注意,不应该使用箭头函数来定义 method 函数
(例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

4. 计算属性 computed

主要是针对 data 的属性进行操作,this的指针默认指向实例vm。
可以像绑定普通属性一样在模板中绑定计算属性

<div id="example">
  <p>原本值: "{{ basicNum }}"</p>
  <p>计算后的值: "{{ countNum }}"</p>
</div>
<script>
  var vm = new Vue({
  el: '#example',
  data: {
    basicNum: 0
  },
  computed: {
    // 计算属性的 getter
    countNum: function () {
      return Math.floor(this.basicNum*999/100);
    }
  }
})
</script>
// 设basicNum = 3  >> countNum = 29
// 设countNum = 28 报错 因为计算属性默认情况下不支持set设值

默认只有getter没有setting,只能读取不能修改。 需要支持修改的话 要手动加上去 like this:

<div id="app">
    <!--fullName.get 只被调用一次-->
    <p>{{fullName}}</p>
    <p>{{fullName}}</p>
    <p>{{fullName}}</p>
    <!--每次点击都会调用 changeName-->
    <input type="button" value="changeName" @click="changeName('Vue')">
</div>
<script>
var vm = new Vue({
    el: '#app',
    data: {
        firstName:'DK',
        lastName: 'Lan',
        newName: ''
    },
    computed: {
        fullName:{
            get: function(){
                return this.firstName + '.' + this.lastName
            },
            set: function(newValue){
                this.firstName = newValue
            }
        }
    },
    methods: {
        changeName: function(txt){
            this.newName = txt;
            //如果在这里改变 this.fullName 的值,则会再次自动触发对应的 getter
        }
    }
})
</script>
5. 监听器 watch

当该属性发生改变的时候,自动触发,此项使用不当会影响性能,慎用

<div id="example">
  <p>输入的值: <input v-model="basicNum"></p>
  <p>计算后的值: "{{ countNum }}"</p>
  
</div>
<script>
  var vm = new Vue({
  el: '#example',
  data: {
    basicNum: 0
  },
  watch: {
    // 侦听 data属性 这个属性一旦变化 
    basicNum: function () {
      return Math.floor(this.basicNum*999/100);
    }
  }
})
//补充 computer 和 watch 还都支持对象的写法。
vm.$watch('obj', {
    // 深度遍历
    deep: true,
    // 立即触发
    immediate: true,
    // 执行的函数
    handler: function(val, oldVal) {}
})
</script>
computed与watch区别
  • 相同:
    computed和watch都起到监听/依赖一个数据,并进行处理的作用
  • 不同:
    1.computed 创建新的属性, watch 监听 data 已有的属性
    2.computed 会产生依赖缓存
    3.当 watch 监听 computed 时,watch 在这种情况下无效,仅会触发 computed.setter

    {
        computed: {
            a: {
                get: function(){
                    return '';
                },
                set: function(newVal){
                    //会触发此项
                    console.log('set val %s', newVal);
                }
            }                 
        },
        watch: {
            a: function(){
                //不会被触发
                console.log('watch');
            }
        }    
    }

所以一般来说需要依赖别的属性来动态获得值的时候可以使用computed,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用watch

6. 过滤器 filters

(1) 介绍

<div id="app"> 
    <!-- 用法一:在双花括号中 -->
    {{ money | monerFilter }}
    <!-- 用法二:在表达式中  版本要求2.1.0+ -->
    <div v-bind:id="rawId | formatId"></div>
</div>

<script>
//定义方法一:vue选项中定义本地的过滤器
    var vm = new Vue({
        el: '#example',
        filters: {
          capitalize: function (value) {
            return "¥"+ value 
          }
        }
    })
//定义方法二:在vue实例化之前全局定义过滤器
    Vue.filter('formatId', function (value) {
      return value + "_total"
    })

    new Vue({
      // ...
    })
</script>

(2) 可调用多个过滤器: {{msg | filterA | filterB}}

<template>
  <div>  
    {{msg | filterA | filterB}} <!-- //可调用多个过滤器 -->
  </div>
</template>
<script>
export default {
  data () {
   return {
     msg: '5'   //数据
   }
  },
  filters: {
    filterA(val) {
      return val - 0       // 返回值
    },
    filterB(val) {
      return val + 12       // 返回值
    }
  }
}
</script>

(3) 允许传入多个参数: {{msg|filterA(a,b,c)}}

<template>
  <div>  
    {{msg | filterA('转换结果',false)}}
  </div>
</template>
<script>
export default {
  data () {
   return {
     msg: '5'   //数据
   }
  },
  filters: {
    filterA(val) {
      console.log(arguments); // ["5","转换结果",false] msg是第一个值 后面是传入的值
      let [a,b,c] = arguments;
      return c ? Number(a).toFixed(2) : `${b}: ${a}`      // 返回值
    }
  }
}
</script>
7. 生命周期

(1) vue 生命周期:
beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed

var app = new Vue({
  el: '#app',
  data: {
      msg: "你好,我是初始值"
  },
  beforeCreate: function() {
      console.log(this.$el,this.$data,this.msg); 
      // this.$el >> undefined ; this.$data >> undefined ; this.msg >> undefined 
  },
  created: function() {
      console.log(this.$el,this.$data,this.msg); 
      // this.$el >> undefined ; this.$data >> 有值 ; this.msg >> 已被初始化 "你好,我是初始值"  
  },
  beforeMount: function() {
      console.log(this.$el,this.$data,this.msg); 
      // this.$el >> 有值 ; this.$data >> 有值 ; this.msg >> 已被初始化 "你好,我是初始值" 
      // <p>{{msg}}</p> 页面调用的东西依然是代码状态  
  },
  mounted: function() {
      console.log(this.$el,this.$data,this.msg); 
      // this.$el >> 有值 ; this.$data >> 有值 ; this.msg >> 已被初始化 "你好,我是初始值" 
      // <p>你好,我是初始值</p> 已挂载 页面调用的东西渲染出数据
  },

  // 某个地方修改值后触发beforeUpdate、updated;如 vm.msg = '你好,我更新了'
  beforeUpdate: function() { //数据已更新调用,发生在虚拟 DOM 打补丁之前,DOM 未更新时。
      console.log(this.$el,this.$data,this.msg);  
      // this.$el >> 有值 ; this.$data >> 有值 ; this.msg >> "你好,我更新了" 

      console.log(this.$el.innerHTML); //"你好,我是初始值"
      console.log(this.$el); //展开和updated一样都是更新后的 因为当点开下面的箭头展开具体内容时,显示的是该指针指向对象的当前内容,因此看来,两个都一样。

  },
  updated: function() {
      console.log(this.$el,this.$data,this.msg);  
      // this.$el >> 有值 ; this.$data >> 有值 ; this.msg >> "你好,我更新了" 

      console.log(this.$el.innerHTML); //'你好,我更新了'
      console.log(this.$el); //更新后的

  },

  //例如触发 app.$destroy(); 销毁vm实例与DOM之间的关联
  //beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
  //destroyed后,DOM所有东西仍然存在,实例指示的所有东西都会解绑定,所有的事件监听器会被移除, 不过后续就不再受vue控制。
  beforeDestroy: function() {
      console.log(this.$el,this.$data,this.msg);  
  },
  destroyed: function() {
      console.log(this.$el,this.$data,this.msg);  
  }
})

(2) 组件还有两个生命周期函数
activated,deactivated

export default {
  name: "MyFamily",
  components:{
    FamilyItem
  },
  data(){
  },
  //在创建vue对象时,当html渲染之前就触发;created()只会触发一次;
  created() {
    console.log('进来执行了');
  },
  //每次进入当前存在activated()函数的页面时就触发;
  activated(){
    console.log('activated');
  },
  deactivated(){
    console.log('deactivated');
  }
}

(3) 第一次页面加载会触发哪几个钩子?
beforeCreate、created、beforeMount、mounted

(4) DOM 渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了,但 mounted 不会保证所有的子组件也都一起被挂载。如希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick

mounted: function () {
  this.$nextTick(function () {
    // do something
  })
}
8. 自定义指令 directives

除了默认内置的指令 (v-modelv-show),Vue允许注册自定义指令,可分全局指令和局部指令。

全局指令
<div id="app">
    <!--使用自定义的指令 v-myGlobalDir-->
    <input type="text" value="" v-myGlobalDir />
</div>
<script>
// 注册指令名称不用写前缀 v-
// 参数 element:使用指令的元素
Vue.directive('myGlobalDir',  function(element){
    //默认触发钩子函数的 inserted
    element.value = "世界和平";
    element.focus();
})

var vm = new Vue({
    el: '#app'
})
</script>    
局部指令
<div id="app">
    <!--使用自定义的指令 v-privateDir-->
    <input type="text" value="" v-privateDir />
</div>
<script>
var vm = new Vue({
    el: '#app',
    directives: {
        //注册指令名称不用写前缀 v-
        // 参数 element:使用指令的元素
        privateDir: function(element){ 
            element.style.background = '#ccc';
            element.value = "世界和平";
        }
    }
})
</script>
指令的钩子函数

钩子函数可以理解成是指令的生命周期

  • bind:指令第一次绑定到元素时调用。可用于初始化。
  • inserted:被绑定元素插入父节点时调用
  • update:被绑定元素所在的模板更新时调用。
  • componentUpdated:指令所在组件完成一次更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

详细参数点击跳转官网

<div id="app">
    <!--使用自定义的指令 v-demo-->
    <input type="text" v-model="text" v-demo="{color:'red'}">
</div>

<script>
Vue.directive('demo', {
    //先于 inserted 触发,只调用一次 可用于初始化
    bind: function(element, binding, vnode){
        console.log('bind');
        element.style.color = binding.value.color
    },
    //被绑定元素插入父节点时调用 后于 bind 触发 
    //参数 element: 使用指令的元素; 参数 binding: 使用指令的属性对象; 参数 vnode: 整个 Vue 实例
    inserted: function(element, binding, vnode){
        console.log('inserted');
    },
    //被绑定元素所在的模板更新时调用,而不论绑定值是否变化
    update: function(element, binding, vnode){
        console.log('update');
    },
    //被绑定元素所在模板完成一次更新周期时调用。
    componentUpdated: function(element, binding, vnode){
        console.log('componentUpdated');
    }
})

var vm = new Vue({
    el: '#app',
    data:{
        text: '钩子函数'
    }
})
</script>

案例:自定义日期控件

<div id="app">
    <!--直接在 jQuery 环境下使用 datepicker 插件-->
    <input type="text" id="datepicker" data-date-format="yyyy-mm-dd"/>
    <!--使用 Vue 自定义指令 v-datepicker-->
    <input type="text" v-datepicker data-date-format="yyyy-mm-dd"/>
    <input type="button" value="保存" @click="save">
    <span>{{dataform.birthday}}</span>
</div>

//在没有使用 Vue 前,datepicker 插件在 jQuery 的环境下是这样使用
$('#datepicker').datepicker();

//使用 Vue 自定义指令 v-datepicker
Vue.directive('datepicker', function(element, binding, vnode){
    // data = dataform.birthday
    $(element).datepicker({
        language: 'zh-CN',
        pickTime: false,
        todayBtn: true,
        autoclose: true
    }).on('changeDate', function(){
        //由于不是手动在 input 输入值,所以双向绑定 v-model 无效
        //所以需要手动改变实例的数据模型
        var data = $(element).data('model');
        if(data){
            // datas = ['dataform', 'birthday']
            var datas = data.split('.');
            //context = vm
            var context = vnode.context;
            //循环属性自动添加
            datas.map((ele, idx) => {
                //最后一个属性就直接赋值
                if(idx == datas.length - 1){
                    context[ele] = element.value
                } else {
                    //动态添加属性
                    context = context[ele]
                }
            })
        }
    })
})

var vm = new Vue({
    el: '#app',
    data: {
        dataform: {}
    },
    methods: {
        save: function(){
            //使用 $set 更新 dataform
            //更多 $set 的使用在下面继续介绍
            this.$set(this.dataform)
        }
    }
})

三、 组件

1. 组件注册使用

(1).组件命名两个选择:
短横线分隔命名 eg:<my-component-name>;
驼峰命名 eg:<MyComponentName>;

(2)组件data必须是个函数并return返回,强迫创建一个独立作用域,就算组件多次复用不相互影响。

局部组件
<div id="app">
    <!--组件的使用-->
    <private-component></private-component>
</div>
//组件的定义 Vue.component(组件名称, {template})
var vm = new Vue({
    el: '#app',
    components:{
        'private-component': {
            template: '<h1>局部组件</h1>'
        }
    }
})

最终渲染的效果

<div id="app">
    <h1>局部组件</h1>
</div>
2.插槽

Vue 组件默认是覆盖渲染,为了解决这一问题,Vue 提出了 slot 分发内容,留给父组件注入内容。

//父组件
<div id="app">
    <component1>
        <h1>Sam</h1>
        <h1>Lucy</h1>
    </component1>
</div>

//组件留有slot
Vue.component('component1', {
    template: `
        <div>
            <h1>Tom</h1>
            <slot></slot>
        </div>`
})

>>渲染出来效果
<div id="app">
    <component1>
        <h1>Tom</h1>
        <h1>Sam</h1> //注入
        <h1>Lucy</h1> //注入
    </component1>
</div>
具名slot

如果要将组件里面不同的子元素放到不同的地方,那就为子元素加上一个属性 slot="名称",然后在组件定义的时候用名称对应位置 ,其它没有 slot 属性的子元素将统一分发到 里面

//父组件
<h1 slot="lucy">Lucy</h1> //在名字为lucy的slot注入内容


//组件内部
<slot name="lucy"></slot>
缩写

(v-slot:) 替换为字符#。例如v-slot:header可以被重写为#header

3.动态和异步组件
(1)动态组件 is
<div id="app" style="display: none;">
    //切换动态组件
    <input type="button" value="changeLight" @click="changeLight" /> 
    <br/>
    //渲染读取动态组件
    <p :is="show"></p>
</div>

<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            show: 'red',
        },
        methods:{
            changeLight: function(){
                this.show = this.show == 'red' ? 'green' : 'red';
            }
        },
        components: {
            red: {
                template: '<h1>Red</h1>'
            },
            green: {
                template: '<h1>Green</h1>'
            }
        }
    })
</script>
  • <keep-alive> 组件实例在第一次创建的时候被缓存下来

    <!-- 失活的组件将会被缓存!-->
    <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
    </keep-alive>
(2) 异步组件

Vue.component('async-example', function (resolve, reject)
resolve 加载成功
reject 加载失败

<template>
<div>
    组件一 延迟300毫秒,从服务器加载
    组件二 不延迟从服务器加载
    <template v-if="loadComponent">
        <child></child>
        <child2></child2>
    </template>
    <button @click="toggle">点击异步加载组件</button>
</div>
</template>
<script>
import Vue from 'vue';
const child = Vue.component('child', function (resolve) {
    setTimeout(function () {
        require(['./child.vue'], resolve)
    }, 3000);
});
const child2 = Vue.component('child2', function (resolve) {
    require(['./child2.vue'], resolve)
});
export default{
    data: function () {
        return {
            loadComponent: false
        };
    },
    components: {
        child,
        child2,
    },
    methods: {
        toggle:function () {
            this.loadComponent = !this.loadComponent;
        }
    }
}
</script>

4.组件间的通讯

(1)父传子

父组件在引入子组件时上带属性过去,子组件props接收。
image.png

(2)子传父

父组件在引入子组件时v-on订阅监听对应的数据,子组件通过$.emit数据发送给父
image.png

(3)兄弟传兄弟

引入公共bus文件
image.png

(4)引入插件vueX托管状态

5.动画和过度效果
(1) 设置name, 然后和切换参数搭配设置。

在进入/离开的过渡中,会有 6 个 class 切换。
v-enter: 定义进入过渡的开始状态。在元素被插入之前生效。
v-enter-active: 定义进入过渡生效时的状态。
v-enter-to: 进入过渡的结束状态。
v-leave: 定义离开过渡的开始状态。
v-leave-active: 定义离开过渡生效时的状态。
v-leave-to: 离开过渡的结束状态。

<transition name="fade">
<p v-if="show">hello</p>
</transition>

.fade-enter-active, .fade-leave-active { 
    transition: opacity .5s;  //直接写
    //animation: bounce-in .5s; 或者在css动画里写
} 
.fade-enter, .fade-leave-to  /\* .fade-leave-active below version 2.1.8 \*/ { 
    opacity: 0; //直接写
    //animation: bounce-in .5s; 或者在css动画里写
}

@keyframes bounce-in {
  0% {transform: scale(0)}
  100% {transform: scale(1)}
}
(2) 自定义过渡的类名

enter-class 定义进入过渡的开始状态。在元素被插入之前生效。
enter-active-class 定义进入过渡生效时的状态。
enter-to-class 进入过渡的结束状态。
leave-class 定义离开过渡的开始状态。
leave-active-class 定义离开过渡生效时的状态。
leave-to-class 离开过渡的结束状态。

<transition
  name="custom-classes-transition"
  enter-active-class="animated tada"
  leave-active-class="animated bounceOutRight"
>

直接调用了Animate.css的动画,也可以写自己动画。
(3) JavaScript钩子
<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>


----------------------

methods: {
  beforeEnter: function (el) {},
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  enter: function (el, done) { done() },
  afterEnter: function (el) {},
  enterCancelled: function (el) {},


  beforeLeave: function (el) {},
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  leave: function (el, done) { done() },
  afterLeave: function (el) {},
  leaveCancelled: function (el) {} // leaveCancelled 只用于 v-show 中
}

参考资料:
官网:https://cn.vuejs.org/
学习笔记: https://github.com/Wscats/vue...
过渡:https://segmentfault.com/q/10...


Jerry
481 声望203 粉丝

学习的付出 从不欺人。记忆总是苦,写总结最牢固