从零实现Vue的组件库(二)-Slider组件实现

栏目: 编程语言 · 发布时间: 6年前

内容简介:实现一个Slider组件,方便用户通过拖动滑块在一个固定区间内进行选择,增强交互细节。概述: 在用户手动一些限定数字时,如果采用输入框的形式,会需要提示信息和错误信息来引导用户,这就存在一些冗余操作。所以衍生出Slider组件,方便用户拖动来选定一个值。代码

实现一个Slider组件,方便用户通过拖动滑块在一个固定区间内进行选择,增强交互细节。

概述: 在用户手动一些限定数字时,如果采用输入框的形式,会需要提示信息和错误信息来引导用户,这就存在一些冗余操作。所以衍生出Slider组件,方便用户拖动来选定一个值。

该组件的痛点在于:
  • 兼容不同游览器的样式;
  • Slider组件的value、min、max之间的关系,以及对样式的影响。

1. 实例

从零实现Vue的组件库(二)-Slider组件实现

代码

<!-- 基础用法 -->
<fat-slider />
<!-- 设置Min、Max以及Step -->
<fat-slider :min="20" :max="40" step="5" />
<!-- 绑定v-model -->
<fat-slider v-model="initValue" />
<!-- 不现实Tool-Tip -->
<fat-slider v-model="value" :show-tooltip="false" />
<!-- disabled 该组件 -->
<fat-slider disabled />
复制代码

实例地址:Slider 实例

代码地址: Github UI-Library

2. 原理

该组件的实现是基于原生的 <input type="range" /> ,再通过改写样式以达到上图效果。

组件的基本结构如下

<template>
  <div :class="['slider-wrap', { 'is-disabled': disabled }]">
    <input
      :class="['slider-inner', { 'is-disabled': disabled }]"
      :disabled="disabled"
      :min="min"
      :max="max"
      type="range"
      v-on="$listeners"
      v-model="rate"
      v-bind="$attrs"
    >
  </div>
</template>
复制代码
  • 先将修改组件的thumb以及轨道track的样式:

将其从原生的形式

从零实现Vue的组件库(二)-Slider组件实现

变成以下的样式

从零实现Vue的组件库(二)-Slider组件实现

基于 cross-browser-range-input 这篇博文,进行基础样式的修改。

为了兼容不同的游览器,首先利用 @mixin 抽离出thumb公共的样式。

@mixin thumb-common-style() {
    position: relative;
    z-index: 3;
    border: 2px solid #409eff;
    background: #fff;
    cursor: grab;
    transition: all 0.3s;
}
// 后续可以丰富rect-slider-thumb等类型
@mixin circle-slider-thumb() {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    &:active {
        cursor: grabbing;
    }
}
复制代码

然后适配不同的浏览器

&::-webkit-slider-thumb {
    // thumb居中
    margin-top: -6px;
    @include circle-slider-thumb();
    @include thumb-common-style();
}
&::-moz-range-thumb {
    @include circle-slider-thumb();
    @include thumb-common-style();
    // z-index无效
    transform: translateZ(1px);
}
&::-ms-thumb {
    @include circle-slider-thumb();
    @include thumb-common-style();
}
复制代码

然后以同样的方法来处理track的样式

@mixin common-track {
    width: 100%;
    height: 6px;
    background: #e4e7ed;
    border-radius: 3px;
    cursor: pointer;
}
复制代码

适配不同浏览器

&::-webkit-slider-runnable-track {
        @include common-track();
    }
    &::-moz-range-track {
        @include common-track();
    }
    /* 只有ms支持fill-lower、fill-upper */
    &::-ms-track {
        width: 100%;
        height: 6px;
        cursor: pointer;
        background: transparent;
        border-color: transparent;
        border-width: 16px 0;
        color: transparent;
    }
    &::-ms-fill-lower {
        background: #409eff;
        border-radius: 3px;
    }
    &::-ms-fill-upper {
        background: #c4c4c4;
        border-radius: 3px;
    }
复制代码

此时Slider组件在不同浏览器下的显示,如下图

  • Chrome

    从零实现Vue的组件库(二)-Slider组件实现
  • Firefox

    从零实现Vue的组件库(二)-Slider组件实现
  • Ie11

    从零实现Vue的组件库(二)-Slider组件实现

此时的Ie11优秀的不得了,不仅提供了 fill-upperfill-lower 还自带tool-tip提示功能。为了让其他浏览器向他靠齐,就需要实现上述两个功能。丰富组件的结构为

<div :class="['slider-wrapper', { 'is-disabled': disabled }]">
    <div v-if="!isIE" class="progress" :style="progressStyle"></div>
    <input
      :class="['slider-inner', { 'is-disabled': disabled }]"
      :disabled="disabled"
      :min="min"
      :max="max"
      type="range"
      v-on="$listeners"
      v-model="rate"
      v-bind="$attrs"
    >
    <span v-if="!isIE && showTooltip" class="tooltip" :style="toolTipPosition">
    {{ rate }}</span>
</div>
复制代码

组件中 progresstooltip 的样式需要通过当前的rate值来进行修改,其规则为

computed: {
    isIE() {
        return (
            !!window.ActiveXObject ||
            "ActiveXObject" in window ||
            navigator.userAgent.indexOf("Edge") > -1
        );
    },
    progressStyle() {
        const { rate, max, min } = this;
        
        return {
            width: `${((rate - min) * 100) / (max - min)}%`
        };
    },
    toolTipPosition() {
        const { rate, max, min } = this;
        const xOffset = 9 - 18 * ((rate - min) / (max - min));
        
        return {
            left: `${((rate - min) * 100) / (max - min)}%`,
            marginLeft: `${xOffset}px`,
            transform: `translateX(-50%)`
        };
    }
}
复制代码

其中 progressStyle 比较好理解,就是当前rate的值占整体的百分比,而 toolTipPosition 则是利用

position: absolute;
/* <percentage>s of the width of the containing block */
left: 10%;
/* <percentage>s of the width of the element */
tansform: translateX(-50%);
复制代码

3. 使用

进一步将其封装成Vue的组件,配置其 propsdata

export default {
    props: {
        showTooltip: { type: Boolean, default: true },
        disabled: { type: Boolean, default: false },
        min: { type: Number, default: 0 },
        max: { type: Number, default: 100 },
        value: { type: [Number, String] }
    },
    // 处理v-model
    model: {
        prop: "value",
        event: "sliding"
    },
    watch: {
        // 动态修改
        rate(value) {
            this.$emit("sliding", Number(value));
        },
        // 如果不存在初始值的话,以最小值为初始值
        value: {
            handler(value) {
                this.rate = this.value || this.min;
            },
            immediate: true
        }
    }
}
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

GWT in Action

GWT in Action

Robert Hanson、Adam Tacy / Manning Publications / 2007-06-05 / USD 49.99

This book will show Java developers how to use the Google Web Toolkit (GWT) to rapidly create rich web-based applications using their existing skills. It will cover the full development cycle, from ......一起来看看 《GWT in Action》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换