【sgOvalMenu】自定义组件:椭圆形菜单,菜单按钮可以随着椭圆轨迹进行循环运动

news2024/11/17 8:25:36

 

特性:

  1. 可以设置椭圆轨迹宽度、高度 
  2. 可以设置椭圆轨迹旋转角度,并且自动纠偏菜单文字水平状态
  3. 可以设置运动轨迹坐标移动步长
  4. 可以设置运动轨迹改变频率
  5. 可以设置顺时针还是逆时针旋转

sgOvalMenu源码 

<template>
    <div :class="$options.name" :style="style">
        <div class="ovalMenuBtn" v-for="(a, i) in menubtns" :key="i" :style="a.style" @click="$emit(`click`, a);">
            <slot :data="a"></slot>
        </div>
    </div>
</template>
<script>
export default {
    name: 'sgOvalMenu',
    data() {
        return {
            style: {},
            coordinates: [],
            step_: 0,//按钮在椭圆轨道上面移动的步长
            time_: 0,//按钮坐标变化的时间间隔
            interval: null,
            menubtns: [],
        }
    },
    props: [
        "width",//椭圆的长直径
        "height",//椭圆的短直径
        "rotate",//椭圆旋转角度
        "step",//按钮在椭圆轨道上面移动的步长
        "time",//按钮坐标变化的时间间隔
        "clockwise",//顺时针运动(boolean)
        "data",//椭圆上面的按钮数据
    ],
    watch: {
        width: {
            handler(d) {
                this.style.width = `${d || 800}px`;
            }, deep: true, immediate: true,
        },
        height: {
            handler(d) {
                this.style.height = `${d || 400}px`;
            }, deep: true, immediate: true,
        },
        rotate: {
            handler(d) {
                this.style.rotate = `${d || 0}deg`;
                this.setProperty();
            }, deep: true, immediate: true,
        },
        step: {
            handler(d) {
                this.step_ = d || 2;
            }, deep: true, immediate: true,
        },
        time: {
            handler(d) {
                this.time_ = d || 200;
            }, deep: true, immediate: true,
        },
        data: {
            handler(d) {
                if (d) {
                    this.menubtns = JSON.parse(JSON.stringify(d));
                    this.getCoordinates(d => {
                        this.coordinates = d;
                        this.triggerAnimate();
                    });
                }
            }, deep: true, immediate: true,
        },
    },
    destroyed() {
        clearInterval(this.interval);

    },
    created() {
    },
    mounted() {
        this.setProperty();
    },
    computed: {

    },
    methods: {
        setProperty() {
            this.$el && this.$el.style.setProperty("--rotate", `${-1 * parseFloat(this.style.rotate || 0)}deg`); //js往css传递局部参数
        },
        triggerAnimate() {
            clearInterval(this.interval);
            this.interval = setInterval(() => {
                this.setStyles();
            }, this.time_);
            this.setStyles();
        },
        setStyles() {
            let coordinateStep = this.coordinates.length / this.menubtns.length;
            let arr = this.coordinates, N = this.step_;
            if (this.clockwise || this.clockwise === '') {
                //前面N个元素挪到最后
                arr.splice(arr.length - 1, 0, ...arr.splice(0, N));
            } else {
                //最后N个元素挪到前面
                arr.splice(0, 0, ...arr.splice(arr.length - N));
            }
            this.coordinates = arr;
            this.menubtns.forEach((v, i) => {
                let coordinate = this.coordinates[i * coordinateStep];
                this.$set(v, "style", {
                    left: `${coordinate.x}px`,
                    top: `${coordinate.y}px`,
                });
            });
        },
        getCoordinates(cb) {
            let a = parseFloat(this.style.width) / 2;
            let b = parseFloat(this.style.height) / 2;
            this.getCPoint(a, b, 1, a, b, cb);
        },
        // a 长半径, b 短半径, p 节点的间隔 , cx, cy 圆心, 
        getCPoint(a, b, p = 1, cx = 0, cy = 0, cb) {
            const data = []
            for (let index = 0; index < 360; index = index + p) {
                let x = a * Math.cos(Math.PI * 2 * index / 360)
                let y = b * Math.sin(Math.PI * 2 * index / 360)
                data.push({ x: x + cx, y: y + cy })
            }
            cb && cb(data);
        },
    }
};
</script>    
<style lang="scss" scoped>
$rotate: var(--rotate);

.sgOvalMenu {
    border: 2px dashed #eee;
    border-color: #66b1ff66 #66b1ffAA #66b1CC #66b1ff;
    border-radius: 100%;
    width: 100%;
    height: 100%;
    transform-origin: center;
    transition: .382s linear;

    .ovalMenuBtn {
        white-space: nowrap;
        position: absolute;
        width: max-content;
        height: max-content;
        left: 0;
        top: 0;
        transform: translate(-50%, -50%) rotate($rotate);
        transform-origin: center;
        // transition: left .618s, top .618s, filter .382s;
        transition: .382s;
        pointer-events: auto;
        color: white;
        cursor: pointer;

        &:hover {
            filter: brightness(1.1);
        }
    }
}
</style>

应用

<template>
  <div :class="$options.name">
    <!-- 椭圆菜单 -->
    <sgOvalMenu :data="ovalMenus" @click="clickOvalMenu" :width="700" :height="200" :rotate="30" clockwise>
      <template v-slot="scope">
        <div class="btn">
          {{ scope.data.label }}
        </div>
      </template>
    </sgOvalMenu>
  </div>
</template>
  
<script>
import sgOvalMenu from "./sgOvalMenu";
export default {
  name: 'sgBody',
  components: { sgOvalMenu },
  data() {
    return {
      ovalMenus: [
        { value: '1', label: '显示文本1', },
        { value: '2', label: '显示文本2', },
        { value: '3', label: '显示文本3', },
        { value: '4', label: '显示文本4', },
        { value: '5', label: '显示文本5', },
      ],
    }
  },
  methods: {
    clickOvalMenu(d) {
      console.log(`获取点击信息:`, JSON.stringify(d, null, 2));
    },
  }
};
</script>
  
<style lang="scss" scoped>
.sgBody {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: black;

  .btn {
    box-sizing: border-box;
    padding: 10px 20px;
    border-radius: 88px;
    box-sizing: border-box;
    border: 1px solid #409EFF;
    box-shadow: 0 10px 30px #409EFFAA, 0 10px 30px #409EFF99 inset;
    color: #409EFF;
    cursor: pointer;
    transition: .382s;

    &:hover {
      box-shadow: 0 10px 30px #409EFFAA, 0 10px 30px #409EFF99 inset;
      background-color: #409EFF;
      color: black;
      filter: brightness(1.3);
    }
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/933454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nacos集群

需要与Nginx配合。 这是使用三个Nacos来搭建集群。 创建mysql数据库nacos。 配置Nacos 进入nacos的conf目录&#xff0c;修改配置文件cluster.conf.example&#xff0c;重命名为cluster.conf。 在cluster.conf文件的最后加上&#xff1a; #it is ip #example 127.0.0.1:8…

【滑动窗口】leetcode209:长度最小的子数组

一.题目描述 长度最小的子数组 二.思路分析 题目要求&#xff1a;找出长度最小的符合要求的连续子数组&#xff0c;这个要求就是子数组的元素之和大于等于target。 如何确定一个连续的子数组&#xff1f;确定它的左右边界即可。如此一来&#xff0c;我们最先想到的就是暴力枚…

小研究 - Android 字节码动态分析分布式框架(五)

安卓平台是个多进程同时运行的系统&#xff0c;它还缺少合适的动态分析接口。因此&#xff0c;在安卓平台上进行全面的动态分析具有高难度和挑战性。已有的研究大多是针对一些安全问题的分析方法或者框架&#xff0c;无法为实现更加灵活、通用的动态分析工具的开发提供支持。此…

项目---日志系统

目录 项目系统开发环境核心技术日志系统介绍为什么需要日志系统? 日志系统框架设计日志系统模块划分代码实现通用工具实现日志等级模块实现日志消息模块实现格式化模块实现落地模块实现日志器模块同步日志器异步日志器缓冲区实现异步工作器实现 回归异步日志器模块建造者模式日…

用大白话来讲讲多线程的知识架构

感觉多线程的知识又多又杂&#xff0c;自从接触java&#xff0c;就在一遍一遍捋脉络和深入学习。现在将这次的学习成果展示如下。 什么是多线程&#xff1f; 操作系统运行一个程序&#xff0c;就是一个线程。同时运行多个程序&#xff0c;就是多线程。即在同一时间&#xff0…

C语言练习4(巩固提升)

C语言练习4 选择题 前言 面对复杂变化的世界&#xff0c;人类社会向何处去&#xff1f;亚洲前途在哪里&#xff1f;我认为&#xff0c;回答这些时代之问&#xff0c;我们要不畏浮云遮望眼&#xff0c;善于拨云见日&#xff0c;把握历史规律&#xff0c;认清世界大势。 选择题 …

设计模式--适配器模式(Adapter Pattern)

一、什么是适配器模式&#xff08;Adapter Pattern&#xff09; 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端所期望的另一个接口。适配器模式主要用于解决不兼容接口之间的问题&#xff0c;使得原本…

小研究 - Java虚拟机性能及关键技术分析

利用specJVM98和Java Grande Forum Benchmark suite Benchmark集合对SJVM、IntelORP,Kaffe3种Java虚拟机进行系统测试。在对测试结果进行系统分析的基础上&#xff0c;比较了不同JVM实现对性能的影响和JVM中关键模块对JVM性能的影响&#xff0c;并提出了提高JVM性能的一些展望。…

[Go版]算法通关村第十四关白银——堆高效解决的经典问题(在数组找第K大的元素、堆排序、合并K个排序链表)

目录 题目&#xff1a;在数组中找第K大的元素解法1&#xff1a;维护长度为k的最小堆&#xff0c;遍历n-k个元素&#xff0c;逐一和堆顶值对比后&#xff0c;和堆顶交换&#xff0c;最后返回堆顶复杂度&#xff1a;时间复杂度 O ( k ( n − k ) l o g k ) O(k(n-k)logk) O(k(n−…

大数据治理运营整体解决方案[39页PPT]

导读&#xff1a;原文《大数据治理运营整体解决方案[39页PPT]》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 数据治理总体方案 数据治理平台解决方案 数据治理运…

nginx生成自定义证书

1、创建key文件夹 [rootlocalhost centos]# mkdir key 进入key文件夹 [rootlocalhost centos]# cd key/ 2、生成私钥文件 [rootlocalhost key]# openssl genrsa -des3 -out ssl.key 4096 输入这个key文件的密码。不推荐输入&#xff0c;因为以后要给nginx使用。每次reload ngin…

yolov8热力图可视化

安装pytorch_grad_cam pip install grad-cam自动化生成不同层的bash脚本 # 循环10次&#xff0c;将i的值从0到9 for i in $(seq 0 13) doecho "Running iteration $i";python yolov8_heatmap.py $i; done热力图生成python代码 import warnings warnings.filterwarn…

如何延长周末体验感

美好的周末永远都是从周五开始 为了享受周末的美好时光一定要在周五下班前把工作中应该处理的事情处理好&#xff0c;避免突发事件影响后续的计划。 此外过周五晚上开始做让自己感到开心的事情&#xff0c;以此让自己感觉到周末已经开始了。包括单不限于 享受美食 周五晚上是一…

【业务功能篇84】微服务SpringCloud-ElasticSearch-Kibanan-电商实例应用

一、商品上架功能 ElasticSearch实现商城系统中全文检索的流程。 1.商品ES模型 商品的映射关系 PUT product {"mappings": {"properties": {"skuId": {"type": "long"},"spuId": {"type": "ke…

mall:redis项目源码解析

文章目录 一、mall开源项目1.1 来源1.2 项目转移1.3 项目克隆 二、Redis 非关系型数据库2.1 Redis简介2.2 分布式后端项目的使用流程2.3 分布式后端项目的使用场景2.4 常见的缓存问题 三、源码解析3.1 集成与配置3.1.1 导入依赖3.1.2 添加配置3.1.3 全局跨域配置 3.2 Redis测试…

DataFrame.set_index()方法--Pandas

1.函数功能 为DataFrame重新设置索引&#xff08;行标签&#xff09; 2. 函数语法 DataFrame.set_index(keys, *, dropTrue, appendFalse, inplaceFalse, verify_integrityFalse)3. 函数参数 参数含义keys作为行标签的列名&#xff0c;可以DataFrame中的是单个列或者多列组…

【实例分割】(一)Mask R-CNN详细介绍带python代码

目录 1.&#x1f340;&#x1f340;实例分割定义 2.&#x1f340;&#x1f340;Mask R-CNN 3.&#x1f340;&#x1f340;经典的实例分割算法 4.&#x1f340;&#x1f340;Mask R-CNN python代码 整理不易&#xff0c;欢迎一键三连&#xff01;&#xff01;&#xff01;…

【FreeRTOS】【应用篇】任务管理相关函数

文章目录 前言一、函数解析1. 任务挂起 vTaskSuspend()① 使用场景② 设计思路③ 代码 2. 任务恢复 vTaskResume()① 作用② 设计思路③ 代码 3. 挂起任务调度器 vTaskSuspendAll()① 作用② 代码 4. 恢复任务调度器 xTaskResumeAll()① 设计思路② 代码 5. 任务删除函数 vTask…

牡丹宣言:七种皮肤类型|教你如何区分和保姆级护肤大法

经常听到有人说&#xff0c;我的皮肤T区油&#xff0c;脸颊干&#xff0c;应该是混合型皮肤吧 正常的皮肤根据皮脂腺分泌油脂量的多少可分为&#xff1a;中性&#xff0c;干性&#xff0c;油性&#xff0c;混合性。 接下来小编就帮大家细化整理了七种不同的皮肤类型&#xff0c…

Nginx详解 第一部分:编译安装Nginx+Nginx模块

Part 1 一 、HTTP 和 Nginx1.1 套接字Socket1.2 URL1.2.1 定义1.2.1 URL和URN的区别1.2.3 URL组成 1.3 请求访问完整过程详解 二、I/O模型 处理高并发的时候用2.1 I/O模型简介2.2 多路复用I/O型2.3 异步I/O模型2.4 事件模型 select poll epoll 三、NGINX概述3.1 简介3.2 NGINX和…