vue+css如何实现圆环渐变仪表盘

 更新时间:2024年08月28日 15:26:42   作者:南泉鳥  
这篇文章主要介绍了vue+css如何实现圆环渐变仪表盘问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

整体效果

主要原理

渐变圆环

设置如下css代码可实现出环形渐变效果

.box{
    background:conic-gradient(from 0deg at 50% 50%,#eee 0deg,yelllow 180deg,red 360deg)
}
  • 效果图

添加圆角以及内部圆形居中遮挡即可实现圆环效果

  • 效果图

仪表盘效果

添加若干个环绕圆点旋转的元素,组成仪表盘,融合背景色将底色圆环覆盖掉,就得到了仪表盘效果。

1.div结构

<div class="scale">
    <div
         class="s-item"
         v-for="item in 72"
         :key="'item-' + item"
         >
    </div>
</div>

2.scss

.scale {
    border-radius: 50%;
    width: 100%;
    height: 100%;
    position: absolute;
    .s-item {
        position: absolute;
        width: 1px;
        height: 2px;
        background-color: #fff;
        left:50%;
        top: 0px;
        transform-origin: 0 24px;
    }
    @for $i from 0 through 72 {
        .s-item:nth-child(#{$i + 1}) {
            transform: rotate($i * 5deg);
        }
    }
}
  • 形式图

  • 效果图

全部代码

<template>
  <div
    class="gauge"
    :style="{
      width: diameter + 'px',
      height: diameter + 'px',
      background: bgColor,
    }"
  >
    <div class="cricle" ref="cricle">
      <!-- 色块圈 -->
      <div
        class="s-color"
        :style="
          follow
            ? {
                background: `conic-gradient(from 0deg at 50% 50%,${
                  rampColor[0]
                } 0deg,${rampColor[1]} ${value / 2}deg,${
                  rampColor[2]
                } ${value}deg,${defaultColor} ${value}deg)`,
              }
            : {
                background: `conic-gradient(from 0deg at 50% 50%,${rampColor[0]} 0deg,${rampColor[1]} 50%,${rampColor[2]}`,
              }
        "
      >
        <div
          class="follow"
          v-if="!follow"
          :style="{
            background: `conic-gradient(from 0deg at 50% 50%,transparent 0deg,transparent ${value}deg,${defaultColor} ${value}deg)`,
          }"
        ></div>
        <div
          class="mask"
          :style="{
            width: `calc(100% - ${dotHeight}px *2)`,
            height: `calc(100% - ${dotHeight}px *2)`,
            background: bgColor,
          }"
        ></div>
      </div>
      <!-- 拖动按钮 -->
      <div
        class="slider"
        :style="{
          transform: `rotate(${value}deg)`,
          width: sliderDiameter + 'px',
          height: `calc(50% - ${dotHeight / 2}px + ${sliderDiameter / 2}px)`,
          left: `calc(50% - ${sliderDiameter / 2}px)`,
          top: `calc((${sliderDiameter / 2}px - ${dotHeight / 2}px) *-1)`,
        }"
      >
        <div
          class="btn"
          ref="slider"
          :style="{
            width: sliderDiameter + 'px',
            height: sliderDiameter + 'px',
            background: sliderColor,
          }"
        ></div>
      </div>
      <!-- 仪表盘 -->
      <div class="bar scale">
        <div
          class="s-item"
          v-for="item in dotCount"
          :key="'item-' + item"
          :style="{
            'transform-origin': `2px calc(${diameter}px/2 + 1px)`,
            width: dotWidth + 'px',
            height: diameter / 2 + 'px',
            transform: `rotate(${(item * 360) / dotCount}deg)`,
            background: bgColor,
          }"
        ></div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "gauge",
/** 组件参数  */
  props: {
    /** 默认值 */
    default: {
      type: Number,
      default: 0,
    },
    /** 直径 */
    diameter: {
      type: Number,
      default: 200,
    },
    /** 点间隔 */
    dotWidth: {
      type: Number,
      default: 4,
    },
    /** 点高度 */
    dotHeight: {
      type: Number,
      default: 8,
    },
    /** 滑块直径 */
    sliderDiameter: {
      type: Number,
      default: 20,
    },
    /** 滑块颜色 */
    sliderColor: {
      type: String,
      default: "red",
    },
    /** 点数量 */
    dotCount: {
      type: Number,
      default: 72,
    },
    /** 渐变色 */
    rampColor: {
      type: Array,
      default: function () {
        return ["#ddd", "#faba2a", "#f24c4f"];
      },
    },
    /** 环形默认颜色 */
    defaultColor: {
      type: String,
      default: "#ddd",
    },
    /** 背景颜色 */
    bgColor: {
      type: String,
      default: "#fff",
    },
    /** 渐变跟随 */
    follow: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      value: 0,
    };
  },
  methods: {
    /** ## 组件方法 */
    /** 获取进度 */
    getValue(){
      return this.value/360;
    }
  },
  created() {
    this.value = this.default;
  },
  mounted() {
    /** 滑块滑动功能 */
    this.$refs.slider.onmousedown = (e) => {
      const cricle = this.$refs.cricle;
      /** 获取位置(坐标轴原点) */
      let client = cricle.getBoundingClientRect();
      let x0 = client.x + cricle.offsetWidth / 2;
      let y0 = client.y + cricle.offsetHeight / 2;
      /** 阻止默认事件 */
      let ev = e || window.event;
      ev.preventDefault ? ev.preventDefault() : (ev.returnValue = false);
      /** 鼠标移动 */
      document.onmousemove = (el) => {
        let move = el ? el : window.event;
        /** 鼠标位置 */
        let x = move.x - x0;
        let y = y0 - move.y;
        /** 计算角度 */
        let deg = (Math.atan(y / x) / 2 / Math.PI) * 360;
        if (x >= 0) {
          if (this.value >= 270) {
            /** 象限跳跃优化 */
            this.value = 360;
          } else {
            this.value = 90 - deg;
          }
        } else {
          if (this.value <= 90) {
            this.value = 0;
          } else {
            this.value = 270 - deg;
          }
        }
      };
      /** 鼠标松开 */
      document.onmouseup = () => {
        /** 取消订阅鼠标移动事件 */
        document.onmousemove = null;
        document.onmouseup = null;
      };
    };
  },
};
</script>
<style lang="scss" scoped>
.box {
  width: 100%;
  height: 100%;
  position: absolute;
}
.gauge {
  padding: 5px;
  //background-color: white;
  position: relative;
  .cricle {
    width: calc(100% - 10px);
    height: calc(100% - 10px);
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translateY(-50%) translate(-50%);
    .slider {
      //background-color: pink;
      width: 20px;
      height: calc(50% + 6px);
      position: absolute;
      z-index: 10;
      overflow: hidden;
      transform-origin: 50% 100%;
      top: -6px;
      transform: rotate(140deg);
      left: calc(50% - 10px);
      .btn {
        position: absolute;
        cursor: pointer;
        top: 0px;
        width: 20px;
        height: 20px;
        // background-color: red;
        border-radius: 50%;
      }
    }
    .s-color {
      z-index: 5; //5
      position: absolute;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      .follow{
        @extend .box;
        // position: absolute;
        // width: calc(100% + 2px );
        // height: calc(100% + 2px);
        left:50%;
        top:50%;
        transform: translate(-50%,-50%);
        z-index: 6;
        border-radius: 50%;
      }
      .mask {
        content: "";
        display: block;
        position: absolute;
        //background-color: #fff;
        z-index: 9;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        border-radius: 50%;
      }
    }
    .bar {
      transform: rotate(0deg);
      transform-origin: 0 100px;
    }
    .scale {
      border-radius: 50%;
      width: calc(100% + 2px);
      height: calc(100% + 2px);
      position: absolute;
      z-index: 9;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      .s-item {
        position: absolute;
        //background-color: #fff;
        left: calc(50% - 2px);
        top: 0px;
      }
      //   @for $i from 0 through 72 {
      //     .s-item:nth-child(#{$i + 1}) {
      //       transform: rotate($i * 5deg);
      //     }
      //   }
    }
  }
}
</style>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue-router实现嵌套路由的讲解

    vue-router实现嵌套路由的讲解

    今天小编就为大家分享一篇关于vue-router实现嵌套路由的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • vue3组件库Shake抖动组件搭建过程详解

    vue3组件库Shake抖动组件搭建过程详解

    这篇文章主要为大家介绍了vue3组件库Shake抖动组件搭建过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • vue如何监听el-select选择值的变化

    vue如何监听el-select选择值的变化

    这篇文章主要介绍了vue如何监听el-select选择值的变化,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue-router中 query传参和params传参的使用和区别讲解

    vue-router中 query传参和params传参的使用和区别讲解

    这篇文章主要介绍了vue-router中 query传参和params传参的使用和区别讲解,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • mpvue全局引入sass文件的方法步骤

    mpvue全局引入sass文件的方法步骤

    这篇文章主要介绍了mpvue全局引入sass文件的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 浅谈Vue.js 1.x 和 2.x 实例的生命周期

    浅谈Vue.js 1.x 和 2.x 实例的生命周期

    下面小编就为大家带来一篇浅谈Vue.js 1.x 和 2.x 实例的生命周期。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • vue实现页面上传文件夹压缩后传给服务器的操作

    vue实现页面上传文件夹压缩后传给服务器的操作

    这篇文章主要介绍了vue实现页面上传文件夹压缩后传给服务器的操作,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • 在vue中使用防抖函数组件操作

    在vue中使用防抖函数组件操作

    这篇文章主要介绍了在vue中使用防抖函数组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • Vue局部组件数据共享Vue.observable()的使用

    Vue局部组件数据共享Vue.observable()的使用

    随着组件的细化,就会遇到多组件状态共享的情况,今天我们介绍的是 vue.js 2.6 新增加的 Observable API ,通过使用这个 api 我们可以应对一些简单的跨组件数据状态共享的情况,感兴趣的可以了解一下
    2021-06-06
  • vue3+vant4封装日期时间组件方式(年月日时分秒)

    vue3+vant4封装日期时间组件方式(年月日时分秒)

    这篇文章主要介绍了vue3+vant4封装日期时间组件方式(年月日时分秒),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10

最新评论