vue-cli 脚手架:
1.生成目录结构
2.本地开发调试
3.代码部署
4.热加载
5.单元测试
前端路由:在web开发中,路由是指根据url分配到对应的处理程序。
vue-router
作用:通过管理url,实现url和组件的对应和通过url进行组件之间的切换。
单页应用(SPA):加载单个HTML页面,并在用户与应用程序交互时动态更新该页面。
vue-router使用步骤:
安装模块:npm install vue-router --save
引入模块:import VueRouter from 'vue-router'
作为Vue插件:Vue.use(VueRouter)
创建路由实例对象:
new VueRouter({
mode: 'history',//hash模式和history模式;
...配置参数
})
注入Vue选项参数:
new Vue({
router
})
告诉路由渲染的位置:
<router-view></router-view>
hash模式和history模式:
mode: 'history',
router-link:
to/tag/event/exact
嵌套路由:
routes:[
{
path: '/home',
//name:'Home',
component: Home,
alias: '/index' //别名
children: [
{
path:'', //默认的子路由 /home
name:'Home',
component:Home,
},
{
path:'study', //home/study
//path:'/study', //study
name:'Study',
component:Study
},
{
path:'/document',
name:'Document',
components:{
default: Document, //默认
slider: Slider //新建
}
}
]
}
]
命名视图:
<router-view name="slider" ></router-view>
重定向(方式):
redirect:'/home'
redirect:{path:'/home'}
redirect:{name: 'Home'}
redirect: (to) =>{ //动态设置重定向的目标
//目标路由对象,就是访问的路径的路由信息
return '/Home'
}
redirect: (to) =>{ //动态设置重定向的目标
//目标路由对象,就是访问的路径的路由信息
if(to.path === '/123'){
return '/home'
}else if(to.path === '/456'){
return {path: '/document'}
}else{
return {name: 'Home'}
}
}
滚动行为:①
scrollBehavior(to,from,savePosition){ //点击浏览器的前进后退或切换导航触发
console.log(to); // 要进入的目标路由对象 要去向哪里
console.log(from); // 离开的路由对象 从哪里来
console.log(savePosition); // 记录滚动条坐标 点击前进后退的时候记录值
if(savePosition){
return savePosition;
}else {
return {x:0, y:0}
}
}
②
<router-link :to="{path:'/document#abc'}" event="mouseover">Document</router-link>
<div id = "abc">定位到这个元素</div>
scrollBehavior(to,from,savePosition){ //点击浏览器的前进后退或切换导航触发
if(to.hash){
return {
selector: to.hash
}
}
}
动态路径:
匹配到的所有路由,全都映射到同一个组件
路径: /user/:userId suerId为动态路径参数
获取参数:路由信息对象的params
<router-link :to = "'/user/'+item.id" > </router-link>
{ path:'/user/:userId?', // /user/1 /suer/2 /user
component: User}
created(){ //生命周期钩子函数
console.log(this.$router)
console.log(this.$router)
}
对组件注入:
通过在Vue根实例的router配置传入router实例
$router router实例
$route 当前激活的路由信息对象,每个组件实例都会有。
beforeRouterEnter() 进入组件前钩子函数
beforeRouteLeave() 离开组件前钩子函数
路由信息对象:
一个路由信息对象表示当前激活的路由的状态信息,每次成功的导航后都会产生一个新对象
path 字符串,对应当前路由的路径
params对象,包含动态路由参数
query对象,URL查询参数
hash字符串,当前路由的hash值
fullPath 字符串,URL包含查询参数和hash的完整路径
matched数组,包含当前路由的所有嵌套路径片段的路由记录
name字符串,当前路由的名称
<router-link :to = "'/user/'+item.tip+'/'+item.id" > </router-link>
{ path:'/user/:tip?/:userId?', // /user/vip/1 /user/common/2 /user
component: User
}
created(){
//渲染这个组件会调用一次这个生命周期函数
//复用这个组件,这个函数不会再次被调用了
//地址一旦发生变化,$route会重新生成一个路由信息对象
console.log(this.$route)
console.log(this.$route.params.userId)
this.getData()
}
watch:{
$route(){
//路径发生变化,$route会重新赋值,监控这个属性
console.log("监控$route")
console.log(this.$route.params.userId)
this.getData()
}
},
query字符串传参:
<router-link to = "?info = follow">关注</router-link>
<router-link to = "?info = share">分享</router-link>
<router-link :to = "{path:'',query:{info:'follow'}}">关注</router-link>
<router-link :to = "{path:'',query:{info:'share'}}">分享</router-link>
<router-link :to = "{path:'/user/'+item.tip+'/'+item.id, query:{info:'follow'}}" v-for="(item,index) in userList" :key ="item.id"> </router-link>
过渡动效:
提供了transition的封装组件,添加过渡动画
添加删除css类名
过度的css类名:
v-enter: 定义进入过渡的开始状态
v-enter-active:定义进入活动状态
v-enter-to:定义进入的结束状态
v-leave: 定义离开过渡的开始状态
v-leave-active: 定义离开活动状态
v-leave-to: 定义离开的结束状态
使用name属性改变类名前缀
过渡模式:
in-out: 新元素先进行过渡,完成之后当前元素过渡离开
out-in: 当前元素先进行过渡,完成之后新元素过渡进入
<transition mode="in-out"> <router-view></router-view> </transition>
动态设置name属性
<transition name="left">
.left-enter{ transform: translateX(100%); } .left-enter-to{ transform: translateX(0); } .left-enter-active{ transition: 1s; }
路由元信息:
在路由配置中meta可以配置一些数据,用在路由信息对象中
访问meta中数据:$route.meta
{ path: '/home',
component: Home,
meta:{
index:0
}
},
当前导航下标:{{$route.meta.index}}
<transition :name="names" mode="in-out"> <router-view class="center"></router-view> </transition>
data(){
return{
index:'/home',
names:'left'
}
},
watch:{
$route(to,from){
console.log(to.meta.index); //目标导航下标
console.log(from.meta.index); //离开导航下标
if(to.meta.index < from.meta.index){
this.names = 'right'
}else{
this.names = "left"
}
}
}
编程式导航:
借助于router的实例方法,通过编写代码来实现导航的切换
back 后退一步
forward 前进一步
go 指定前进回退步数 //go(0)刷新当前页
push 导航到不同url,向history栈添加一个新的记录
replace 导航到不同url,替换history栈中当前记录
<input type="button" value="后退" @click = "backHandle"/>
<input type="button" value="前进" @click = "frowardHandle"/>
<input type="button" value="控制指定的导航push" @click = "pushHandle"/>
<input type="button" value="控制指定的导航replace" @click = "replaceHandle"/>
methods:{
backHandle(){
this.$router.back()
},
frowardHandle(){
this.$router.forward()
},
pushHandle(){
this.$router.push('/home')
this.$router.push({path:'/document'})
},
replaceHandle(){
this.$router.replace({path:'/document'})
}
},
导航钩子函数:
导航发生变化时,导航钩子主要用来拦截导航,让它完成跳转或取消
执行钩子函数位置:
router全局
单个路由
组件中
钩子函数
router实例上:beforeEach、afterEach
单个路由中:beforeEnter
组件内的钩子:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
钩子函数接收的参数:
to: 要进入的目标 路由对象 到哪里去
from: 正要离开导航的路由对象,从哪里来
next: 用来决定跳转或取消导航
全局钩子函数:
router.beforeEach((to,from,next) =>{
//next()
//next(false);//取消导航
})
meta:{
index:1;
login:true,
title:'home'
}
router.beforeEach((to,from,next) =>{
if(to.meta.login){
next('/login')
}else{
next()
}
})
router.afterEach((to,from) =>{
if(to.meta.title){
window.document.title = to.meta.title;
}else{
window.document.title = 'miaomiao';
}
})
某个单独的路由设置钩子函数:
{
path:'/document',
name:'Document',
beforeEnter(to,from,next){
next();
}
component: Document,
meta:{
index:1,
title:'document'
}
},
组件级钩子函数:
//beforeRouteEnter先于beforeCreate前执行;
export default {
name: "About",
data(){
return{
test: '改变前'
}
},
beforeCreate(){
console.log('beforeCreate')
},
beforeRouteEnter(to,from,next){
console.log('beforeRouteEnter')
console.log(this)
next((vm)=>{
vm.test = "改变了"
})
},
beforeRouteUpdate(to,from,next){
next()
},
beforeRouteLeave(to,from,next){
next()
}
}
懒加载:
把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件
Vue 异步组件
{
components:{
custom:(resolve,reject) => {}
}
}
webpack代码分割功能
require.ensure代码分块
require.ensure(依赖,回调函数,[chunk名字])
import函数
①import Header from '@/components/Header'
components:{
// HeaderNav: Header
headerNav: (resolve)=>{
setTimeout(() =>{
resolve(Header)
},2000)
}
},
②components:{
// HeaderNav: Header
headerNav: (resolve)=>{
setTimeout(() =>{
resolve(require('@/components/header'))
},2000)
}
},
// import Layout from '@/components/Project' == //懒加载方式
// import Doc from '@/components/Doc'
let Layout = (resolve)=>{
return require.ensure([],()=>{
resolve(require('@/components/Project'))
})
}
let Doc = (resolve)=>{
return require.ensure([],()=>{
resolve(require('@/components/Doc'))
})
}
合并成一个JS文件
let Layout = (resolve)=>{
return require.ensure([],()=>{
resolve(require('@/components/Project'))
},"abc')
}
let Doc = (resolve)=>{
return require.ensure([],()=>{
resolve(require('@/components/Doc'))
},'abc')
}
import方式:(目前不能同时加载多个)
let Doc = (resolve)=>{
return import('@/components/Doc'))
}
打包:
npm run build
服务器配置:
Nginx配置:
location/{
root/home/我的应用根目录;
try_files $url $url//index.html =404;
}
Appache配置:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ [L]
RewriteCond %[REQUEST_FILENAME] !-f
RewriteCond %[REQUEST_FILENAME] !-d
RewriteRule .index.html [L]
</IfModule>
Vuex:
Vuex 是什么:
专为Vue.js应用程序开发的状态管理模式
采用集中式存储管理应用的所有组件的状态
以相应的规则保证状态以一种可预测的方式发生变化
状态:
组件内部状态:仅在一个组件内使用的状态(data字段)
应用级别状态:多个组件共用的状态
什么情况下使用 Vuex
多个视图依赖于同一状态
来自不同视图的行为需要变更同一状态
使用Vuex :
安装vuex模块
npm install vuex --save
作为插件使用
Vue.use(Vuex)
定义容器
new Vuex.Store()
注入根实例
{
store
}
Vuex 核心概念
store: 类似容器,包含应用的大部分状态
一个页面只能有一个store
状态存储是响应式的
不能直接改变store中的状态,唯一途径显示地提交mutations
State: 包含所有应用级别状态的对象
Getters: 在组件内部获取store 中状态的函数
Mutations: 唯一修改状态的事件回调函数
Actions:包含异步操作、提交mutation改变状态
Modules: 将store分割成不同的模块
import Vuex from 'vuex'
Vue.use(Vuex)
//定义一个容器
let store = new Vuex.Store({
state:{
count: 1000
},
mutations:{
addIncrement(state,payload){
state.count += payload.n;
},
deIncrement(state){
state.count -= 1
},
deIncrement(state,payload){
state.count -= payload.de
}
}
})
export default store;
<input type="button" value="-" @click = 'deHandle'/> <span>{{num}}</span> <input type="button" value="+" @click = 'addHandle' />
methods:{
addHandle(){
//改变状态,提交mutation addIncrement
this.$store.commit("addIncrement",{
n: 5
})
},
deHandle(){
this.$store.commit("deIncrement")
},
deHandle(){
this.$store.commit({
type: 'deIncrement',
de: 10
})
}
},
computed:{
num(){
return this.$store.state.count
}
}
异步改变:
mutations:{
addIncrement(state, payload){
state.count += payload.n;
},
deIncrement(state,payload){
state.count -= payload.de
}
},
actions:{
addAction(context){
setTimeout(()=>{
//改变状态,提交mutations
context.commit("addIncrement",{n:5})
},1000)
}
}
addHandle(){
//改变状态,提交mutation addIncrement
/*this.$store.commit("addIncrement",{
n: 5
})*/
//触发一个action
this.$store.dispatch("addAction")
},
actions:{
addAction(context){
setTimeout(()=>{
//改变状态,提交mutations
context.commit("addIncrement",{n:5})
},1000)
}
}
action异步操作:
actions:{
addAction(context){
console.log(context);
setTimeout(()=>{
//改变状态,提交mutations
context.commit("addIncrement",{n:5})
context.dispatch("textAction",{text:"测试"})
},1000)
},
textAction(context,obj){
console.log(obj)
}
}
actions:{
addAction({commit,dispatch}){
setTimeout(()=>{
commit("addIncrement",{n:5})
dispatch("textAction",{text:"测试"})
},1000)
},
textAction(context,obj){
console.log(obj)
}
}
getter 计算状态:
let store = new Vuex.Store({
state:{
count: 100
},
getters:{
filterCount(state){
return state.count > 120 ? 120 : state.count;
}
},
mutations:{
addIncrement(state, payload){
state.count += payload.n;
},
deIncrement(state,payload){
state.count -= payload.de
}
},
actions:{
addAction({commit,dispatch}){
setTimeout(()=>{
commit("addIncrement",{n:5})
dispatch("textAction",{text:"测试"})
},1000)
},
textAction(context,obj){
console.log(obj)
}
}
})
export default store;
<input type="button" value="-" @click = 'deHandle'/>
<span>{{num}}</span>
<input type="button" value="+" @click = 'addHandle' />
{{num2}}
computed:{
num(){
return this.$store.state.count
},
num2(){
return this.$store.getters.filterCount
}
}
Vuex 的流程图:
vue调试工具:
Vuex 辅助函数:
mapState
mapGetters
mapMutations
mapActions
import {mapState} from 'vuex'
export default {
name: "Increment",
computed: mapState({
// num: state => state.count
// num: 'count'
num(state){
return state.count + 100
}
}),
}
computed: mapState(['count'])
修改{{count}} <input type="button" value="-" @click = 'deHandle({de: 10})'/> //传参
import {mapState,mapGetters,mapActions,mapMutations} from 'vuex'
export default {
computed:{
abc(){
return 123
},
...mapState(['count']),
...mapGetters({
num2: 'filterCount'
})
},
methods:{
...mapActions({
addHandle: 'addAction'
}),
...mapMutations({
deHandle:'deIncrement'
})
},
}
easy-mock.com 创建模拟接口
npm install axios --save
代码:
store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import Axios from 'axios'
Vue.use(Vuex)
// 划分模块
/*let selectModule = {
state:{
title: 'hello',
list:[]
},
mutations:{
changeTitle(state,payload){
state.title = payload.title
},
changeList(state,list){
state.list = list
}
},
actions:{
getListAction({commit}){
//发送请求
Axios.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1')
.then((data) =>{
console.log(data.data.result)
commit("changeList",data.data.result)
})
.catch((error)=>{
console.log(error)
})
}
}
}*/
// this.$store.state.title
// this.$store.state.selectModule.title
//定义一个容器
let store = new Vuex.Store({
modules:{
// selectModule
},
state:{
count: 100,
title: '',
list: []
},
getters:{
filterCount(state){
return state.count > 120 ? 120 : state.count;
}
},
mutations:{
addIncrement(state, payload){
state.count += payload.n;
},
deIncrement(state,payload){
state.count -= payload.de
},
changeTitle(state,payload){
state.title = payload.title
},
changeList(state,list){
state.list = list
}
},
actions:{
addAction({commit,dispatch}){
// console.log(context);
setTimeout(()=>{
//改变状态,提交mutations
commit("addIncrement",{n:5})
dispatch("textAction",{text:"测试"})
},1000)
},
textAction(context,obj){
console.log(obj)
},
getListAction({commit}){
//发送请求
Axios.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1')
.then((data) =>{
console.log(data.data.result)
commit("changeList",data.data.result)
})
.catch((error)=>{
console.log(error)
})
}
}
})
export default store;
Select.vue:
<template>
<div class="select">
<section class="warp">
<div class="searchIpt claerFix">
<select-input :is-show.sync="listShow"></select-input>
<list v-show="listShow" ></list>
<!--<list v-show="listShow" :data="listData"></list>-->
</div>
</section>
</div>
</template>
<script>
import SelectInput from '@/components/SelectInput'
import List from '@/components/List'
let listData = [
{
title: 'javascript'
},
{
title: 'html+css'
},
{
title: 'jQuery'
},
{
title: 'Vue'
},
{
title: 'angular'
},
{
title: 'react'
},
{
title: 'node.js'
}
]
export default {
name: "Select",
data(){
return{
listShow: false,
listData: listData,
// title: ''
}
},
components:{
selectInput: SelectInput,
list: List
}
}
</script>
<style scoped> </style>
List.vue:
<template>
<div class="">
<ul class="list">
<li v-for="item in data" @click="getTitleHandle(item.title)" >{{item.title}}</li>
</ul>
</div>
</template>
<script>
export default {
name: "List",
data(){
return{
}
},
//props:['data'],
computed:{
data(){
return this.$store.state.list
// return this.$store.state.selectModule.list
}
},
methods:{
getTitleHandle(title){
//改变Vuex中状态
this.$store.commit("changeTitle",{title: title})
}
},
created(){
//获取数据
this.$store.dispatch("getListAction")
}
}
</script>
<style scoped> </style>
SelectInput.vue:
<template>
<div class="clearFix">
<input class="keyWord" readonly="readonly" @click="showListHandle" :value="title" />
<input type="button" value="GO" />
<span></span>
</div>
</template>
<script>
export default {
name: "SelectInput",
data(){
return{
}
},
props:['isShow'],
computed:{
initShow(){
return this.isShow
},
title(){
return this.$store.state.title
// return this.$store.state.selectModule.title
}
},
methods:{
showListHandle(){
this.$emit('update:isShow', !this.initShow)
}
}
}
</script>
<style scoped> </style>
划分模块module:
例:
let selectModule = {
state:{
title: 'hello',
list:[]
},
mutations:{
changeTitle(state,payload){
state.title = payload.title
},
changeList(state,list){
state.list = list
}
},
actions:{
getListAction({commit}){
//发送请求
Axios.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1')
.then((data) =>{
console.log(data.data.result)
commit("changeList",data.data.result)
})
.catch((error)=>{
console.log(error)
})
}
}
}
let store = new Vuex.Store({
modules:{
selectModule
},
})
export default store;
注意取值:
// this.$store.state.title = > // this.$store.state.selectModule.title
Axios
简介:
基于Promise 用于浏览器和nodejs的与服务端通信库
特征:
支持Promise API
拦截请求和相应
转换请求和响应数据
取消请求
自动转换JSON 数据
使用:
$ npm install axios --save
CDN地址:https://unpkg.com/axios/dist/axios.min.js
Mock 模拟数据:
http://easy-mock.com
使用axios
需要的模块中引入使用:
import axios from 'axios'
语法:
1.axios(config)
2.axios[method]()
返回值为 promise
支持的请求方式:
axios.get(url[,config])
axios.post(url[,data[,config]])
axios.delete(url[,config])
axios.head(url[,config])
axios.options(url[,config])
axios.put(url[,data[,config]])
axios.patch(url[,data[,config]])
import axios from 'axios'
created(){
/*axios.get('http://www.phonegap100.com/appapi.php',{
params:{
a: 'getPortalList',
catid: '20',
page: '1'
}
})*/
axios({
method: 'get',
url: 'http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1'
})
.then((response) =>{
console.log(response)
})
.catch((error)=>{
console.log(error)
})
}
自定义请求实例:
创建:
axios.create(config)
配置:
{
baseURL: '',
timeout:1000,
headers:{},
reaponseType: 'json',
params:{},
transformRequest:[] //只适合PUT、POST和PATCH
transformResponse:[]
validateStatus: function(){ }
cancelToken
}
import axios from 'axios'
var HTTP = axios.create({
baseURL:'',
timeout: 1000,
headers: {
'custom-header':''
},
responseType: 'json',
params: { }
})
created(){
HTTP.get("")
.then((response) =>{
console.log(response.data)
})
.catch((error)=>{
console.log(error)
})
}
取消请求:
创建取消请求令牌:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
配置
cancelToken: source.token
捕获取消错误
if(axios.isCancel(error)){
console.log(error.message);
}
调用取消
source.cancel('操作被用户取消')
并发请求;
请求;
axios.all(iterable)
axios.spread(callback)
created(){
function http1(){
return HTTP.get("")
}
function http2(){
return HTTP.post("")
}
axios.all([http1(),http2()]).then((response)=>{
console.log(response)
})
.catch((error)=>{
if(axios.isCancel(error)){
console.log(error.message);
}else{
console.log(error)
}
})
}
axios.all([http1(),http2()]).then(axios.spread((res1,res2)=>{
console.log(res1)
console.log(res1)
}))
.catch((error)=>{
if(axios.isCancel(error)){
console.log(error.message);
}else{
console.log(error)
}
})
拦截器:
全局拦截:
拦截请求
axios.interceptors.request.use(function(config){
//在发送请求之前做某事
return config;
},function(error){
//请求错误时做某事
return Promise.reject(error);
});
拦截响应
axios.interceptors.response.use()
取消拦截:
axios.interceptors.request.eject(myInterceptor);
例
HTTP.interceptors.request.use(function(config){
//在发送请求之前做某事
console.log(config)
return config;
},function(error){
//请求错误时做某事
return Promise.reject(error);
});
HTTP.interceptors.response.use(function(data){
console.log(data);
return data;
})
在vue 中使用
安装:
npm install axios vue-axios --save
作为插件
Vue.use(VueAxios,Axios)
在组件中使用
this.$http[method]()
import Axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, Axios)
import Axios from 'axios'
methods:{
getData(){
//请求数据
var api='http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1';
this.$http.get(api).then(function(response){
console.log(response);
//注意this指向
this.list=response.body.result;
}, function (err) {
console.log(err)
})
},
getData2(){
var api2='http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1';
Axios.get(api2).then((response)=>{
console.log(response)
this.list2=response.data.result;
}).catch((error)=>{
console.log(error)
})
}
},
mounted(){ /*生命周期函数*/
this.getData();
this.getData2()
}
vue 的几个特点: 1.应用范围广 2.生态环境好 3.代码轻量(vuejs的底层帮助我们做了很多事情) 4.上手简单,使用容易(使用react要学习JSX语法、es6语法,angular要学习TypeScript语法) 学习NUXT框架、WEEX框架: v-once指令,<span v-once></span>; rawHTML、v-html="rawHTML"; v-if 和 v-show 区别: key=index 与 key=id 区别; v-for="(item,index) in list" :key="index" :key="item.id" 数组不能根据索引改变值 Vue.set(vm.list, 3, {id:'1004',text:'明天见!'} ) vm.$set(vm.list, 4, {id:'1005',text:'后天见!'} ) vm.list.splice(3, 1, {id:'1004',text:'明天见!'} ) 循环对象 v-for="(item,key,index) in userInfo" Vue.set(vm.userInfo, 'age', '20' ) vm.$set(vm.userInfo, 'country', 'china' ) is特性/data项: <table> <tbody> <tr is="child"></tr> </tbody> </table> Vue.component('child',{ data:function(){ return{ content: 'this is a row' } }, template:'<tr><td>{{content}}</td></tr>' }) ref特性: <div ref="div" @click="handleDivClick">this is a content of div</div> methods:{ handleDivClick: function(){ console.log(this.$refs.div) } }, 父子组件传值;组件prop校验;prop特性: $emit() 组件原生事件绑定;非父子组件传值: <child @click.native = "handleClick"></child> vuex 插槽; 单个插槽 slot 多个插槽 <div slot="header">this is header</div> <slot name="header"></slot> 作用域插槽 <child> <template slot-scope="props"> <h1>{{props.content}}</h1> </template> </child> Vue.component('child',{ template:'<div><slot content="我是一段插槽"></slot></div>' }) v-once 指令: <transition [type="transition"][:duration= {enter:1000,leave:1000}] appear enter-active-class = "enter v-enter-active" leave-active-class = "leave v-leave-active" appear-active-class="enter v-appear-active"></transition> 钩子函数: @before-enter="handleBeforeEnter"; @enter="handleEnter"; @after-enter="handleAfterEnter"; @before-leave="handleBeforeLeave"; @leave="handleLeave"; @after-leave="handleAfterLeave"; handleBeforeEnter:function (el) { console.log(el) el.style.color="red" }, handleEnter:function (el,done) { console.log(el) setTimeout(function(){ el.style.color="yellow" },1000) setTimeout(function(){ done() },2000) } handleAfterEnter:function (el) { console.log(el) el.style.color="blue" } 学习 velocity.js 库: 多个元素或组件的过渡: <transition mode="out-in[in-out]"></transition> <transition mode="out-in[in-out]"> <component :is="child-one"></component> </transition> Vue.component('child',{ template:'<div>child-one</div>' }) 列表过渡: <transition-group> <li v-for ="item of list" :key="item.id">{{item.text}}</li> <transition-group> 动画封装: <fade :show="show"> <div>hello from div</div> </fade> </div> Vue.component('fade',{ props:['show'], template: '<transition @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter" @before-leave="handleBeforeLeave" @leave="handleLeave" @after-leave="handleAfterLeave" ><slot v-if="show"></slot></transition>', methods:{ handleBeforeEnter:function (el) { el.style.opacity= 0; console.log("进场动画即将执行") }, handleEnter:function (el,done) { Velocity(el,{ opacity:1 },{ duration:3000, complete:done }) console.log("进场动画执行中") }, handleAfterEnter:function (el) { console.log("进场动画执行完毕") } } })