vue实现标签云效果的示例


Posted in Javascript onNovember 09, 2020

闲扯两句

最近想给自己的博客上加上一个3D标签云的效果,用来表示自己博客文章的分组,网上找到了canvas实现的,还有a元素实现的解析3D标签云,我想让标签可以选择和点击,又不想在标签数量较多时操作a标签导致性能问题,于是svg就成了一个不错的选择。

标签初始化

这里实现的核心主要是参考了前面的那篇解析3D标签云的文章,作者给出了源码,讲解也比较通俗易懂。大体来说,整个代码分三步:

  • 根据标签的数量,算出每个标签在球面上分布的x,y,z坐标
  • 根据标签的坐标,将标签绘制出来,x,y坐标通过标签的位置来表示,z坐标通过标签字体的大小和透明度来表示
  • 通过函数根据球的旋转角速度不断计算标签新的x,y坐标,制造出旋转效果
  • 通过mousemove事件,根据鼠标坐标值,改变球旋转的角速度,做出交互效果

贴上代码:

<div id='app' >
    <svg :width='width' :height='height' @mousemove='listener($event)'>
      <a :href="tag.href" rel="external nofollow" v-for='tag in tags'>
        <text :x='tag.x' :y='tag.y' :font-size='20 * (600/(600-tag.z))' :fill-opacity='((400+tag.z)/600)'>{{tag.text}}</text>
      </a>
    </svg>
  </div>

在模板中,借用指令v-for来渲染标签,每个标签上绑定了x,y,font-size(用来表现z轴),fill-opacity(都是与z坐标有关的表达式,用来表现z轴),及text;

data: {
   width:700,//svg宽度
   height:700,//svg高度
   tagsNum:20,//标签数量
   RADIUS:200,//球的半径
   speedX:Math.PI/360,//球一帧绕x轴旋转的角度
   speedY:Math.PI/360,//球-帧绕y轴旋转的角度
   tags: []
 }
 computed:{
   CX(){//球心x坐标
     return this.width/2;
   },
   CY(){//球心y坐标
     return this.height/2;
   }
 },

做好了上面的基础,下面我们来初始化标签数据:

created(){//初始化标签位置
   let tags=[];
   for(let i = 0; i < this.tagsNum; i++){
     let tag = {};
     let k = -1 + (2 * (i + 1) - 1) / this.tagsNum;
     let a = Math.acos(k);
     let b = a * Math.sqrt(this.tagsNum * Math.PI)//计算标签相对于球心的角度
     tag.text = i + 'tag';
     tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b);//根据标签角度求出标签的x,y,z坐标
     tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b); 
     tag.z = this.RADIUS * Math.cos(a);
     tag.href = 'https://imgss.github.io';//给标签添加链接
     tags.push(tag);
   }
   this.tags = tags;//让vue替我们完成视图更新
 },

到了这里,我们就算了算坐标,vue完成了视图更新的工作,这时基本上就可以得到一副静态的图像了:

vue实现标签云效果的示例

下面就是通过改变每一个tag的x,y的值来使球旋转起来;实现方法是rotateX,rotateY函数:

rotateX(angleX){
    var cos = Math.cos(angleX);
    var sin = Math.sin(angleX);
    for(let tag of this.tags){
      var y1 = (tag.y- this.CY) * cos - tag.z * sin + this.CY;
      var z1 = tag.z * cos + (tag.y- this.CY) * sin;
      tag.y = y1;
      tag.z = z1;
    }
  },
  rotateY(angleY){
    var cos = Math.cos(angleY);
    var sin = Math.sin(angleY);
    for(let tag of this.tags){
      var x1 = (tag.x - this.CX) * cos - tag.z * sin + this.CX;
      var z1 = tag.z * cos + (tag.x - this.CX) * sin;
      tag.x = x1;
      tag.z = z1;
    }
  },

这两个函数就是根据标签原来的坐标和球旋转的角度算出新的坐标,最后在mounted钩子下面,写一个animate函数,不断调用这两个函数,实现旋转动画

mounted(){//使球开始旋转
    setInterval(() => {
      this.rotateX(this.speedX);
      this.rotateY(this.speedY);
    }, 17)
  },

全部代码如下:

<script>
    var app = new Vue({
      el: '#app',
      data: {
        width:700,
        height:700,
        tagsNum:20,
        RADIUS:200,
        speedX:Math.PI/360,
        speedY:Math.PI/360,
        tags: []
      },
      computed:{
        CX(){
          return this.width/2;
        },
        CY(){
          return this.height/2;
        }
      },
      created(){//初始化标签位置
        let tags=[];
        for(let i = 0; i < this.tagsNum; i++){
          let tag = {};
          let k = -1 + (2 * (i + 1) - 1) / this.tagsNum;
          let a = Math.acos(k);
          let b = a * Math.sqrt(this.tagsNum * Math.PI);
          tag.text = i + 'tag';
          tag.x = this.CX + this.RADIUS * Math.sin(a) * Math.cos(b);
          tag.y = this.CY + this.RADIUS * Math.sin(a) * Math.sin(b); 
          tag.z = this.RADIUS * Math.cos(a);
          tag.href = 'https://imgss.github.io';
          tags.push(tag);
        }
        this.tags = tags;
      },
      mounted(){//使球开始旋转
        setInterval(() => {
          this.rotateX(this.speedX);
          this.rotateY(this.speedY);
        }, 17)
      },
      methods: {
        rotateX(angleX){
          var cos = Math.cos(angleX);
          var sin = Math.sin(angleX);
          for(let tag of this.tags){
            var y1 = (tag.y- this.CY) * cos - tag.z * sin + this.CY;
            var z1 = tag.z * cos + (tag.y- this.CY) * sin;
            tag.y = y1;
            tag.z = z1;
          } 
        },
        rotateY(angleY){
          var cos = Math.cos(angleY);
          var sin = Math.sin(angleY);
          for(let tag of this.tags){
            var x1 = (tag.x - this.CX) * cos - tag.z * sin + this.CX;
            var z1 = tag.z * cos + (tag.x-this.CX) * sin;
            tag.x = x1;
            tag.z = z1;
          } 
        },
        listener(event){//响应鼠标移动
          var x = event.clientX - this.CX;
          var y = event.clientY - this.CY;
          this.speedX = x*0.0001>0 ? Math.min(this.RADIUS*0.00002, x*0.0001) : Math.max(-this.RADIUS*0.00002, x*0.0001);
          this.speedY = y*0.0001>0 ? Math.min(this.RADIUS*0.00002, y*0.0001) : Math.max(-this.RADIUS*0.00002, y*0.0001); 
        }
       }
     })
  </script>

完整demo

vue

 no vue

vue实现标签云效果的示例

总结

vue的数据绑定可以减少我们对dom的操作,而将关注点放在逻辑上面,vue构造函数提供的几个选项可以帮助我们更好的组织代码

以上就是vue实现标签云效果的示例的详细内容,更多关于vue 标签云的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
jQuery EasyUI 的EasyLoader功能介绍
Sep 12 Javascript
25个非常棒的jQuery滑块插件和教程小结
Sep 02 Javascript
jquery offset函数应用实例
Nov 14 Javascript
解析Javascript中中括号“[]”的多义性
Dec 03 Javascript
使用node.js半年来总结的 10 条经验
Aug 18 Javascript
node.js中的buffer.toString方法使用说明
Dec 14 Javascript
分享9个最好用的JavaScript开发工具和代码编辑器
Mar 24 Javascript
js模仿java的Map集合详解
Jan 06 Javascript
轻松实现JavaScript图片切换
Jan 12 Javascript
Javascript表单特效之十大常用原理性样例代码大总结
Jul 12 Javascript
简洁实用的BootStrap jQuery手风琴插件
Aug 31 Javascript
JavaScript学习笔记之图片库案例分析
Jan 08 Javascript
写一个Vue loading 插件
Nov 09 #Javascript
解决Vue大括号字符换行踩的坑
Nov 09 #Javascript
vue data有值,但是页面{{}} 取不到值的解决
Nov 09 #Javascript
vue 防止页面加载时看到花括号的解决操作
Nov 09 #Javascript
Webpack的Loader和Plugin的区别
Nov 09 #Javascript
解决vue初始化项目一直停在downloading template的问题
Nov 09 #Javascript
在VUE中使用lodash的debounce和throttle操作
Nov 09 #Javascript
You might like
PHP 出现乱码和Sessions验证问题的解决方法!
2008/12/06 PHP
PHP爆绝对路径方法收集整理
2012/09/17 PHP
PHP之autoload运行机制实例分析
2014/08/28 PHP
PHP实现获取第一个中文首字母并进行排序的方法
2017/05/09 PHP
二行代码解决全部网页木马
2008/03/28 Javascript
浅谈javascript的原型继承
2012/07/25 Javascript
js修改input的type属性及浏览器兼容问题探讨与解决
2013/01/23 Javascript
js调用css属性写法
2013/09/21 Javascript
checkbox勾选判断代码分析
2014/06/11 Javascript
JS动态加载当前时间的方法
2015/02/09 Javascript
详解JavaScript中getFullYear()方法的使用
2015/06/10 Javascript
jquery实现用户信息修改验证输入方法汇总
2015/07/18 Javascript
jQuery实现可关闭固定于底(顶)部的工具条菜单效果
2015/11/06 Javascript
很酷的星级评分系统原生JS实现
2016/08/25 Javascript
JS获取数组中出现次数最多及第二多元素的方法
2017/10/27 Javascript
javaScript日期工具类DateUtils详解
2017/12/08 Javascript
基于Vue 服务端Cookies删除的问题
2018/09/21 Javascript
js实现移动端轮播图
2020/12/21 Javascript
vue实现购物车选择功能
2020/01/10 Javascript
python list语法学习(带例子)
2013/11/01 Python
Python 和 JS 有哪些相同之处
2017/11/23 Python
python爬虫爬取淘宝商品信息(selenum+phontomjs)
2018/02/24 Python
tensorflow 获取模型所有参数总和数量的方法
2018/06/14 Python
python实现从文件中读取数据并绘制成 x y 轴图形的方法
2018/10/14 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
Revolution Beauty美国官网:英国知名化妆品网站
2018/07/23 全球购物
经济学博士求职自荐信范文
2013/11/23 职场文书
挑战杯创业计划书的写作指南
2014/01/07 职场文书
产品质量承诺书
2014/03/27 职场文书
学生检讨书怎么写
2014/10/09 职场文书
2014年民政工作总结
2014/11/26 职场文书
夫妻分居协议书范文
2014/11/26 职场文书
2017寒假社会实践心得体会范文
2016/01/14 职场文书
详解CSS不定宽溢出文本适配滚动
2021/05/24 HTML / CSS
MySQL中B树索引和B+树索引的区别详解
2022/03/03 MySQL
MySQL数据库中的锁、解锁以及删除事务
2022/05/06 MySQL