专栏名称: 奇舞周刊
《奇舞周刊》是由奇舞团维护的前端技术周刊。除周五外,每天向大家推荐一篇前端相关技术文章,每周五向大家推送周刊汇总内容。
目录
相关文章推荐
光伏资讯  ·  来看看曲面屋顶的工商业光伏安装现场! ·  14 小时前  
光伏资讯  ·  来看看曲面屋顶的工商业光伏安装现场! ·  14 小时前  
前端早读课  ·  【第3416期】JavaScript的??= ... ·  22 小时前  
前端早读课  ·  【早阅】es-toolkit:一个Lodas ... ·  4 天前  
前端大全  ·  放弃 React,微软 Edge 团队改用 ... ·  6 天前  
前端大全  ·  Hono - 适用于任何 ... ·  1 周前  
51好读  ›  专栏  ›  奇舞周刊

巧用滑动选项卡,提升用户体验

奇舞周刊  · 公众号  · 前端  · 2017-11-05 11:55

正文

编者按:本文由夏风在众成翻译平台上翻译。

Vue的声明式特性实践


滑动选项卡

目前针对移动设备的Cordova应用程序和渐进式的Web应用程序非常流行。提升用户体验和交互的关键是传递出原生的视觉效果和感觉,这并不总是一件容易的事情。当然,新建有样式装饰的多选复选框(checkboxes)和单选按钮(radio buttons)是很容易的,但是提供我们所追求的质量飞跃的真正特性是基于用户交互的。

滑动选项卡将内容分割成不同的页面,并且它允许用户使用手指将自己想要的页面滑到当前视图。那如果,在用户拖拽页面的同时,这个应用程序随着拖拽逐渐改变自己的外观呢?是不是听起来很酷炫但是有点难呢?让我们来看看用Vue.js实现有多么简单。

开始吧

首先,我们需要一个真正的滑动选项卡组件。有很多可供选择的提供了不同的特性的这样的组件,这里我们将会使用Onsen UI提供的选项卡,它允许在滑动的时候执行自定义操作。以防你不知道这个,Onsen UI针对Vue应用程序有一系列的iOS和安卓组件。针对已存在的项目,可以使用NPM或者Yarn安装。

$> npm install onsenui vue-onsenui --save-dev

$> yarn add onsenui vue-onsenui -D

应用程序里必须有的一些文件:

import 'onsenui/css/onsenui.css'; // Webpack CSS import

import 'onsenui/css/onsen-css-components.css'; // Webpack CSS import

import VueOnsen from 'vue-onsenui';

Vue.use(VueOnsen);

另外,新的项目通过Vue CLI马上就可以开始。它可以可选的添加Vuex和一些其它的特性。

$> vue init OnsenUI/vue-cordova-webpack # For Cordova apps

$> vue init OnsenUI/vue-pwa-webpack # For PWA

这样之后,就可以在这个应用程序中使用这个组件了。

Vue里的滑动选项卡

在Vue模板里用Onsen UI添加一个最小的滑动选项卡非常简单。可以像下面这样定义:

<v-ons-tabbar swipeable :tabs="tabs" />

swipeable属性可以在应用程序的不同时刻切换允许滑动和不允许滑动,如果有必要的话。tabs是一个简单的数组对象,描述了每个选项卡的外观和每个页面、标签和图标属性的内容。这个组件完整的参考页面点击这里

在顶部,可以使用更多的设置来修改默认的表现形式,添加一些额外的自定义的属性设置,可以获得独一无二的应用程序样式。让我们一起来看看吧,例如,为了区分一个应用程序中不同的部分,怎样使用on-swipe属性,让它可以在滑动的时候逐渐的改变界面的颜色呢?(在文章的最后有链接到真实的应用程序)。

颜色插值

代码片段:

<template>

  <v-ons-page>

    <v-ons-toolbar :style="swipeTheme">

      <div class="center">Swiping Tab Bar</div>

    </v-ons-toolbar>


    <v-ons-tabbar

      swipeable

      position="top"

      :tabs="tabs"

      :on-swipe="onSwipe"

      :tabbar-style="swipeTheme"

    />

  </v-ons-page>

</template>


<script>

import Home from './pages/Home.vue';

import Forms from './pages/Forms.vue';

import Animations from './pages/Animations.vue';

// Just a linear interpolation formula

const lerp = (x0, x1, t) => parseInt((1 - t) * x0 + t * x1, 10);

// RGB colors

const red = [244, 67, 54];

const blue = [30, 136, 229];

const purple = [103, 58, 183];

export default {

  data () {

    return {

      colors: red,

      animationOptions: {},

      tabs: [

        {

          page: Home,

          label: 'Home',

          theme: red

        },

        {

          page: Forms,

          label: 'Forms',

          theme: blue

        },

        {

          page: Animations,

          label: 'Anim',

          theme: purple

        }

      ]

    };

  },

  computed: {

    swipeTheme() {

      return {

        backgroundColor: `rgb(${this.colors.join(',')})`,

        transition: `all ${this.animationOptions.duration || 0}${this.animationOptions.timing || ''}`

      }

    }

  },

  methods: {

    onSwipe(index, animationOptions) {

      // Apply the same transition as v-ons-tabbar

      this.animationOptions = animationOptions;

      // Interpolate colors

      const a = Math.floor(index), b = Math.ceil(index), ratio = index % 1;

      this.colors = this.colors.map((c, i) => lerp(this.tabs[a].theme[i], this.tabs[b].theme[i], ratio));

    }

  }

};

</script>

这个代码使用v-ons-pagev-ons-toolbarv-ons-tabbar 组件新建了一个带有简单的工具栏和选项卡的页面。tabs属性包括了一个选项卡数组。pagelabel这两个属性都可以被选项卡组件自己使用来描述这个选项卡的内容和外观,但是这并不能阻止我们用自定义的属性如theme或者其它的属性。这些主题都是RGB颜色的简单数组。我们马上就可以知道为什么这个形式可以很好的描述主题。

注意,swipeTheme计算属性是怎么传递给工具栏的(通过style属性)和选项卡的(通过tabbar-style属性)。无论什么时候改变这个属性,这两个组件的样式都会更新。在on-swipe属性中,也提供了onSwipe方法,当用户的手指在屏幕上滑动的时候总是会调用这个方法。但是我们现在怎么合适地改变界面的颜色呢?

线性插值

简单地射线,线性插值(在计算机图形学中的“lerp”)是基于一些输入,然后可以生成出两个数值(比如颜色)中间的点的一个公式。比如,我们想在屏幕上把一个点从初始位置X0逐渐移动到终点x1。我们只需要把这两个点一起给这个公式还有这个“完成率”以确定这个点在特定时刻该放置在哪个位置。换句话说,这个比率(或者叫alpha值)描述了我们距离终点有多远。

const lerp = (x0, x1, r) => (1 — r) * x0 + r * x1;

比如,如果我们想生成从x0到x1之间的三个点(不包括x0和x1),第一步需要r = 0.25(完成25%);第二步r = 0.5 (完成50%,换句话说,在中点);第三步r = 0.75(完成75%)。当然,通过提供不同的比率我们可以想生成多少就生成多少中间点。

这不仅仅适用于物理的距离,在之前的代码里,我们想根据滑动的位置逐渐把一个颜色变换成另一个颜色。为了实现这个,我们需要把颜色表示成离散的值并且知道两个页面之间滑动的比率。更精确来说,RGB颜色是由三个值组成,可以分开进行插值。其它的表示也可以进行插值但是也意味着需要更复杂的代码。

除了这些,滑动选项卡组件在onSwipe钩子中,也提供了当前页面的十进制指数。比如1.65的指数意思是当前滑动的是在页面1和页面2的65%(r = 0.65)。

因此,如果不同的RGB颜色数组被分配给每个选项卡的话,我们就可以基于当前的滑动给每个值进行插值了:

onSwipe(index, animationOptions) {

  this.animationOptions = animationOptions;


  const x0 = Math.floor(index),

    x1 = Math.ceil(index),

    ratio = index % 1;


  this.colors = this.colors.map((c, i) =>

    lerp(

      this.tabs[x0].theme[i],

      this.tabs[x1].theme[i],

      ratio

    )

  );

}

这给this.colors分派了一个新的颜色数组,基于这些颜色,将会被计算属性this.swipeTheme被动的使用来创建一个有效的CSS语法。

注意animationOptions也作为第二个参数给出来了,当滑动的时候它将会变空,当释放这次滑动的时候,选项卡将会使用手指的速度来结束这个滑动动画。这个速度在这个参数中将会被作为durationtiming(Cubic Bezier curves)并且会用来创造出CSS动画。这样,所有的动画(所有页面,选项卡边界和颜色)将会同步。

接下来是什么呢

正如你知道的,Vue的声明的性质使得这些所有东西都保持得很简单。我们可以只更新特定的属性而不用先从DOM中获取到元素再手动修改样式。

一个完整的包涵之前(甚至更多)所有的代码的Cordova应用程序在这里。它根据相同的概念添加了更多的插值。如果你想了解更多关于针对Vue的Onsen UI,可以在这里看官网

我邀请你尝试不同的动画,然后分享到Twitter :)

敲代码愉快!


奇舞周刊

——————————————————

领略前端技术 阅读奇舞周刊


长按二维码,关注奇舞周刊