1. 什么是transition属性,为什么需要用到他

一个标签的属性变化难免过于生硬,我们想通过放缓这个过程来达到美化的效果,
幸运的是,CSS为我们提供了transition(过渡)属性,只需简单的提供需要变化的属性和动画时间即可

2. Playground

菜鸟教程在线编辑器

3. 个人的一些理解

为状态 A 变换到状态 B 提供过渡时,只需在原来的状态 A 上添加transition属性,
就能得到过渡的效果,当状态恢复时,transition已经默认提供了恢复时的过渡状态,不需要在 B 上再写transition

4. 使用transition构造组件

4.1 switcher

Introduction

ElementUI

设计需求

  1. 状态A 开关未开启

    • 白色小球在左侧
    • 槽为灰色
  2. 状态B 开关开启后

    • 白色小球在右侧
    • 槽为蓝色
    • 小球的移动要动画实现
  3. 再次点击开关,恢复到状态A

说明

  1. 开关组件中白色的小球的移动可以用transform: translateX(move)实现
  2. transform 属性不会改变布局
  3. 状态的改变可以通过绑定类来实现,改变类可以通过点击时间来实现
  4. svg的图标是我从iconfot.cn下的

基本骨架

<template>
  <div class="switcher" @click="toggle" :class="{'active': active}">
    <div class="switcher-slot">
      <div class="button">
        <svg t="1607441891809" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14524" width="200" height="200"><path d="M511.082 36.049c-263.069 0-476.33 212.903-476.33 475.534s213.261 475.534 476.33 475.534c263.073 0 476.33-212.903 476.33-475.534 0-262.63-213.255-475.534-476.33-475.534zM772.988 397.6l-306.63 313.276c-14.106 14.413-36.99 14.413-51.094 0l-166.087-169.696c-14.115-14.414-14.115-37.788 0-52.206 14.105-14.419 36.99-14.419 51.094 0l140.541 143.585 281.072-287.169c14.115-14.418 37.001-14.418 51.105 0 14.115 14.417 14.115 37.792 0 52.21z" p-id="14525"></path></svg>
      </div>
    </div>
  </div>

</template>

样式 <style scoped>

整体样式

div.switcher:hover {
  cursor: pointer;
}

div.switcher-slot {
  width: 210px;
  border-radius: 35px;

  display: flex;
  background-color: rgba(0, 0, 0, 0.1);
}

按钮样式

svg.icon {
  fill: white;
  width: 70px;
  height: 70px;
}

div.button {
  display: flex;
  align-items: center;

  border-radius: 35px;
}

点击过后

div.switcher .button {
  transition: transform 0.5s;
}

div.switcher.active .button {
  transform: translateX(140px); 
}

div.switcher div.switcher-slot {
  transition: background-color 0.3s;
  background-color: rgba(0, 0, 0, 0.1);
}

div.switcher.active div.switcher-slot {
  background-color: #1b9aee;
}

动作设计 <srcipt>

export default {
  props: {
    active: {
      type: Boolean,
      default: false,
    },
  },
  
  methods: {
    toggle() {
      this.$emit('toggle')
    },
  }p
}

在父组件Home.vue

<template>
  <switcher
    :active="active"
    @toggle="handler"> </switcher>
</template>

<script>
import switcher from '@/components/switcher'
export default {
  components: {
    switcher,
  },
  
  data() {
    return {
      active: false,
    }
  },
  
  methods: {
    handler() {
      this.active = !this.active
    }
  },
}
</script>

DEMO

image

4.2 drawer

Introduction

ElementUI
这里我稍稍简化了一点(其实是很多,都魔改了),我打算把内容放在屏幕中间

设计需求

  1. 组件分为两部分,遮罩层和内容层。其实这整个组件就是一个遮罩层,当然你也可以另外再弄一个
  2. 遮罩层需要独立与文档流布局
  3. 点击除内容之外的空白,退出抽屉组件
  4. 显示抽屉时内容层需要从下往上慢慢划出,遮罩层不需要管
  5. 为内容层添加一层阴影

说明

  1. 当实现为整个组件设置transform: translateY(100%)时,组件布局在页面的下方,不可见
  2. 遮罩层是无色的,就像隔了一层玻璃一样,避免点到下面的组件
  3. 遮罩层默认覆盖整个界面
  4. 为内容层添加阴影是怕看不见这一层
  5. 可以通过点击时产生的$event来判断点到的元素,具体的话把这个$event打印出来自己看看就好了
  6. 可以将内容层的position定位属性设置为relative,这样可供子组件使用absoulte定位时参照

基本框架

<template>
  <div class="modal"
       @click.stop="clickBlank"
       :class="{'active': active}">
    <div class="modal-main"
        :style="styleOf(width, height, bcolor)">
    </div>
  </div>
</template>

样式 <style scoped>

整体框架

div.modal {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  
  z-index: 100;
}

div.modal-main {
  box-shadow: 0 0 1000px black;
}

结构布局

div.modal {
  display: flex;
  align-items: center;
  justify-content: center;
}

div.modal-main {
  position: relative;
}

设置过渡

div.modal {
  transform: translateY(100%);
  transition: transform 0.5s;
}

div.modal.active {
  transform: translateY(0);
}

动作设计

export default {
  props: {
    active: {
      type: Boolean,
      default: false,
    },

    bcolor: {
      type: String,
      default: 'white',
    },
  
    width: {
      type: String,
      default: "50%",
    },

    height: {
      type: String,
      default: "60%",
    },
  },

  methods: {
    styleOf(width, height, bcolor) {
      return {
          'width': width,
          'height': height,
          'background-color': bcolor
      }
    },
    
    clickBlank(event) {
      if(event.target.className == 'modal active') {
          this.$emit('hide-modal')
      }

    },
  },

}

在父组件Home.vue

<template>
  <div class="home">
    <button @click="handler"> click me </button>
    <modal
      :active="active"
      @hide-modal="handler">
      
    </modal>
  </div>
</template>

<script>
// @ is an alias to /src
import modal from '@/components/modal'
export default {
  name: 'Home',
  components: {
    modal,
  },

  data() {
    return {
      active: false,
    }
  },

  methods: {
    handler() {
      this.active = !this.active
    },
  },
}
</script>

DEMO

image


nesteiner
1 声望0 粉丝

油腻的大学生