【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/

相关推荐
gys98956 小时前
android studio开发aar插件,并用uniapp开发APP使用这个aar
android·uni-app·android studio
自然 醒11 小时前
荣耀手机,系统MagicOS 9.0 USB配置没有音频来源后无法被adb检测到,无法真机调试的解决办法
adb·uni-app
小张快跑。16 小时前
【Vue3】使用vite创建Vue3工程、Vue3基本语法讲解
前端·前端框架·vue3·vite
*拯16 小时前
Uniapp Android/IOS 获取手机通讯录
android·ios·uni-app
gaojianqiao123417 小时前
uniapp引入七鱼客服微信小程序SDK
微信小程序·uni-app
zhangzuying102619 小时前
在uni-app中实现类似文心一言的流式对话功能:从fetch到websocket的实践
websocket·uni-app·文心一言
假客套1 天前
2025 后端自学UNIAPP【项目实战:旅游项目】3、API接口请求封装,封装后的简单测试以及实际使用
uni-app·旅游项目实战
JAVA叶知秋1 天前
uniapp自定义底部导航栏h5有效果小程序无效的解决方案
小程序·uni-app
moxiaoran57532 天前
uni-app学习笔记(二)--vue页面代码的构成和新建页面
笔记·学习·uni-app
一只程序熊2 天前
【uniapp】errMsg: “navigateTo:fail timeout“
服务器·前端·uni-app