【VUE3】uni-app集成animation.css,按钮触发公共方法,无需绑定样式变量

animation是个好东西,实现了一些常用的方法。最近集成到uni-app中,发现网上的通常都是使用绑定变量的方式来实现。少了通过指定ref触发的模式,总感觉有那么别扭。撸了一上午代码,把这个功能实现了出来。

集成animation.css

集成animation.css没啥好说的,在网上下载4.1.1版的animate.min.css。然后修改头部,添加小程序的兼容补丁代码:

page {

--animate-duration: 1s;

--animate-delay: 1s;

--animate-repeat: 1;

}

然后放到statics/css/animate.min.css

引入animation.css

在系统的全局文件导入即可,我使用uni-best的模板,导入的位置就是style/index.scss

css 复制代码
// 增补字体库
@import '@/static/css/fonts.css';

// 增补动画库
@import '@/static/css/animate.min.css';

.test {
  // 可以通过 @apply 多个样式封装整体样式
  @apply mt-4 ml-4;

  padding-top: 4px;
  color: red;
}
/** 增补快速样式 **/
.x-items-left {
  // 水平排列
  @apply flex flex-row;
}

.x-items-center {
  // 水平排列,垂直居中
  @apply flex flex-row items-center;
}

.x-items-stretch {
  // 水平排列,垂直拉伸
  @apply flex flex-row items-stretch;
}

.x-items-between {
  // 水平排列,垂直居中,分散对齐
  @apply flex flex-row items-center justify-between;
}

.y-items-center {
  // 垂直排列,水平居中
  @apply flex flex-col items-center;
}

.y-items-stretch {
  // 垂直排列,水平拉伸
  @apply flex flex-col items-stretch;
}

.flex-center {
  // 完全居中,使用flex定位
  @apply flex justify-center items-center;
}

.absolute-center {
  // 完全居中,使用 absolute定位
  @apply absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2;
}

编写执行方法

这里有个神坑,就是app(Android)下addEventListener后,removeEventListener相当不好使。移除一次后再添加就监测不到了,索性添加一个对象cache,手动判断保证只添加一次

下面代码也是在unibest环境下的

TypeScript 复制代码
const ANIMATE_CSS_PERFIX = 'animate__'
const ANIMATE_CSS_CLASS = ANIMATE_CSS_PERFIX + 'animated'
const switchAnimateClass: (className: string, animationTypes?: string[]) => string = (
  className,
  animationTypes
) => {
  const classNames: string[] = className.split(/\s+/)
  if (!classNames.includes(ANIMATE_CSS_CLASS)) {
    // 没有指定动画,不处理
    return className
  }
  const filtered = classNames.filter(
    (item) => !(item.startsWith(ANIMATE_CSS_PERFIX) && item !== ANIMATE_CSS_CLASS)
  )
  if (animationTypes) {
    animationTypes.forEach((item) => filtered.push(ANIMATE_CSS_PERFIX + item))
  }
  return filtered.join(' ')
}

const instanceCache = new Set<any>()

/**
 * animatecss集成动画效果执行一次,如果循环执行直接设置样式即可
 * @param ref vue的对象ref
 * @param animationType 动画类型以及时间配置等,例如animate__headShake只需要输入headShake
 * @param callback 动画执行结束后的回调,可以实现连续动画(APP不支持)
 */
export function animatecss(ref: Ref, animationType: string | string[], callback?: () => void) {
  if (ref && ref.value) {
    if (process.env.UNI_PLATFORM === 'app') {
      const instance = ref.value
      // 如果提供了回调函数,则监听动画结束事件
      const animationTypes: string[] = [].concat(animationType)
      instance.className = switchAnimateClass(instance.className, animationTypes)
      const onAnimationEnd = () => {
        try {
          if (callback) {
            callback()
          }
        } finally {
          // 移除事件监听器,避免多次绑定
          const afterClass: string[] = instance.className.split(' ')
          nextTick(() => {
            instance.className = switchAnimateClass(instance.className)
          })
        }
      }
      if (!instanceCache.has(instance)) {
        instance.addEventListener('animationend', onAnimationEnd)
        instanceCache.add(instance)
      }
    } else {
      const instance = ref.value.$el
      const classList: DOMTokenList = instance.classList
      const animationTypes = [].concat(animationType).map((item) => ANIMATE_CSS_PERFIX + item)

      // 如果提供了回调函数,则监听动画结束事件
      classList.add(...animationTypes)

      const onAnimationEnd = () => {
        try {
          if (callback) {
            callback()
          }
        } finally {
          // 移除事件监听器,避免多次绑定
          instance.removeEventListener('animationend', onAnimationEnd)
          classList.remove(...animationTypes)
        }
      }
      instance.addEventListener('animationend', onAnimationEnd)
    }
  }
}

使用方法:元素预先添加animate__animated样式,再在调用时传入ref对象和要执行的动画方法即可

html 复制代码
      <view class="x-items-left mb-60rpx">
        <view class="flex-1" />
        <view ref="tips" class="w-120rpx text-teal animate__animated">密码登录</view>
      </view>

执行动画

TypeScript 复制代码
const tips = ref(null)

const getCode = (type: string = 'headShake') => {
  utils.animatecss(tips, type)
}

由于支持callback,你还可以把多个动画组合起来,例如这个:

摆一摆,再跳一跳(在安卓/IOS下不可用)

TypeScript 复制代码
const getCode = (type: string = 'animate__headShake') => {
  utils.animatecss(tips, 'headShake', () => {
    utils.animatecss(tips, 'bounce')
  })
}

还可以添加多个控制参数指定,例如慢慢摇,快快跳

TypeScript 复制代码
  utils.animatecss(tips, ['headShake', 'slower'], () => {
    utils.animatecss(tips, ['bounce', 'faster'])
  })

控制参数组合见animate.css官方网站

https://animate.style/

相关推荐
某公司摸鱼前端11 小时前
uniapp 上了原生的 echarts 图表插件了 兼容性还行
前端·uni-app·echarts
貂蝉空大12 小时前
uni-app 封装websocket 心跳检测,开箱即用
websocket·网络协议·uni-app
风清云淡_A1 天前
uniapp中在web端如何友好的展示app当前的版本等信息
前端·uni-app
GoppViper1 天前
uniapp设置从右上角到左下角的三种渐变颜色
前端·前端框架·uni-app·uniapp
某公司摸鱼前端1 天前
推荐 uniapp 相对好用的海报生成插件
小程序·uni-app·canvas
程楠楠&M1 天前
uni-app运行到 Android 真机和Android studio模拟器
android·uni-app·android studio
GoppViper1 天前
uniapp view增加删除线
前端·前端框架·uni-app·uniapp
NiNg_1_2342 天前
vue框架和uniapp框架区别
vue.js·uni-app
阿里巴巴首席技术官2 天前
UNIAPP 动态菜单实现方法
uni-app
某公司摸鱼前端3 天前
uniapp微信小程序使用ucharts遮挡自定义tabbar的最佳解决方案
微信小程序·小程序·uni-app·echarts·ucharts