H5之动效

8 篇文章 0 订阅

点名动效

知识点Attr()
attr() 函数返回选择元素的属性值。

  • CSS函数attr()是用来获取被选中元素的属性值,并且在样式文件中使用。它也可以用在伪类元素里,在伪类元素里使用,它得到的是伪元素的原始元素的值。
  • attr()函数可以和任何CSS属性一起使用,但是除了content外,其余都还是试验性的(简单说就是不稳定,浏览器不一定支持)
    代码
  <a href="#" class="btn" data-tip="点击作答">一个按钮</a>

 .btn::before {
  content: attr(data-tip);
  width: 80px;
  padding: 5px 10px;
  border-radius: 4px;
  background-color: #000;
  color: #ccc;
  position: absolute;
  top: -30px;
  left: 50%;
  transform: translate(-50%);
  text-align: center;
  opacity: 0;
  transition: all .3s;
}
<!--
 * @Author: yangyuguang
 * @Date: 2022-10-09 15:11:29
 * @LastEditors: yangyuguang
 * @LastEditTime: 2022-10-09 21:00:37
 * @FilePath: /my_test/src/components/www.vue
-->
<template>
  <div class="list"></div>
</template>

<script>
export default {
  data () {
    return {
      list: '',
      randomSurnam: [
        '赵',
        '钱',
        '孙',
        '李',
        '周',
        '吴',
        '郑',
        '王',
        '冯',
        '陈',
        '褚',
        '卫',
        '蒋',
        '沈',
        '韩',
        '杨'
      ],
      randomName: [
        '泽',
        '桐',
        '梓',
        '一',
        '宁',
        '梅',
        '生',
        '平',
        '明',
        '涵',
        '韵',
        '宸',
        '坤',
        '华',
        '星',
        '家'
      ],
      names: [],
      run: true,
      deg: 0,
      slow: 0
    }
  },
  methods: {
    init () {
      for (let i = 0; i < 40; i++) {
        this.names.push(
          this.randomSurnam[(Math.random() * this.randomSurnam) | 0] +
            this.randomName[Math.random() * this.randomName.length|0] +
            this.randomName[Math.random() * this.randomName.length|0]
        )
      }

      for (let key in this.names) {
        let span = document.createElement('span')
        span.innerText = this.names[key]
        this.list.appendChild(span)
      }
      this.animate()
      this.event()
      
    },
    event () {
      document.addEventListener('keyup', (e) => {
        console.log('====================================');
        console.log(e);
        console.log('====================================');
        if (e.code == 'Space') {
          this.run = !this.run
        }
      })
    },
    draw () {
      const spans = this.list.children
      for (let i = 0; i < spans.length; i++) {
        let span = spans[i]
        span.style.transform = `rotate(${i / this.names.length * 360 +
          this.deg}deg)`;
        span.style.color = '#fff'
      }
      const now =((360 - this.deg) / 360 * this.names.length| 0) % this.names.length
      this.list.setAttribute('data', this.names[now])
      spans[now].style.color = 'red'
      if (this.run) {
        this.slow = 1
      } else {
        this.slow = this.slow * 0.995
      }
      this.deg -= this.slow
    },
    animate(){
        setInterval(()=>this.draw(),10)
    }
  },
  mounted () {
    this.list = document.querySelector('.list')
    this.init()
  }
}
</script>

<style scoped>
.list {
  width: 400px;
  height: 400px;
  border-radius: 50%;
  border: 1px solid #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.list::after {
  content: '';
  display: absolute;
  width: 0;
  height: 0;
  right: 0;
  border-width: 6px;
  border-style: solid;
  border-color: transparent transparent transparent red;
}
.list::before {
  content: attr(data);
  position: absolute;
  color: #1e90ff;
  font-size: 64px;
}
.list span {
  color: #fff;
  position: absolute;
  width: calc(100% + 120px);
  height: 20px;
  text-align: right;
  transition: 0.01 linear;
  user-select: none;
}
</style>

效二

知识点

  • 下面代码中大量使用 在js中的使用setProperty设置变量 在css中利用var使用
  • perspective 属性指定了观察者与z=0平面的距离,使具有三维位置变换的元素产生透视效果
  • 把需要切换的颜色都提出来用css变量代替,并添加上过渡效果 在不同主题类名里修改css变量
  • transitions 可以决定哪些属性发生动画效果 (明确地列出这些属性),何时开始 (设置 delay),持续多久 (设置 duration) 以及如何动画 (定义timing funtion,比如匀速地或先快后慢)。
  • padding:inherit; //内边距继承父元素

代码


<template>
  <div id="btnWrapper" ref="btnWrapper">
    <div class="btn active">按钮1</div>
    <div class="btn">按钮2</div>
  </div>
</template>

<script>


export default {
  mounted () {
    let that = this
    let wrapper = this.$refs.btnWrapper
    // 先给容器设置一个css变量并附初始值
    wrapper.style.setProperty('--groove-left', '12px')
    // 获取按钮元素
    let btns = wrapper.children
    for (let i = 0; i < btns.length; i++) {
      // 给每个按钮添加点击事件
      btns[i].addEventListener('click', function (e) {
        // 点击后,修改css变量的值
        wrapper.style.setProperty('--groove-left', `calc(12px + ${i * 50}%)`)
        wrapper.style.setProperty('--wrapper-rotate', `${i===0?-8:8}deg`)
        wrapper.style.setProperty('--wraper-origin', `${i===0? '80% top':'20% top'}`)
        wrapper.className = "rotateWrap"
        setTimeout(()=>{
          wrapper.className = ""
        },500)
        that.themeChange(i==1)
        // 初始化所有按钮
        that.resetBtn(btns)
        setTimeout(()=>{
          btns[i].className = "btn active"
        },500)
      })
    }
  },
  methods: {
    resetBtn(btns) {
      for(let i=0;i<btns.length;i++){
        setTimeout(()=>{
          btns[i].className = "btn"
        },100)
      }
    },
    themeChange(bol){
      let body = document.body
      body.className = bol?'dark':""
    }
  },
}

</script>

<style scoped>
#btnWrapper {
  position: relative;
  margin:300px auto 0;
  width: 380px;
  height: 80px;
  padding: 12px 16px;
  border-radius: 12px;
  overflow: hidden;
  background-color: var(--c-wrap-bg);;
  box-shadow: -10px -10px 15px var(--c-wrap-shadow1), 10px 10px 15px var(--c-wrap-shadow2);
  /* transform-origin:center; */
  transform-origin:var(--wraper-origin);
  /* 添加过渡效果 */
  transition: transform 0.4s cubic-bezier(0,0,0.48,1);
}
.rotateWrap{
  /* 添加y轴旋转 */
  transform: rotateY(var(--wrapper-rotate));
}
.btn {
  float: left;
  display: flex;
  width: 50%;
  height: 100%;
  align-items: center;
  justify-content: center;
  padding: inherit;
  color: #aaa;
  cursor: pointer;

  /* 添加文字颜色过度效果 */
  transition: color 0.4s linear;
  
  /* 添加按钮未选中动画  注意时间 */
  animation: txtOutScale 0.6s linear;
}
.active {
  color: #111;
  /* 添加文字颜色过度效果*/
  transform: scale(1.1);
  /* 添加按钮未选中动画  注意时间 */
  animation:txtEnterScale 0.4s linear;
}
#btnWrapper::before {
  content: '';
  position: absolute;
  left: var(--groove-left);
  top: 12px;
  width: calc(50% - 16px - 10px);
  height: calc(100% - 24px);
  border-radius: 12px;
  box-shadow: inset 8px 8px 6px var(--c-btn-shadow1), inset -5px -5px 15px var(--c-btn-shadow2),
    inset -5px -5px 15px var(--c-btn-shadow2), inset 7px 7px 6px var(--c-btn-shadow1);
  transition: left 1s cubic-bezier(0.82, 0.12, 0.18, 0.88),box-shadow 0.4s linear;
}
/* 按钮选中缩放动画 */
@keyframes txtEnterScale {
  0%{
    transform: scale(1);
  }
   80%{
    transform: scale(1.15);
  }
   100%{
    transform: scale(1.1);
  }
}
/* 按钮未选中缩放动画 */
@keyframes textOutScale {
  0%{
    transform: scale(1.1);
  }
  80%{
    transform: scale(0.95);
  }
  100%{
    transform: scale(1);
  }
}
</style>

html中设置

 *{
      margin:0;
      padding:0;
      box-sizing: border-box;
    }
    body{
      perspective: 500px;
      background-color: #edf1f4;
      transition: background-color 0.4s linear;
      --c-wrap-shadow1: #f5f9fd;
    --c-wrap-shadow2: #d8dbe5;
    --c-wrap-bg: #e2e6eb;
    --c-btn-shadow1: #d9dbe6;
    --c-btn-shadow2: #f5f9fd;
    --c-txt1: #aaa;
    --c-txt2: #111;
    }
    .dark{
      background-color: #333;
      --c-wrap-shadow1: #292929;
    --c-wrap-shadow2: #202020;
    --c-wrap-bg: #505050;
    --c-btn-shadow1: #323232;
    --c-btn-shadow2: #444;
    --c-txt1: #888;
    --c-txt2: #fff;
    }

纯代码版本

<div id="btnWrapper">
    <div class="btn active">开灯</div>
    <div class="btn">关灯</div>
</div>



let wrapper = document.getElementById('btnWrapper');
wrapper.style.setProperty('--groove-left', '12px');
let btns = document.getElementsByClassName('btn');
for (let i = 0; i < btns.length; i++) {
    btns[i].addEventListener('click', function (e) {
        ThemeChange(i === 1);
        resetBtn(btns);
        wrapper.style.setProperty('--groove-left', `calc(12px + ${i * 50}%)`);
        wrapper.style.setProperty('--wraper-origin', `${i === 0 ? '75% top' : '25% top'}`);
        wrapper.style.setProperty('--wraper-rotate', `${i === 0 ? -8 : 8}deg`);
        wrapper.className = 'rotateWrap';
        setTimeout(() => {
            btns[i].className = 'btn active';
        }, 500);
        setTimeout(() => {
            wrapper.className = ''
        }, 550);
    })
}
// 重置按钮类名
function resetBtn(btns) {
    for (let i = 0; i < btns.length; i++) {
        setTimeout(() => {
            btns[i].className = 'btn';
        }, 100)
    }
}
// 改变主题
function ThemeChange(bol) {
    let body = document.body;
    body.className = bol ? 'dark' : ''
}






*{
  margin:0;
  padding:0;
  box-sizing:border-box;
}
body {
    background-color: #edf1f4;
    perspective: 500px;
    --c-wrap-shadow1: #f5f9fd;
    --c-wrap-shadow2: #d8dbe5;
    --c-wrap-bg: #e2e6eb;
    --c-btn-shadow1: #d9dbe6;
    --c-btn-shadow2: #f5f9fd;
    --c-txt1: #aaa;
    --c-txt2: #111;
    transition: background-color 0.4s linear;
}
.dark {
    background-color: #333;
    --c-wrap-shadow1: #292929;
    --c-wrap-shadow2: #202020;
    --c-wrap-bg: #505050;
    --c-btn-shadow1: #323232;
    --c-btn-shadow2: #444;
    --c-txt1: #888;
    --c-txt2: #fff;
}
#btnWrapper {
    position: relative;
    width: 380px;
    height: 80px;
    padding: 12px 16px;
    margin: 300px auto 0;
    border-radius: 12px;
    overflow: hidden;
    background-color: var(--c-wrap-bg);
    box-shadow: -10px -10px 15px var(--c-wrap-shadow1), 10px 10px 15px var(--c-wrap-shadow2);
    transform-origin: var(--wraper-origin);
    transition: transform 0.4s cubic-bezier(0, 0, 0.48, 1), box-shadow 0.4s linear, background-color 0.4s linear;
}
.rotateWrap {
    transform: rotateY(var(--wraper-rotate));
}
#btnWrapper::before {
    content: "";
    position: absolute;
    left: var(--groove-left);
    top: 12px;
    width: calc(50% - 16px - 8px);
    height: calc(100% - 24px);
    border-radius: 12px;
    box-shadow: inset 8px 8px 6px var(--c-btn-shadow1), inset -5px -5px 15px var(--c-btn-shadow2), inset -5px -5px 15px var(--c-btn-shadow2), inset 7px 7px 6px var(--c-btn-shadow1);
    transition: left 1s cubic-bezier(0.82, 0.12, 0.18, 0.88), box-shadow 0.4s linear;
}
.btn {
    float: left;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 50%;
    height: 100%;
    padding: inherit;
    color: var(--c-txt1);
    transition: color 0.4s linear;
    animation: txtOutScale 0.6s linear;
    cursor: pointer;
}
.active {
    color: var(--c-txt2);
    transform: scale(1.1);
    animation: txtEnterScale 0.4s linear;
}
@keyframes txtEnterScale {
    0% {
        transform: scale(1);
    }

    80% {
        transform: scale(1.15);
    }

    100% {
        transform: scale(1.1);
    }
}
@keyframes txtOutScale {
    0% {
        transform: scale(1.1);
    }

    80% {
        transform: scale(0.95);
    }

    100% {
        transform: scale(1);
    }
}

getBoundingClientRect用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性

兔子动效

<!--
 * @Author: yangyuguang
 * @Date: 2022-12-29 16:46:51
 * @LastEditors: yangyuguang
 * @LastEditTime: 2023-01-09 16:49:53
 * @FilePath: /my_test/src/components/text.vue
-->
<template>
  <div class="container">
    <div class="loading">
      <div class="rabbit"></div>
      <div class="clouds"></div>
      <div class="text">Loading...</div>
    </div>
  </div>
</template>

<script>
export default {
  methods: {},
  mounted () {}
}
</script>

<style scoped>
.container {
  display: grid;
  height: 100vh;
  place-content: center;
}
.loading {
  width: 320px;
  height: 180px;
  background: #e2b29f;
  border-radius: 10px;
  display: grid;
  place-content: center;
  position: relative;
}
.rabbit {
  width: 5em;
  height: 3em;
  background-color: #fff;
  border-radius: 70% 90% 60% 50%;
  position: relative;
  /* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
  box-shadow: -0.2em 1em 0 -0.75em #b78e81;
  transform: translate(-2em, 0);
  animation: hop 1s infinite linear;
  z-index: 1;
}
/* 利用宽高画兔子的尾巴 利用box-shadow画兔子的眼睛和腿 */
.rabbit:before {
  content: '';
  position: absolute;
  width: 1em;
  height: 1em;
  background: white;
  border-radius: 100%;
  top: 0.5em;
  left: -0.3em;
  box-shadow: 4em 0.4em 0 -0.35em #3f3334, 0.5em 1em 0 white,
    4em 1em 0 -0.3em white, 4em 1em 0 -0.3em white, 4em 1em 0 -0.4em white;
  animation: kick 1s infinite linear;
}
/* 利用矩形和box-shdow画兔子的一只耳朵和另一只耳朵 */
.rabbit:after {
  content: '';
  position: absolute;
  width: 0.75em;
  height: 2em;
  background: #fff;
  border-radius: 50% 100% 0 0;
  transform: rotate(-30deg);
  right: 1em;
  top: -1em;
  border-top: 1px solid #f7f5f4;
  border-left: 1px solid #f7f5f4;
  box-shadow: -0.5em 0 0 -0.1em white;
}
/* 宽高创建第一个拱形 box-shadow另外新加两个 */
.clouds {
  background: white;
  width: 2em;
  height: 2em;
  border-radius: 100% 100% 0 0;
  position: relative;
  top: -4em;
  opacity: 0;
  transform: translate(0, 0);
  animation: cloudy 1s infinite linear forwards;
  box-shadow: 5em 2em 0 -0.3em white, -2em 2em 0 0 white;
}
.clouds:before,
.clouds:after {
  content: '';
  position: absolute;
  box-shadow: 5em 2em 0 -0.3em white, -2em 2em 0 white;
}
.clouds:before {
  width: 1.25em;
  height: 1.25em;
  border-radius: 100% 100% 0 100%;
  background: #fff;
  left: -30%;
  bottom: 0;
}
.clouds:after {
  width: 1.25em;
  height: 1.25em;
  border-radius: 100% 100% 100% 0;
  background: #fff;
  left: 65%;
  bottom: 0;
}
.text {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.5em;
  display: grid;
  place-content: center;
  color: white;
  font-size: 2em;
  /* 定义无小写字母,仅有大写字母 */
  text-transform: uppercase; 
  letter-spacing: 0.2em; 
  font-family: fantasy;
}
@keyframes cloudy {
  40% {
    opacity: 0.75;
    transform: translate(-3em, 0);
  }
  50% {
    opacity: 0;
    transform: translate(-4em, 0);
  }
  90% {
    transform: translate(0, 0);
  }
}
@keyframes hop {
  20% {
    transform: rotate(-10deg) translate(1em, -2em);
    box-shadow: -2em 3em 0 -1em #b78e81;
  }
  40% {
    transform: rotate(10deg) translate(3em, -4em);
    box-shadow: -2em 3.25em 0 -1.1em #b78e81;
  }
  60%,
  75% {
    transform: rotate(0) translate(4em, 0);
    box-shadow: -0.2em 1em 0 -0.75em #b78e81;
  }
}
@keyframes kick {
  20%,
  50% {
    box-shadow: 4em 0.4em 0 -0.35em #3f3334, 0.5em 1.5em 0 white,
      4em 1.75em 0 -0.3em white, 4em 1.75em 0 -0.3em white,
      4em 1.9em 0 -0.4em white;
  }
  40% {
    box-shadow: 4em 0.4em 0 -0.35em #3f3334, 0.5em 2em 0 white,
      4em 1.75em 0 -0.3em white, 4.2em 1.75em 0 -0.2em white,
      4.4em 1.9em 0 -0.2em white;
  }
}
</style>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值