基于Vue过渡状态实例讲解


Posted in Javascript onSeptember 14, 2017

前面的话

Vue 的过渡系统提供了非常多简单的方法设置进入、离开和列表的动效。那么对于数据元素本身的动效呢?包括数字和运算、颜色的显示、SVG 节点的位置、元素的大小和其他的属性等。所有的原始数字都被事先存储起来,可以直接转换到数字。做到这一步,我们就可以结合 Vue 的响应式和组件系统,使用第三方库来实现切换元素的过渡状态

状态动画

通过watcher,能监听到任何数值属性的数值更新

<div id="animated-number-demo">
 <input v-model.number="number" type="number" step="20">
 <p>{{ animatedNumber }}</p>
</div>
<script src="Tween.js"></script>
<script src="vue.js"></script> 
<script>
new Vue({
 el: '#animated-number-demo',
 data: {
 number: 0,
 animatedNumber: 0
 },
 watch: {
 number: function(newValue, oldValue) {
  var vm = this;
  function animate () {
  if (TWEEN.update()) {
   requestAnimationFrame(animate)
  }
  }
  new TWEEN.Tween({ tweeningNumber: oldValue })
  .easing(TWEEN.Easing.Quadratic.Out)
  .to({ tweeningNumber: newValue }, 500)
  .onUpdate(function () {
   vm.animatedNumber = this.tweeningNumber.toFixed(0)
  })
  .start();
  animate()
 }
 }
}) 
</script>

当把数值更新时,就会触发动画。这个是一个不错的演示,但是对于不能直接像数字一样存储的值,比如 CSS 中的 color 的值,通过下面的例子来通过 Color.js 实现一个例子:

<div id="example">
 <input v-model="colorQuery" @keyup.enter="updateColor" placeholder="Enter a color">
 <button @click="updateColor">Update</button>
 <p>Preview:</p>
 <span :style="{ backgroundColor: tweenedCSSColor }" style="display: inline-block;width: 50px;height: 50px;"></span>
 <p>{{ tweenedCSSColor }}</p>
</div>
<script src="Tween.js"></script>
<script src="vue.js"></script> 
<script src="color.js"></script>
<script>
var Color = net.brehaut.Color
new Vue({
 el: '#example',
 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 = ''
 }
 }
})
</script>

动态状态转换

就像 Vue 的过渡组件一样,数据背后状态转换会实时更新,这对于原型设计十分有用。当修改一些变量,即使是一个简单的 SVG 多边形也可以实现很多难以想象的效果

<style>
svg,input[type="range"]{display:block;} 
</style>
<div id="app">
 <svg width="200" height="200">
 <polygon :points="points" fill="#41B883"></polygon>
 <circle cx="100" cy="100" r="90" fill=" transparent" stroke="#35495E"></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>
 <script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenLite.min.js"></script>
<script>
new Vue({
 el: '#app',
 data: function () {
 //默认有10条边
 var defaultSides = 10;
 //默认地,stats = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
 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) {
   //增加相应数量的随机值到stats数组中
   for (var i = 1; i <= sidesDifference; i++) {
    this.stats.push(this.newRandomValue())
   }
  }else{
   //否则,计算出差值
   var absoluteSidesDifference = Math.abs(sidesDifference)
   //从stats数组末尾减少相应数量的数组值
   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: {
 //将stats里面的值都变成50-100的随机值
 randomizeStats: function () {
  var vm = this
  this.stats = this.stats.map(function () {
  return vm.newRandomValue()
  })
 },
 newRandomValue: function () {
  //产生一个50-100的随机半径
  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 }
}
//计算polygon中的路径点的值
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(' ')
}
</script>

组件组织过渡

管理太多的状态转换会很快的增加 Vue 实例或者组件的复杂性,幸好很多的动画可以提取到专用的子组件

<div id="example">
 <input v-model.number="firstNumber" type="number" step="20"> +
 <input v-model.number="secondNumber" type="number" step="20"> =
 {{ result }}
 <p>
 <animated-integer :value="firstNumber"></animated-integer> +
 <animated-integer :value="secondNumber"></animated-integer> =
 <animated-integer :value="result"></animated-integer>
 </p>
</div>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/vue.js"></script>
<script type="text/javascript" src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/Tween.js"></script>
<script>
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()
 }
 }
})
new Vue({
 el: '#example',
 data: {
 firstNumber: 20,
 secondNumber: 40
 },
 computed: {
 result: function () {
  return this.firstNumber + this.secondNumber
 }
 }
})
</script>

以上这篇基于Vue过渡状态实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用js在页面中绘制表格核心代码
Sep 16 Javascript
Bootstrap前端开发案例二
Jun 17 Javascript
JS实现iframe编辑器光标位置插入内容的方法(兼容IE和Firefox)
Jun 24 Javascript
JavaScript SHA1加密算法实现详细代码
Oct 06 Javascript
react.js 翻页插件实例代码
Jan 19 Javascript
利用require.js与angular搭建spa应用的方法实例
Jul 19 Javascript
JavaScript中使用参数个数实现重载功能
Sep 01 Javascript
jQuery+ajax读取json数据并按照价格排序示例
Mar 28 jQuery
JavaScript创建防篡改对象的方法分析
Dec 30 Javascript
浅析vue-router实现原理及两种模式
Feb 11 Javascript
vue项目使用高德地图的定位及关键字搜索功能的实例代码(踩坑经验)
Mar 07 Javascript
解决vue与node模版引擎的渲染标记{{}}(双花括号)冲突问题
Sep 11 Javascript
JavaScript使用atan2来绘制箭头和曲线的实例
Sep 14 #Javascript
Vue2.0基于vue-cli+webpack同级组件之间的通信教程(推荐)
Sep 14 #Javascript
Vue2.0基于vue-cli+webpack父子组件通信(实例讲解)
Sep 14 #Javascript
对于js垃圾回收机制的理解
Sep 14 #Javascript
使用SVG基本操作API的实例讲解
Sep 14 #Javascript
JSON 数据格式详解
Sep 13 #Javascript
JS库 Highlightjs 添加代码行号的实现代码
Sep 13 #Javascript
You might like
php 批量添加多行文本框textarea一行一个
2014/06/03 PHP
iis6+javascript Add an Extension File
2007/06/13 Javascript
CSS+Table图文混排中实现文本自适应图片宽度(超简单+跨所有浏览器)
2009/02/14 Javascript
innerhtml用法 innertext用法 以及innerHTML与innertext的区别
2009/10/26 Javascript
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
2010/12/08 Javascript
最佳JS代码编写的14条技巧
2011/01/09 Javascript
SeaJS入门教程系列之完整示例(三)
2014/03/03 Javascript
Firefox中使用outerHTML的2种解决方法
2014/06/07 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
使用coffeescript编写node.js项目的方法汇总
2015/08/05 Javascript
JS实现网页Div层Clone拖拽效果
2015/09/26 Javascript
js命名空间写法示例
2015/12/18 Javascript
三分钟带你玩转jQuery.noConflict()
2016/02/15 Javascript
jQuery ready()和onload的加载耗时分析
2016/09/08 Javascript
JavaScript 实现的checkbox经典实例分享
2016/10/16 Javascript
jquery利用json实现页面之间传值的实例解析
2016/12/12 Javascript
360doc网站不登录就无法复制内容的解决方法
2018/01/27 Javascript
jQuery 实现批量提交表格多行数据的方法
2018/08/09 jQuery
解决vue-cli脚手架打包后vendor文件过大的问题
2018/09/27 Javascript
vue引入axios同源跨域问题
2018/09/27 Javascript
webpack+vue-cil 中proxyTable配置接口地址代理操作
2020/07/18 Javascript
python创建临时文件夹的方法
2015/07/06 Python
Python实现图片转字符画的示例
2017/08/22 Python
对python中的six.moves模块的下载函数urlretrieve详解
2018/12/19 Python
Python基本数据结构与用法详解【列表、元组、集合、字典】
2019/03/23 Python
Pyqt5 关于流式布局和滚动条的综合使用示例代码
2020/03/24 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
HTML5之WebGL 3D概述(下)—借助类库开发及框架介绍
2013/01/31 HTML / CSS
HTML5 Canvas旋转动画的2个代码例子(一个旋转的太极图效果)
2014/04/10 HTML / CSS
西班牙伏林航空公司:Vueling
2016/08/05 全球购物
美国性感内衣店:Yandy
2018/06/12 全球购物
苏格兰领先的多渠道鞋店:Begg Shoes
2019/10/22 全球购物
航空学院求职信
2014/06/11 职场文书
工作态度不端正检讨书
2014/10/04 职场文书
交通事故赔偿协议书怎么写
2014/10/04 职场文书
鼋头渚导游词
2015/02/05 职场文书