vue.js 过渡动效

过渡动效

图片描述

    <div id="app">
        <component :is="currView"></component>
        <ul>
            <li><router-link to="/foo">foo</router-link></li>
            <li><router-link to="/bar">bar</router-link></li>
            <li><router-link to="/student">student</router-link></li>
        </ul>
        <transition :name="transitionName" mode="out-in">
            <router-view></router-view>
        </transition>
        
    </div>
 <script>

var router=new VueRouter({
routes:[
      {
    path:"/student",
    component:{
        template:`
        <ul>
            <li><router-link to="/student/xiaoli">xiaoli</router-link></li>
            <li><router-link         
                  to="/student/xiaozhang">xiaozhang</router-link></li>
            <li><router-link to="/student/xiaowang">xiaowang</router-link></li>
        </ul>
        `
        }
    },
{
    path:"/student/:name",
    component:{
        template:`
                <ul>
                    <li><router-link to="/student">back</router-link></li>
                    <li>{{$route.params.name}}</li>
                    
                </ul>
                `
            }
        },
    ]
});
    var vm=new Vue({
    el:"#app",
    data:{
        currView:"home",
        transitionName:""
    },
    components:{
          home:{
            template:"<div>home</div>"
        },
        about:{
            template:"<div>about</div>"
        }

    },
    router,
    watch:{
        '$route'(to,from){
            const toDepth = to.path.split('/').length
            const fromDepth = from.path.split('/').length
            this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
        }
    }
});

</script>   
    

<router-view> 是基本的动态组件,所以我们可以用 <transition> 组件给它添加一些过渡效果:

    <transition>
    
      <router-view></router-view>
      
    </transition>

单个路由的过渡

上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用 <transition> 并设置不同的 name。

const Foo = {
  template: `
    <transition name="slide">
      <div class="foo">...</div>
    </transition>
  `
}

const Bar = {
  template: `
    <transition name="fade">
      <div class="bar">...</div>
    </transition>
  `
}

基于路由的动态过渡

还可以基于当前路由与目标路由的变化关系,动态设置过渡效果:

<!-- 使用动态的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// 接着在父组件内
// watch $route 决定使用哪种过渡
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

在路由中可以给路由视图<router-view>用<transition>标签设置总的过渡类名

 <transition :name="transitionName" mode="out-in">
    <router-view></router-view>
</transition>

数据获取

导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。

导航完成之前获取:导航完成前,在路由的 enter 钩子中获取数据,在数据获取成功后执行导航。

从技术角度讲,两种方式都不错 —— 就看你想要的用户体验是哪种。

导航完成后获取数据

当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。

假设我们有一个 Post 组件,需要基于 $route.params.id 获取文章数据:
<template>
  <div class="post">
    <div class="loading" v-if="loading">
      Loading...
    </div>

    <div v-if="error" class="error">
      {{ error }}
    </div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>
export default {
  data () {
    return {
      loading: false,
      post: null,
      error: null
    }
  },
  created () {
    // 组件创建完后获取数据,
    // 此时 data 已经被 observed 了
    this.fetchData()
  },
  watch: {
    // 如果路由有变化,会再次执行该方法
    '$route': 'fetchData'
  },
  methods: {
    fetchData () {
      this.error = this.post = null
      this.loading = true
      // replace getPost with your data fetching util / API wrapper
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

在导航完成前获取数据

通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter 钩子中获取数据,当数据获取成功后只调用 next 方法。

export default {
  data () {
    return {
      post: null,
      error: null
    }
  },
  beforeRouteEnter (to, from, next) {
    getPost(to.params.id, (err, post) => {
      if (err) {
        // display some global error message
        next(false)
      } else {
        next(vm => {
          vm.post = post
        })
      }
    })
  },
  // 路由改变前,组件就已经渲染完了
  // 逻辑稍稍不同
  watch: {
    $route () {
      this.post = null
      getPost(this.$route.params.id, (err, post) => {
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

在为后面的视图获取数据时,用户会停留在当前的界面,因此建议在数据获取期间,显示一些进度条或者别的指示。如果数据获取失败,同样有必要展示一些全局的错误提醒。


搜狗搜到你
533 声望31 粉丝

“工欲善其事,必先利其器”。 思考、书籍和社会实践使我不断走向成熟,对知识的渴望,对理想的追求,人际关系的扩展,思维方式的变更,造就了我不断完善的专业技能和日趋成熟的思想,培养了我务实进取、认真负责的...