Przeglądaj źródła

feat: 高度渐变动画

ChenYangfan 6 lat temu
rodzic
commit
782c335097

+ 43 - 0
src/animations/ShowTransition.vue

@@ -0,0 +1,43 @@
+<template>
+  <transition name="show">
+    <slot></slot>
+  </transition>
+</template>
+
+<script>
+export default {}
+</script>
+
+<style lang="scss" scoped>
+.show-enter-active {
+  overflow: hidden;
+  animation: show .5s forwards cubic-bezier(0, 0.5, 0.5, 1);
+}
+
+.show-leave-active {
+  overflow: hidden;
+  animation: hide .5s forwards cubic-bezier(0, 0.5, 0.5, 1);
+}
+
+@keyframes show {
+  from {
+    max-height: 0;
+    opacity: 0.3;
+  }
+  to {
+    opacity: 1;
+    max-height: 200px;
+  }
+}
+
+@keyframes hide {
+  from {
+    opacity: 1;
+    max-height: 200px;
+  }
+  to {
+    max-height: 0;
+    opacity: 0.3;
+  }
+}
+</style>

+ 43 - 0
src/animations/ShowTransitionLarge.vue

@@ -0,0 +1,43 @@
+<template>
+  <transition name="show-large">
+    <slot></slot>
+  </transition>
+</template>
+
+<script>
+export default {}
+</script>
+
+<style lang="scss" scoped>
+.show-large-enter-active {
+  overflow: hidden;
+  animation: show-large .5s forwards;
+}
+
+.show-large-leave-active {
+  overflow: hidden;
+  animation: hide .5s forwards;
+}
+
+@keyframes show-large {
+  from {
+    max-height: 0;
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+    max-height: 1200px;
+  }
+}
+
+@keyframes hide-large {
+  from {
+    opacity: 1;
+    max-height: 1200px;
+  }
+  to {
+    max-height: 0;
+    opacity: 0;
+  }
+}
+</style>

+ 43 - 0
src/animations/ShowTransitionSmall.vue

@@ -0,0 +1,43 @@
+<template>
+  <transition name="show-small">
+    <slot></slot>
+  </transition>
+</template>
+
+<script>
+export default {}
+</script>
+
+<style lang="scss" scoped>
+.show-small-enter-active {
+  overflow: hidden;
+  animation: show-small 1s forwards;
+}
+
+.show-small-leave-active {
+  overflow: hidden;
+  animation: hide-small .5s forwards cubic-bezier(0, .5, .5, 1);
+}
+
+@keyframes show-small {
+  from {
+    max-height: 0;
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+    max-height: 50px;
+  }
+}
+
+@keyframes hide-small {
+  from {
+    opacity: 1;
+    max-height: 50px;
+  }
+  to {
+    max-height: 0;
+    opacity: 0;
+  }
+}
+</style>

+ 0 - 5
src/animations/SlideInDifferentTransition.vue

@@ -18,16 +18,11 @@ export default {}
 }
 
 .slide-in-difference-leave-to {
-  overflow: hidden;
   opacity: 0;
-  box-shadow: unset;
 }
 
 .slide-in-difference-enter {
-  position: absolute;
-  overflow: hidden;
   opacity: 0;
-  box-shadow: unset;
 }
 
 @media (min-width: 600px) {

+ 0 - 4
src/animations/SlideInSameTransition.vue

@@ -19,14 +19,10 @@ export default {}
 
 .slide-in-same-leave-to {
   opacity: 0;
-  box-shadow: unset;
-  backdrop-filter: unset;
 }
 
 .slide-in-same-enter {
   opacity: 0;
-  box-shadow: unset;
-  backdrop-filter: unset;
 }
 
 @media (min-width: 600px) {

+ 14 - 11
src/animations/SlideUpTransition.vue

@@ -9,21 +9,24 @@ export default {}
 </script>
 
 <style lang="scss" scoped>
-@media (min-width: 600px) {
-  .slide-up-enter-active {
-    transition: .5s cubic-bezier(0, 0.5, 0, 1);
-  }
+.slide-up-enter-active {
+  transition: .5s cubic-bezier(0, 0.5, 0, 1);
+}
 
-  .slide-up-leave-active {
-    transition: .2s cubic-bezier(0.5, 0, 1, 1);
-  }
+.slide-up-leave-active {
+  transition: .2s cubic-bezier(0.5, 0, 1, 1);
+}
 
-  .slide-up-leave-to {
-    opacity: 0;
-  }
+.slide-up-leave-to {
+  opacity: 0;
+}
+
+.slide-up-enter {
+  opacity: 0;
+}
 
+@media (min-width: 900px) {
   .slide-up-enter {
-    opacity: 0;
     transform: translateY(1.2%);
   }
 }

+ 3 - 3
src/components/Basic/BackTitle.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="title back-title">
-    <icon-button @click="handleBack()">arrow_back</icon-button>
+    <icon-button class="back-button" @click="handleBack()">arrow_back</icon-button>
     <slot></slot>
   </div>
 </template>
@@ -19,8 +19,8 @@ export default {
 </script>
 
 <style scoped>
-.icon-button {
-  left: -10px;
+.back-button {
+  left: -8px;
 }
 
 .back-title {

+ 2 - 2
src/components/Basic/CTag.vue

@@ -28,11 +28,11 @@ div {
   padding: 4px;
   border-radius: 4px;
   margin-left: 4px;
-  font-size: 14px;
+  font-size: 12px;
   line-height: 1;
   vertical-align: middle;
   position: relative;
-  bottom: 2px;
+  bottom: 1px;
 }
 
 @mixin theme($name, $color, $backgroundColor) {

+ 1 - 6
src/components/DiscussionTab/CMessage.vue

@@ -106,14 +106,9 @@ export default {
 
 .c-editing-message {
   cursor: pointer;
-  transform: translateY(60px);
   background-color: $theme-green-transparent;
 }
 
-.c-editing-message:last-child {
-  margin-bottom: 60px;
-}
-
 .left-content {
   opacity: 0;
   display: flex;
@@ -126,7 +121,7 @@ export default {
   color: #7a8a9a;
   min-width: 11ch;
   padding-right: 8px;
-  animation: show .2s .3s forwards;
+  animation: show .1s .2s forwards;
 
   .archive-button {
     opacity: .4;

+ 1 - 1
src/components/PDF/PdfController.vue

@@ -9,7 +9,7 @@
     <icon-button @click="handleScreenShot" title="将本页截图">save_alt</icon-button>
     <icon-button @click="handleNext" title="下一页">navigate_next</icon-button>
     <div class="spacer"></div>
-    <icon-button :theme="showDiscussion ? 'blue' : null" @click="handleDiscussionShowState" title="讨论区">char_bubble</icon-button>
+    <icon-button :theme="showDiscussion ? 'blue' : null" @click="handleDiscussionShowState" title="讨论区">chat_bubble</icon-button>
   </div>
 </template>
 

+ 11 - 22
src/views/shared/Discussion.vue

@@ -10,10 +10,12 @@
       </template>
     </h1>
     <discussion-tab-tool-bar :read="false" @refresh="handleRefresh"></discussion-tab-tool-bar>
-    <div v-show="editMode" class="confirm-area">
-      <c-button theme="green" @click="handleSubmit" text icon="check">确定</c-button>
-      <c-button theme="red" @click="cancel" text icon="close">取消</c-button>
-    </div>
+    <show-transition-small>
+      <div v-if="editMode" class="confirm-area">
+        <c-button theme="green" @click="handleSubmit" text icon="check">确定</c-button>
+        <c-button theme="red" @click="cancel" text icon="close">取消</c-button>
+      </div>
+    </show-transition-small>
     <template v-if="!showRead">
       <div class="no-content-warning" v-if="unreadMessage === null">
         加载中...
@@ -59,9 +61,10 @@ import DiscussionTabToolBar from '@/components/DiscussionTab/DiscussionTabToolBa
 import CMessage from '@/components/DiscussionTab/CMessage'
 import { deleteMessages, getReadMessages, getUnreadMessages, readMessages } from '@/server/message'
 import CButton from '@/components/Basic/CButton'
+import ShowTransitionSmall from '@/animations/ShowTransitionSmall'
 
 export default {
-  components: { CButton, DiscussionTabToolBar, CMessage },
+  components: { CButton, DiscussionTabToolBar, CMessage, ShowTransitionSmall },
   data () {
     return {
       unreadMessage: null,
@@ -159,8 +162,8 @@ export default {
 
 @media (min-width: 800px) {
   .tab {
-    max-width: 520px;
-    min-width: 520px;
+    max-width: 480px;
+    min-width: 480px;
     position: relative;
     box-sizing: border-box;
     min-height: 450px;
@@ -182,22 +185,8 @@ export default {
 }
 
 .confirm-area {
-  opacity: 0;
-  position: absolute;
   width: 100%;
-  margin-top: 20px;
-  box-sizing: border-box;
   display: flex;
-  justify-content: left;
-  animation: .2s .2s show forwards;
-}
-
-@keyframes show {
-  from {
-    opacity: 0;
-  }
-  to {
-    opacity: 1;
-  }
+  transform: translateY(8px);
 }
 </style>

+ 2 - 2
src/views/student/components/StudentCourseDetail.vue

@@ -61,12 +61,12 @@ export default {
   display: flex;
   align-items: center;
 
-  & .c-input {
+  .c-input {
     margin-bottom: unset;
     flex: 1;
   }
 
-  & .c-button {
+  .c-button {
     margin-left: 12px;
   }
 }

+ 28 - 4
src/views/student/components/StudentCourseSlides.vue

@@ -1,7 +1,16 @@
 <template>
   <tab-side-component>
-    <back-title>{{course.name}}</back-title>
-    <course-detail :course="course"></course-detail>
+    <back-title>
+      {{course.name}}
+      <icon-button class="expand-button" :theme="showMore ? 'blue' : 'normal'" @click="handleShowMore" :class="showMore ? 'reverse' : ''">
+        expand_more
+      </icon-button>
+    </back-title>
+    <show-transition>
+      <div v-if="showMore">
+        <course-detail :course="course"></course-detail>
+      </div>
+    </show-transition>
     <div class="sub-title">课件列表</div>
     <div class="no-content-warning" v-if="slides === null">
       <div class="no-content-warning-tip">加载中...</div>
@@ -27,12 +36,15 @@ import { SET_SLIDE_INFO } from '@/store/types/pdf-types'
 import { SET_COURSE } from '@/store/types/main-types'
 import { mapState } from 'vuex'
 import CourseDetail from '@/components/Details/CourseDetail'
+import IconButton from '@/components/Basic/IconButton'
+import ShowTransition from '@/animations/ShowTransition'
 
 export default {
-  components: { CourseDetail, CButton, SlideCard, BackTitle, TabSideComponent },
+  components: { IconButton, CourseDetail, CButton, SlideCard, BackTitle, TabSideComponent, ShowTransition },
   data () {
     return {
-      slides: null
+      slides: null,
+      showMore: false
     }
   },
   watch: {
@@ -68,6 +80,9 @@ export default {
     handleToManager () {
       this.$store.commit(SET_COURSE, { courseInfo: this.course })
       this.$router.push({ name: 'student-course-detail', params: { courseId: this.course.id } })
+    },
+    handleShowMore () {
+      this.showMore = !this.showMore
     }
   }
 }
@@ -81,4 +96,13 @@ export default {
 .no-content-warning {
   height: unset;
 }
+
+.expand-button {
+  transform: translateX(4px);
+  transition: .5s cubic-bezier(0, .5, .5, 1.3);
+}
+
+.reverse {
+  transform: translateX(4px) rotate(-180deg);
+}
 </style>

+ 1 - 0
src/views/student/tabs/StudentExplore.vue

@@ -16,6 +16,7 @@
         </div>
         <template v-for="(course, index) of courses">
           <course-card :key="course.id" :course="course" :index="index + 1" hide-bio
+                       title="点击查看课程下的所有课件信息"
                        :clickHandler="handleToCourseSlideList"></course-card>
         </template>
       </section>

+ 25 - 19
src/views/student/tabs/StudentPersonal.vue

@@ -1,23 +1,28 @@
 <template>
-  <div class="tab">
-    <h1 class="title">
-      个人信息设置
-      <c-tag theme="green">学生</c-tag>
-    </h1>
-    <div class="sub-title">修改姓名</div>
-    <c-input :placeholder="'目前资料中的姓名:' + userInfo.name" class="mb-16" v-model="newName"></c-input>
-    <c-button theme="orange" block class="mb-32" @click="handleModifyName">确认修改姓名</c-button>
-    <div class="sub-title">修改密码</div>
-    <div class="verified-code-wrapper">
-      <c-input placeholder="邮箱验证码" type="number" v-model="code"></c-input>
-      <c-button theme="blue" :no-click-warn="typeof this.emailButtonContent === typeof 0"
-                @click="handleSendEmailCode">{{ emailButtonContent }}
-      </c-button>
+  <div class="tab complex-tab">
+    <div class="left">
+      <h1 class="title">
+        个人信息设置
+        <c-tag theme="green">学生</c-tag>
+      </h1>
+      <div class="sub-title">修改姓名</div>
+      <c-input :placeholder="'目前资料中的姓名:' + userInfo.name" class="mb-16" v-model="newName"></c-input>
+      <c-button theme="orange" block class="mb-32" @click="handleModifyName">确认修改姓名</c-button>
+      <div class="sub-title">修改密码</div>
+      <div class="verified-code-wrapper">
+        <c-input placeholder="邮箱验证码" type="number" v-model="code"></c-input>
+        <c-button theme="blue" :no-click-warn="typeof this.emailButtonContent === typeof 0"
+                  @click="handleSendEmailCode">{{ emailButtonContent }}
+        </c-button>
+      </div>
+      <c-input placeholder="新密码" type="password" class="mb-16" v-model="password"></c-input>
+      <c-input placeholder="确认新密码" type="password" class="mb-16" v-model="passwordEnsure"></c-input>
+      <c-button theme="orange" block class="mb-32" @click="handleModifyPassword">确认修改密码</c-button>
+      <c-button theme="red" block @click="handleLogout">登出</c-button>
     </div>
-    <c-input placeholder="新密码" type="password" class="mb-16" v-model="password"></c-input>
-    <c-input placeholder="确认新密码" type="password" class="mb-16" v-model="passwordEnsure"></c-input>
-    <c-button theme="orange" block class="mb-32" @click="handleModifyPassword">确认修改密码</c-button>
-    <c-button theme="red" block @click="handleLogout">登出</c-button>
+    <slide-in-different-transition>
+      <router-view/>
+    </slide-in-different-transition>
   </div>
 </template>
 
@@ -28,9 +33,10 @@ import { sendEmailCode } from '@/server/code'
 import { logout, modifyUser, resetPasswordByEmail } from '@/server/user'
 import { mapState } from 'vuex'
 import CTag from '@/components/Basic/CTag'
+import SlideInDifferentTransition from '@/animations/SlideInDifferentTransition'
 
 export default {
-  components: { CTag, CInput, CButton },
+  components: { CTag, CInput, CButton, SlideInDifferentTransition },
   data () {
     return {
       emailButtonContent: '发送验证码',

+ 25 - 19
src/views/teacher/tabs/TeacherPersonal.vue

@@ -1,24 +1,29 @@
 <template>
   <div class="tab">
-    <h1 class="title">
-      个人信息设置
-      <c-tag theme="blue">教师</c-tag>
-    </h1>
-    <c-button block theme="blue" class="mb-24" @click="handleToQuestions">题库设置</c-button>
-    <div class="sub-title">修改姓名</div>
-    <c-input :placeholder="'目前资料中的姓名:' + userInfo.name" class="mb-16" v-model="newName"></c-input>
-    <c-button theme="orange" block class="mb-32" @click="handleModifyName">确认修改姓名</c-button>
-    <div class="sub-title">修改密码</div>
-    <div class="verified-code-wrapper">
-      <c-input placeholder="邮箱验证码" type="number" v-model="this.code"></c-input>
-      <c-button theme="blue" :no-click-warn="typeof this.emailButtonContent === typeof 0"
-                @click="handleSendEmailCode">{{ emailButtonContent }}
-      </c-button>
+    <div class="left">
+      <h1 class="title">
+        个人信息设置
+        <c-tag theme="blue">教师</c-tag>
+      </h1>
+      <c-button block theme="blue" class="mb-24" @click="handleToQuestions">题库设置</c-button>
+      <div class="sub-title">修改姓名</div>
+      <c-input :placeholder="'目前资料中的姓名:' + userInfo.name" class="mb-16" v-model="newName"></c-input>
+      <c-button theme="orange" block class="mb-32" @click="handleModifyName">确认修改姓名</c-button>
+      <div class="sub-title">修改密码</div>
+      <div class="verified-code-wrapper">
+        <c-input placeholder="邮箱验证码" type="number" v-model="this.code"></c-input>
+        <c-button theme="blue" :no-click-warn="typeof this.emailButtonContent === typeof 0"
+                  @click="handleSendEmailCode">{{ emailButtonContent }}
+        </c-button>
+      </div>
+      <c-input placeholder="新密码" type="password" class="mb-16" v-model="password"></c-input>
+      <c-input placeholder="确认新密码" type="password" class="mb-16" v-model="passwordEnsure"></c-input>
+      <c-button block theme="orange" class="mb-32" @click="handleModifyPassword">确认修改密码</c-button>
+      <c-button block theme="red" @click="handleLogout">登出</c-button>
     </div>
-    <c-input placeholder="新密码" type="password" class="mb-16" v-model="password"></c-input>
-    <c-input placeholder="确认新密码" type="password" class="mb-16" v-model="passwordEnsure"></c-input>
-    <c-button block theme="orange" class="mb-32" @click="handleModifyPassword">确认修改密码</c-button>
-    <c-button block theme="red" @click="handleLogout">登出</c-button>
+    <slide-in-different-transition>
+      <router-view/>
+    </slide-in-different-transition>
   </div>
 </template>
 
@@ -29,9 +34,10 @@ import { sendEmailCode } from '@/server/code'
 import { logout, modifyUser, resetPasswordByEmail } from '@/server/user'
 import { mapState } from 'vuex'
 import CTag from '@/components/Basic/CTag'
+import SlideInDifferentTransition from '@/animations/SlideInDifferentTransition'
 
 export default {
-  components: { CTag, CInput, CButton },
+  components: { CTag, CInput, CButton, SlideInDifferentTransition },
   data () {
     return {
       emailButtonContent: '发送验证码',