Vue | 19 过渡动画-状态过渡

news/2024/7/10 0:36:42 标签: vue, frontend technology, framework

内容提要:

  1. 动画的状态与监听器
  2. 动态状态过渡
  3. 在组件内组织过渡
  4. 为设计赋予生命

Vue的过渡系统提供了许多简单的方式去实现动画的进入、离开和列表的动效。但是怎么样对你的数据本身进行动画处理呢?例如:

  • 数字和计算
  • 颜色显示
  • 可缩放的矢量图形节点的位置
  • 元素的大小和其他属性

所有这些或者被存储为原始数据或者被转化为数字。一旦我们这样做了,我们可以使用第三方库去把这些改变的状态做成动画,再结合Vue’s的响应性和组件系统。

动画状态与监听器

监听器允许我们去捕捉将任意数字属性变为另一个属性的动画。这可能听起来很复杂,让我们使用GreenSock研究一个例子:

<script src="https://unpkg.com/pickaday@1.7.0"></script>
<script src="https://unpkg.com/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>

<div id="animated-number-demo">
  <input v-model.number = "number" type="number" step="20">
  <p>{{ animatedNumber }}</p>
</div>
new Vue({
	el: '#animated-number-demo',
  data: {
  	number: 0,
    tweenedNumber: 0
  },
  computed: {
    animatedNumber: function() {
     return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    number: function(newValue) {
      TweenLite.to(this.$data,0.5, {tweenedNumber: newValue});
    }
  }
})

animated-zero

当你更新数字的时候,改变动画在输入框的下面。这是一个很好的演示,但有些东西不是直接作为数字存储的。例如我们使用任何一项有效的CSS颜色值作为例子?这里我们使用 Tween.js 和Color.js实现:

<script src="https://unpkg.com/pickaday@1.7.0"></script>
<script src="https://unpkg.com/vue"></script>

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>
<script src="https://cdn.jsdelivr.net/npm/color-js@1.0.3"></script>

<div id="example-7">
<input 
v-model="colorQuery"
v-on:keyup.enter="updateColor"
placeholder="Enter a color"
>
<button v-on:click="updateColor">Update</button>
<p>Preview:</p>
<span
  v-bind:style="{ backgroundColor: tweenedCSSColor }"
    class="example-7-color-preview"
></span>
<p>{{ tweenedCSSColor }}</p>
</div>
var Color = net.brehaut.Color

new Vue({
 el: '#example-7',
 data: {
   colorQuery: '',
   color: {
    	red: 0,
        green: 0,
        blue: 0,
        alpha: 1
   },
   tweenedColor:{}
 },
 created: function() {
   this.tweenedColor = Object.assign({}, this.color)
 },
 watch: {
   color: function () {
     function animate () {
        if (TWEEN.update()){
           requestAnimationFrame(animate)
        }
      }
      
      new TWEEN.Tween(this.tweenedColor)
      	.to(this.color, 750)
        .start()
        
      animate() 
   }
 },
 computed: {
   tweenedCSSColor: function () {
     return new Color({
      red: this.tweenedColor.red,
      green: this.tweenedColor.green,
      blue: this.tweenedColor.blue,
      alpha: this.tweenedColor.alpha
     }).toCSS()
   }
 },
 methods: {
   updateColor: function () {
     this.color = new Color(this.colorQuery).toRGB()
     this.colorQuery = ''
   }
 }
})
.example-7-color-preview {
  display: inline-block;
  width: 50px;
  height: 50px;
}

preview-color

动态状态过渡

正如Vue过渡组件一样,数据背后状态过渡会实时更新,这对于原型设计是特别有用的!当你修改一些变量, 即使一个简单的SVG多边形,你也能实现许多效果。

<script src="https://unpkg.com/pickaday@1.7.0"></script>
<script src="https://unpkg.com/vue"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenLite.min.js"></script>

<div id="app">
  <svg width="200" height="200">
    <polygon :points="points"></polygon>
    <circle cx="100" cy="100" r="90"></circle>
  </svg>
  <label>Sides: {{ sides }}</label>
  <input 
    type="range" 
    min="3" 
    max="500" 
    v-model.number="sides"
  >
  <label>Minimum Radius: {{ minRadius }}%</label>
  <input 
    type="range" 
    min="0" 
    max="90" 
    v-model.number="minRadius"
  >
  <label>Update Interval: {{ updateInterval }} milliseconds</label>
  <input 
    type="range" 
    min="10" 
    max="2000"
    v-model.number="updateInterval"
  >
</div>
new Vue({
  el: '#app',
  data: function () {
  	var defaultSides = 10
  	var stats = Array.apply(null, { length: defaultSides })
    	.map(function () { return 100 })
  	return {
    	stats: stats,
    	points: generatePoints(stats),
      sides: defaultSides,
      minRadius: 50,
      interval: null,
      updateInterval: 500
    }
  },
  watch: {
  	sides: function (newSides, oldSides) {
    	var sidesDifference = newSides - oldSides
      if (sidesDifference > 0) {
      	for (var i = 1; i <= sidesDifference; i++) {
        	this.stats.push(this.newRandomValue())
        }
      } else {
        var absoluteSidesDifference = Math.abs(sidesDifference)
      	for (var i = 1; i <= absoluteSidesDifference; i++) {
        	this.stats.shift()
        }
      }
    },
    stats: function (newStats) {
			TweenLite.to(
      	this.$data, 
        this.updateInterval / 1000, 
        { points: generatePoints(newStats) }
    	)
    },
    updateInterval: function () {
    	this.resetInterval()
    }
  },
  mounted: function () {
  	this.resetInterval()
  },
  methods: {
    randomizeStats: function () {
    	var vm = this
    	this.stats = this.stats.map(function () {
      	return vm.newRandomValue()
      })
    },
    newRandomValue: function () {
    	return Math.ceil(this.minRadius + Math.random() * (100 - this.minRadius))
    },
    resetInterval: function () {
    	var vm = this
    	clearInterval(this.interval)
      this.randomizeStats()
    	this.interval = setInterval(function () { 
      	vm.randomizeStats()
      }, this.updateInterval)
    }
  }
})

function valueToPoint (value, index, total) {
  var x     = 0
  var y     = -value * 0.9
  var angle = Math.PI * 2 / total * index
  var cos   = Math.cos(angle)
  var sin   = Math.sin(angle)
  var tx    = x * cos - y * sin + 100
  var ty    = x * sin + y * cos + 100
  return { x: tx, y: ty }
}

function generatePoints (stats) {
	var total = stats.length
	return stats.map(function (stat, index) {
    var point = valueToPoint(stat, index, total)
    return point.x + ',' + point.y
  }).join(' ')
}
svg { display: block; }
polygon { fill: #41B883; }
circle {
  fill: transparent;
  stroke: #35495E;
}
input[type="range"] {
  display: block;
  width: 100%;
  margin-bottom: 15px;
}

sides-radius

把过渡放在组件内

在Vue的实例或组件中管理多个状态过渡会让复杂度很快提升。幸运的是,许多动画能够被提取到专用的子组件中。让我们使用之前例子中的整数动画来改写这个:

<script src="https://unpkg.com/pickaday@1.7.0"></script>
<script src="https://unpkg.com/vue"></script>

<script src="https://cdn.jsdelivr.net/npm/tween.js@16.3.4"></script>

<div id="example-8" class="demo">
 <input v-model.number="firstNumber" type="number" step="20"> + <input v-model.number="secondNumber" type="number" step="20"> = {{ result }}

<p>
<animated-integer v-bind:value="firstNumber"></animated-integer> + <animated-integer v-bind:value="secondNumber"></animated-integer> = <animated-integer v-bind:value="result"></animated-integer>
</p>
</div>
// 我们希望动画在我们的应用中这个复杂的tweening逻辑能够在任何数字之间复用。组件也提供了一个清楚的界面用于配置更多动态过渡和复杂的过渡策略
Vue.component('animated-integer',{
  template: '<span>{{ tweeningValue }}</span>',
  props: {
    value: {
      type:Number,
      required:true
    }
  },
  data: function () {
    return {
      tweeningValue: 0
    }
  },
  watch: {
    value: function (newValue, oldValue) {
      this.tween(oldValue, newValue)
    }
  },
  mounted: function () {
    this.tween(0, this.value)
  },
  methods: {
    tween: function (startValue, endValue) {
      var vm = this
      function animate () {
         if (TWEEN.update()) {
           requestAnimationFrame(animate)
         }
      }
      new TWEEN.Tween({ tweeningValue: startValue})
      .to({ tweeningValue: endValue}, 500)
      .onUpdate(function () {
         vm.tweeningValue = this.tweeningValue.toFixed(0)
      })
      .start()
      
      animate()
    }
  }
})

// 在主Vue实例中我们移除了所有的复杂性
new Vue({
 el: '#example-8',
 data: {
   firstNumber: 20,
   secondNumber: 40
 },
 computed: {
   result: function () {
     return this.firstNumber + this.secondNumber
   }
 }

})

twenty-fourth

在子组件内,我们能够使用这页介绍过的任何的联合过渡策略,和被Vue的提供的 built-in transition system一起。总之,实现各种过渡很少有限制。

赋予设计以生命

对于动画,一旦定义,意味着带来生命。不幸的是,当设计者创建了图标,logos,和吉祥物,他们常常通过图片或静态的SVGs做出。所以尽管GitHub的章鱼猫,Twitter的鸟,和其他许多logos像活生生的生物,他们看起来并不真的活着。

Vue能给予这方面的帮助。由于SVGs仅仅是数据,我们只需要这些生物兴奋,思考的,或惊慌的样子,然后Vue能帮我们在这些状态间过渡,组成你的欢迎页,加载指示器,和更多吸引人的通知。

Sarah Drasner展示了下面这个demo,这个demo结合了时间和交互相关的状态改变:

原文查看Demo


http://www.niftyadmin.cn/n/1035764.html

相关文章

13.【Linux】无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用)

当使用sudo apt-get xxx 时碰到 E: 无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用) E: 无法对目录 /var/lib/apt/lists/ 加锁解决方式具体如下&#xff1a; 1、ps-aux 查出apt-get进程的PID&#xff0c;通常是一个四位数字。 2、用kill PID代码 杀死进程&am…

Vue | 20 可复用性组合-混入

内容提要&#xff1a; 基础的混入方式操作项的合并全局的混入方式自定义操作项合并策略 混入是一种非常灵活的分发Vue组件中可复用的功能模块的方式。一个混入对象能包含任何组件操作项。当一个组件使用一个混入对象的时候&#xff0c;在混入对象的所有操作项被‘混合’进组件自…

windows10 Vscode+CMake+GCC/G++ 配置

目录一.安装软件二.配置Vscode三.配置完成后创建工程&#xff1a;一.安装软件 1.安装Vscode 支持跨平台&#xff0c;微软产品. 下载地址&#xff1a;https://code.visualstudio.com/ vscode所需插件 C/C C Intellisense CMake CMake tools CMake Tools Helper安装勾选需要的…

Vue | 21 可复用性组合-自定义指令

内容提要&#xff1a; 自定义指令基本用法介绍自定义指令内部包含哪些钩子函数指令钩子内部传递哪些元素值自定义指令函数的缩略写法用例在JavaScript对象中传递多个字面值 介绍 除了在核心附带的默认的指令集合&#xff08;v-model和v-show&#xff09;外&#xff0c;Vue也允…

ubuntu adb shell 配置

为了确保电脑可以烧写设备&#xff0c;首先需要在/etc/udev/rules.d/51-android.rules文件中增加以下命令&#xff1a; SUBSYSTEM"usb", ATTR{idVendor}"0e8d", ATTR{idProduct}"201c", MODE"0666",GROUP"plugdev"SUBSYSTEM…

15.【Linux】ubuntu 安装微信

目录1.下载deepin-wine2.下载deepin.com.wechat_2.6.8.65deepin0_i386.deb1.下载deepin-wine https://github.com/wszqkzqk/deepin-wine-ubuntu 点击 deepin-wine-ubuntu-v2.18-12-ubuntu2.tar.gz进行下载 下载下来后单独建立一个文件夹进行解压 mkdir deepin tar -xvf dee…

Vue | 22 可复用性组合-渲染函数 JSX

内容提要&#xff1a; 渲染函数基本用法节点、树和虚拟DOMcreateElement参数详解使用普通的JavaScript代替模板特性JSX插件介绍函数式组件的用法&#xff1a;传递属性和事件给子元素或子组件&#xff0c;slots() vs children模板编译的demo演示 基础 在大部分情况下我们推荐使…

SAP Validation和Substitution

先来看看Validation的简单应用&#xff1a;当用户LI_J输入Item金额大于10000时&#xff0c;系统提示Error信息。1.1.新建Validation(T-code:GGB0)如图1-1&#xff1a;[1].选择只在凭证头BKPF回车或保存时触发凭证的有效性检查。[2].选择凭证头BKPF或行项目BSEG做先决条件&#…