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

相关推荐
初遇你时动了情1 小时前
uniapp 城市选择插件
开发语言·javascript·uni-app
小小黑0074 小时前
uniapp+vue3+ts H5端使用Quill富文本插件以及解决上传图片反显的问题
uni-app·vue
草字4 小时前
uniapp input限制输入负数,以及保留小数点两位.
java·前端·uni-app
前端小胡兔5 小时前
uniapp rpx兼容平板
uni-app
荔枝吖5 小时前
uniapp实现开发遇到过的问题(持续更新中....)
uni-app
艾小逗5 小时前
uniapp将图片url转换成base64支持app和h5
uni-app·base64·imagetobase64
halo14167 小时前
uni-app 界面TabBar中间大图标设置的两种方法
开发语言·javascript·uni-app
赣州云智科技的技术铺子1 天前
uni app下开发AI运动小程序解决方案
uni-app·ai运动·ai运动识别·运动识别引擎·uni ai运动解决方案·ai运动会·ai体测
Random_index1 天前
#Uniapp篇:变量&v-if 和 v-show 区别&.sync 修饰符&宽屏适配指南&Pinia内置了
uni-app
江湖行骗老中医1 天前
uni-app 修改复选框checkbox选中后背景和字体颜色
开发语言·javascript·uni-app