# transition

transition CSS 属性是 transition-property、transition-duration、transition-timing-function 和 transition-delay 的一个简写属性 (en-US)。

# uni-app x 兼容性

Web Android iOS HarmonyOS
4.0 3.9 4.11 4.61

# 语法

transition: <single-transition>#;

# transition 的属性值

名称 兼容性 描述
all
每一个能够进行过渡动画的属性都会进行过渡动画。
none
没有属性会进行过渡动画。

# App平台

从 HBuilderX4.11 版起,默认值调整为all。HBuilderX4.11 以下版本,默认值为none

transition暂不支持结束属性值为百分比。

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

扫码体验(手机浏览器跳转到App直达页)

示例

<template>
  <!-- #ifdef APP -->
  <scroll-view style="flex: 1">
  <!-- #endif -->
    <view class="container">
      <text class="text">点击修改宽度</text>
      <view class="base-style transition-width" id="widthOrHeight" @click="changeWidthOrHeight"></view>
    </view>
    <view class="container">
      <text class="text">点击修改宽度(递增)</text>
      <view class="width-progress transition-width" id="widthProgress" @click="changeWidthProgress"></view>
    </view>
    <view class="container">
      <text class="text">点击修改宽度(通过style设置transition)</text>
      <view class="base-style" style="transition-property: width; transition-duration: 1s;" id="widthOrHeightStyle"
        @click="changeWidthOrHeightStyle"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Margin</text>
      <view class="base-style transition-margin" id="styleMargin" @click="changeMargin"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Padding</text>
      <view class="base-style transition-padding" id="stylePadding" @click="changePadding">
        <view style="background-color: black; height: 50px; width: 50px"></view>
      </view>
    </view>
    <view class="container">
      <text class="text">点击修改background-color和opacity</text>
      <view class="base-style transition-background" id="styleBackground" @click="changeBackground"></view>
    </view>
    <view class="container">
      <text class="text">点击修改background-color(rgba)</text>
      <view style="flex: 1;">
        <view class="base-style transition-background" id="styleBackground2" @click="changeBackground2"></view>
      </view>
    </view>
    <view class="container">
      <text class="text">点击修改opacity渐隐渐现</text>
      <view class="base-style transition-opacity" id="styleOpacity" @click="changeStyleOpacity"></view>
    </view>
    <view class="container">
      <text class="text">动态修改background-color和duration</text>
      <view class="base-style" id="propertyStyleBackground" @click="propertyChangeBackground"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Transform</text>
      <view class="base-style transition-transform" id="styleTransform" @click="changeTransform"></view>
    </view>
    <view class="container">
      <text class="text">点击修改TransformTranslate</text>
      <view class="base-style transition-transform" id="transformTranslate" @click="changeTransformTranslate"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Transform和宽</text>
      <view class="base-style transition-transform-width" id="styleTransformWithWidth"
        @click="changeTransformWithWidth"></view>
    </view>
    <view class="container" @click="changeTransformWithOrigin">
      <text class="text">点击修改Transform(含transform-origin)</text>
      <view class="base-style transition-transform" style="transform-origin: 0 0;" id="styleTransformWithOrigin"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Border</text>
      <view class="base-style transition-border" id="styleBorder" @click="changeBorder"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Position</text>
      <view class="base-style transition-position" id="stylePosition" @click="changestylePosition"></view>
    </view>
    <view class="container">
      <text class="text">点击修改Scale
      </text>
      <view class="base-style transition-transform" id="styleChangScale" @click="changestyleScale"></view>
    </view>
    <view class="container">
      <text class="text">仅指定transition-duration背影有动画为正常</text>
      <view style="width: 100%;height: 50px;" :style="changestyleTransitionDuration"
        @click="doChangeTransitionDuration">
      </view>
    </view>

    <view class="container">
      <text class="text">transition-property: all/none 演示</text>
      <view class="base-style transition-all" id="styleTransitionAll" @click="changeTransitionAll"></view>
    </view>

    <view class="container">
      <text class="text">在组件内滑动测试是否闪动</text>
      <view class="base-style transition-transform" id="styleTransformTranslateScale" @touchmove="handleTouchMove"
        @touchstart="handleTouchStart" @touchend="handleTouchEnd">
        这是一段文字
      </view>
    </view>

    <view class="container">
      <text class="text">测试在style中同时修改transform和width</text>
      <view style="width:100%;height: 100%;">
        <view class="base-style transition-transform-width" id="styleTransformTranslateScale"
          :style="{transform:`translateX(${lineLeft}px)`,width:`${lineWidth}px`}" @click="changeTransform61">
        </view>
      </view>
    </view>

    <!-- #ifndef APP-ANDROID -->
    <view style="margin: 7px; height: 60px;">
      <navigator url="/pages/CSS/transition/transition-transform" hover-class="none">
        <button type="primary">
          transform 多个属性示例
        </button>
      </navigator>
    </view>
    <!-- #endif -->

  <!-- #ifdef APP -->
  </scroll-view>
  <!-- #endif -->
</template>

<script>
  export default {
    data() {
      return {
        isTranstionWidthOrHeight: false,
        widthOrHeight: null as UniElement | null,
        widthProgress: null as UniElement | null,
        isTranstionWidthOrHeightStyle: false,
        widthOrHeightStyle: null as UniElement | null,
        progressWidth: 200,
        isTranstionChangeMargin: false,
        styleMargin: null as UniElement | null,
        isTransitionStylePadding: false,
        stylePadding: null as UniElement | null,
        isTransitionstyleBackground: false,
        isTransitionstyleBackground2: false,
        isTransitionstyleOpacity: false,
        styleBackground: null as UniElement | null,
        styleBackground2: null as UniElement | null,
        styleOpacity: null as UniElement | null,
        isTransitionStyleTransform: false,
        styleTransform: null as UniElement | null,
        isTransitionStyleTransformWithWidth: false,
        styleTransformWithWidth: null as UniElement | null,
        isTransitionstyleBorder: false,
        styleBorder: null as UniElement | null,
        isTransitionstylePosition: false,
        stylePosition: null as UniElement | null,
        isSetTransition: false,
        isTransitionpropertystyleBackground: false,
        propertyStyleBackground: null as UniElement | null,
        isTransitionStyleTransformWithOrigin: false,
        styleTransformWithOrigin: null as UniElement | null,
        styleTransformTranslate: null as UniElement | null,
        isTransformTranslate: false,
        styleTransformTranslateScale: null as UniElement | null,
        startX: 0,
        moveX: 0,
        oldX: 0,
        changestyleTransitionDuration: 'background-color:brown;',
        styleTransitionAll: null as UniElement | null,
        isTransitionAll: false,
        lineLeft: 0,
        lineWidth: 200,
      }
    },
    onReady() {
      this.widthOrHeight = uni.getElementById("widthOrHeight")
      this.widthProgress = uni.getElementById("widthProgress")
      this.widthOrHeightStyle = uni.getElementById("widthOrHeightStyle")
      this.styleMargin = uni.getElementById("styleMargin")
      this.stylePadding = uni.getElementById("stylePadding")
      this.styleBackground = uni.getElementById("styleBackground")
      this.styleBackground2 = uni.getElementById("styleBackground2")
      this.styleOpacity = uni.getElementById("styleOpacity")
      this.styleTransform = uni.getElementById("styleTransform")
      this.styleBorder = uni.getElementById("styleBorder")
      this.stylePosition = uni.getElementById("stylePosition")
      this.propertyStyleBackground = uni.getElementById("propertyStyleBackground")
      this.styleTransformWithOrigin = uni.getElementById("styleTransformWithOrigin")
      this.styleTransformWithWidth = uni.getElementById("styleTransformWithWidth")
      this.styleTransformTranslate = uni.getElementById("transformTranslate")
      this.styleTransformTranslateScale = uni.getElementById("styleTransformTranslateScale")
      this.styleTransitionAll = uni.getElementById("styleTransitionAll")
    },
    methods: {
      changeWidthOrHeight() {
        this.widthOrHeight?.style?.setProperty("width", this.isTranstionWidthOrHeight
          ? '200px'
          : '300px')
        this.isTranstionWidthOrHeight = !this.isTranstionWidthOrHeight
      },
      changeWidthProgress() {
        this.progressWidth += 20
        this.widthProgress?.style?.setProperty("width", this.progressWidth + 'px')
      },
      changeWidthOrHeightStyle() {
        this.widthOrHeightStyle?.style?.setProperty("width", this.isTranstionWidthOrHeightStyle
          ? '200px'
          : '300px')
        this.isTranstionWidthOrHeightStyle = !this.isTranstionWidthOrHeightStyle
      },
      changeMargin() {
        this.styleMargin?.style?.setProperty("margin-top", this.isTranstionChangeMargin
          ? '0px'
          : '50px'
        )
        this.styleMargin?.style?.setProperty("margin-left", this.isTranstionChangeMargin
          ? '0px'
          : '50px'
        )
        this.isTranstionChangeMargin = !this.isTranstionChangeMargin
      },

      changePadding() {
        this.stylePadding?.style?.setProperty("padding-top", this.isTransitionStylePadding
          ? '0px'
          : '50px')
        this.stylePadding?.style?.setProperty("padding-left", this.isTransitionStylePadding
          ? '0px'
          : '50px')
        this.isTransitionStylePadding = !this.isTransitionStylePadding
      },
      changeBackground() {
        this.styleBackground?.style?.setProperty("background-color", this.isTransitionstyleBackground
          ? 'brown'
          : 'black'
        )
        this.styleBackground?.style?.setProperty("opacity", this.isTransitionstyleBackground
          ? '1'
          : '0.5'
        )
        this.isTransitionstyleBackground = !this.isTransitionstyleBackground
      },
      changeBackground2() {
        this.styleBackground2?.style?.setProperty("background-color", this.isTransitionstyleBackground2
          ? 'brown'
          : 'rgba(0, 0, 0, 0.5)'
        )
        this.isTransitionstyleBackground2 = !this.isTransitionstyleBackground2
      },
      changeStyleOpacity() {
        this.styleOpacity?.style?.setProperty("opacity", this.isTransitionstyleOpacity
          ? '1'
          : '0'
        )
        this.isTransitionstyleOpacity = !this.isTransitionstyleOpacity
      },
      propertyChangeBackground() {
        if (!this.isSetTransition) {
          this.propertyStyleBackground?.style?.setProperty("transition-property", "background-color")
          this.propertyStyleBackground?.style?.setProperty("transition-duration", "1000ms")
          this.isSetTransition = true
        }
        this.propertyStyleBackground?.style?.setProperty("background-color", this.isTransitionpropertystyleBackground
          ? 'brown'
          : 'black'
        )
        this.isTransitionpropertystyleBackground = !this.isTransitionpropertystyleBackground
      },
      changeTransform() {
        this.styleTransform?.style?.setProperty("transform", this.isTransitionStyleTransform
          ? 'rotate(0deg)'
          : 'rotate(135deg)'
        )
        this.isTransitionStyleTransform = !this.isTransitionStyleTransform
      },
      changeTransformTranslate() {
        const translate = this.isTransformTranslate ? `translate(0%,0%)` : `translate(100%,0%)`
        this.styleTransformTranslate?.style?.setProperty('transform', translate)
        this.isTransformTranslate = !this.isTransformTranslate
      },
      changeTransformWithWidth() {
        this.styleTransformWithWidth?.style?.setProperty("transform", this.isTransitionStyleTransformWithWidth
          ? 'rotate(0deg)'
          : 'rotate(135deg)'
        )
        this.styleTransformWithWidth?.style?.setProperty("width", this.isTransitionStyleTransformWithWidth
          ? '200px'
          : '100px'
        )
        this.isTransitionStyleTransformWithWidth = !this.isTransitionStyleTransformWithWidth
      },
      changeTransformWithOrigin() {
        this.styleTransformWithOrigin?.style?.setProperty("transform", this.isTransitionStyleTransformWithOrigin
          ? 'scaleX(1)'
          : 'scaleX(0)'
        )
        this.isTransitionStyleTransformWithOrigin = !this.isTransitionStyleTransformWithOrigin
      },
      changeBorder() {
        this.styleBorder?.style?.setProperty("border-color", this.isTransitionstyleBorder
          ? 'brown'
          : 'yellow'
        )
        this.isTransitionstyleBorder = !this.isTransitionstyleBorder
      },
      changestylePosition() {
        this.stylePosition?.style?.setProperty("left", this.isTransitionstylePosition
          ? '0px'
          : '100px'
        )
        this.isTransitionstylePosition = !this.isTransitionstylePosition
      },
      changestyleScale() {
        let el = uni.getElementById("styleChangScale")
        el?.style.setProperty("transition-duration", "0ms")
        el?.style.setProperty("transform", "translate(10px,10px) scale(1)")
        setTimeout(() => {
          el?.style.setProperty("transition-duration", "200ms")
          el?.style.setProperty("transform", "translate(10px,10px) scale(0.5)")
        }, 200)
      },
      handleTouchStart(e : UniTouchEvent) {
        this.startX = e.changedTouches[0].clientX
      },
      handleTouchMove(e : UniTouchEvent) {
        console.log("touchmove:" + e.touches[0].clientX + "," + e.touches[0].clientY);
        e.preventDefault()
        e.stopPropagation()
        const difX = e.changedTouches[0].clientX
        this.moveX = difX - this.startX + this.oldX
        this.styleTransformTranslateScale?.style?.setProperty('transition-duration', '0ms')
        this.styleTransformTranslateScale?.style?.setProperty('transform', `translate(${this.moveX}px,0px) scale(0.5) rotate(90deg)`)
      },
      handleTouchEnd(_ : UniTouchEvent) {
        this.oldX = this.moveX
      },
      doChangeTransitionDuration() {
        console.log("doChangeTransitionDuration")
        this.changestyleTransitionDuration
          = this.changestyleTransitionDuration === 'background-color:brown;' ? 'transition-duration: 2000ms;background-color: blue;' : 'background-color:brown;'
      },
      changeTransitionAll() {
        if (!this.isTransitionAll) {
          // 设置为 all 时的效果
          this.styleTransitionAll?.style?.setProperty("transition-property", "all")
          this.styleTransitionAll?.style?.setProperty("width", "300px")
          this.styleTransitionAll?.style?.setProperty("height", "300px")
          this.styleTransitionAll?.style?.setProperty("background-color", "blue")
          this.styleTransitionAll?.style?.setProperty("transform", "rotate(45deg)")
        } else {
          // 设置为 none 时的效果
          this.styleTransitionAll?.style?.setProperty("transition-property", "none")
          this.styleTransitionAll?.style?.setProperty("width", "200px")
          this.styleTransitionAll?.style?.setProperty("height", "200px")
          this.styleTransitionAll?.style?.setProperty("background-color", "brown")
          this.styleTransitionAll?.style?.setProperty("transform", "rotate(0deg)")
        }
        this.isTransitionAll = !this.isTransitionAll
      },
      changeTransform61() {
        if (this.lineLeft == 0) {
          this.lineLeft = 70
          this.lineWidth = 300
        } else {
          this.lineLeft = 0
          this.lineWidth = 200
        }
      },
    },
  }
</script>

<style>
  .container {
    margin: 7px;
    background-color: white;
  }

  .text {
    margin-top: 10px;
    margin-bottom: 16px;
  }

  .base-style {
    width: 200px;
    height: 200px;
    background-color: brown;
  }

  .width-progress {
    width: 200px;
    height: 200px;
    background-color: brown;
  }

  .transform-bgColor {
    transition-property: background-color;
    transition-duration: 0.5s;
  }

  .transition-width {
    transition-property: width;
    transition-duration: 1s;
  }

  .transition-margin {
    transition-property: margin-left, margin-top;
    transition-duration: 1s;
  }

  .transition-padding {
    transition-property: padding-left, padding-top;
    transition-duration: 1s;
  }

  .transition-background {
    transition-property: background-color, opacity;
    transition-duration: 1s;
  }

  .transition-opacity {
    transition-property: opacity;
    transition-duration: 1s;
  }

  .transition-transform {
    transform: translate(0%, 0%) scaleX(1) rotate(0deg);
    transition-property: transform;
    transition-duration: 1s;
  }

  .transition-border {
    border-width: 5px;
    border-color: brown;
    border-style: solid;
    transition-property: border-color;
    transition-duration: 1s;
  }

  .transition-position {
    left: 0px;
    transition-property: left;
    transition-duration: 1s;
  }

  .transition-transform-width {
    transform: rotate(0deg);
    transition-property: transform, width;
    transition-duration: 1s;
  }

  .transition-all {
    transition-property: all;
    transition-duration: 1s;
  }
</style>

# 参见

# Bug & Tips

  • App-Harmony 平台, 更新属性值时是否有动画效果,取决于 transition-property 中是否包含该属性。
    例如要对 width 做动画效果,初始宽度不需要动画效果,则应该在设置 transition-property: width 前设置初始宽度。
    后续修改 width 需要有动画效果时,需要在修改前设置 transition-property: width
.box {
	/* 初始宽度不需要动画效果, 需要设置在 transition-property: width 之前 */
	width: 100px;
	transition-property: width;
	transition-duration: 1s;
}
/* 因为之前设置了 transition-property: width,此时修改 width 会有动画效果 */
.box.active {
	width: 200px;
}