Vue3仿卖座电影开发纪实(四):用户交互

402 阅读2分钟

@页面跳转

定义详情页路由

router/index.js

  /* 动态路由 id为动态路由参数 组件实例中this.$route.params.id */
  {
     path: "/film/:id(\\d{4})",
     name: "detail",
     meta: { hideTabBar: true },
     component: Detail,
  },

点击电影条目跳转详情页

  <ul v-else>
     <!-- 点击跳转详情页,携带动态参数影片id -->
     <FilmItem
        v-for="film in films"
        :key="film.filmId"
        :item="film"
        @click="$router.push(`/film/${film.filmId}`)">
     </FilmItem>
  </ul>

从详情页返回

 <!-- 详情页导航条 -->
 <div class="film-header show-film-header">
    <!-- 点击返回 -->
    <div
       class="goBack"
       @click="$router.back()">
       <img
          src="data:image/png;base64,iVBOR..."
          alt="" />
    </div>

    <div
       class="title"
       ref="refTitle">
       {{ film.name }}
    </div>
 </div>

@详情页导航条的动态透明

给标题元素添加ref

 <!-- 详情页导航条 -->
 <div class="film-header show-film-header">
    <!-- 点击返回 -->
    <div
       class="goBack"
       @click="$router.back()">
       <img
          src="data:image/png;base64,iVBOR..."
          alt="" />
    </div>

    <!-- 给导航条中的标题元素添加ref,以便后续捕获这个元素 -->
    <div
       class="title"
       ref="refTitle">
       {{ film.name }}
    </div>
 </div>

在详情渲染完毕时逮到标题栏元素

   /* 组件挂载时获取数据 */
   mounted() {

      /* 获取详情并渲染完毕后,逮到标题栏元素 */
      getDetail(this.$route.params.id).then(res => {
         console.log("res=", res);

         // 渲染页面(数据驱动视图)
         this.film = res;

         /*
         film对应的div元素在渲染完毕后会回调nextTick内的函数
         此时根据ref获取title元素
         */
         this.$nextTick(() => {
            this.titleDom = this.$refs.refTitle;
         });
      });

      /* 组件挂载完毕以后监听窗口的滚动事件 */
      ...
   },

根据页面滚动距离调整标题栏样式

   /* 组件挂载时获取数据 */
   mounted() {
      /* 获取详情并渲染完毕后,逮到标题栏元素 */
      ...

      /* 组件挂载完毕以后监听窗口的滚动事件 */
      const mainDom = document.querySelector("main");
      mainDom.onscroll = e => {
         // 如果标题栏尚未渲染完毕 就什么都不做
         if (!this.titleDom) return;

         // 实时main元素滚动的距离
         console.log("scroll", mainDom.scrollTop);

         /* 如果滚动距离超过50就白底黑字,否则透明 */
         if (mainDom.scrollTop > 50) {
            this.titleDom.style.backgroundColor = "white";
            this.titleDom.style.color = "black";
         } else {
            this.titleDom.style.backgroundColor = "transparent";
            this.titleDom.style.color = "transparent";
         }
      };
   },

CSS动画的配合

.title {
   padding: 0;
   background-color: transparent;
   color: transparent;

   // 当样式发生改变时使用动画
   transition: all 0.5s linear;
}

@详情页摘要的展开与折叠

点击toggle按钮触发展开/折叠

<!-- 点击toggle按钮时 动态切换hideSynopsis的真假 -->
<div
   class="toggle"
   @click="hideSynopsis = !hideSynopsis">

   <!-- 隐藏时使用↓图标 -->
   <i
      v-if="hideSynopsis"
      class="fa fa-angle-down"
      style="font-size: 20px"></i>

   <!-- 展开时使用↑图标 -->
   <i
      v-else
      class="fa fa-angle-up"
      style="font-size: 20px"></i>
</div>

摘要元素的高度随折展动态变化

<!-- 影片摘要 -->
<!-- 
// 我们让摘要元素的高度随着hideSynopsis的真假与与否动态变化
// 当hideSynopsis为true时 高度为60px 此时为折叠态
// 当hideSynopsis为false时 高度为动态计算的充分展开高度 此时为展开态
:style="{
   height: hideSynopsis ? '60px' : `${Math.ceil(film.synopsis.length / 28) * 18}px`,
}"
 -->
<div
   id="synopsis"
   class="film-synopsis grey-text"
   :style="{
      height: hideSynopsis ? '60px' : `${Math.ceil(film.synopsis.length / 28) * 18}px`,
   }"
>
   {{ film.synopsis }}
</div>

CSS动画的配合

// 摘要样式
#synopsis {
   // 为高度做动画
   transition: height 0.5s linear;

   // 高度以外的文字隐藏
   overflow: hidden;
}

@全局组件切换动画

为根组件的RouterView添加切换动画

<!-- 路由对应的目标组件的承载容器 -->
<main>
  <!-- 无动画 -->
  <!-- <RouterView /> -->

  <!-- 添加组件的切换动画 -->
  <router-view v-slot="{ Component }">
     <!-- 动画过渡模式 先切走 再切入 -->
     <transition name="fade" mode="out-in">
        <component :is="Component" />
     </transition>
  </router-view>
</main>

定义这个切换动画slide-fade

/* 定义组件切换动画 */
/* 组件入场动画 + 组件离场动画 */
.slide-fade-enter-active,
.slide-fade-leave-active {
   transition: all 0.5s ease;
}

/* 组件进入之前 + 组件离去以后的状态 */
.slide-fade-enter-from,
.slide-fade-leave-to {
   opacity: 0;
   transform: translateY(20px);
}

注意事项

  • 参与切换的组件必须有唯一的根元素,否则会报警报;
  • 这个根元素最好是稳定的、不会反复diff和重新渲染的纯容器元素;

😈 点赞收藏加关注了吗就走?!

image.png

本项目源码 watch,follow,fork!!!

祝大家撸码愉快~