vue实现标签云效果的方法详解


Posted in Javascript onAugust 28, 2019

本文实例讲述了vue实现标签云效果的方法。分享给大家供大家参考,具体如下:

闲扯两句

最近想给自己的博客上加上一个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.js程序设计有所帮助。

Javascript 相关文章推荐
javascript encodeURI和encodeURIComponent的比较
Apr 03 Javascript
jQuery的deferred对象使用详解
Aug 20 Javascript
javascript开发随笔一 preventDefault的必要
Nov 25 Javascript
服务器端的JavaScript脚本 Node.js 使用入门
Mar 07 Javascript
js图片延迟加载的实现方法及思路
Jul 22 Javascript
基于jQuery实现的扇形定时器附源码下载
Oct 20 Javascript
apply和call方法定义及apply和call方法的区别
Nov 15 Javascript
jQuery+HTML5+CSS3制作支持响应式布局时间轴插件
Aug 10 Javascript
JS实现仿UC浏览器前进后退效果的实例代码
Jul 17 Javascript
vue.js父子组件通信动态绑定的实例
Sep 28 Javascript
vue中使用element ui的弹窗与echarts之间的问题详解
Oct 25 Javascript
vue项目接口管理,所有接口都在apis文件夹中统一管理操作
Aug 13 Javascript
微信小程序通过js实现瀑布流布局详解
Aug 28 #Javascript
TypeScript类型声明书写详解
Aug 28 #Javascript
vue服务端渲染操作简单入门实例分析
Aug 28 #Javascript
浅谈对于“不用setInterval,用setTimeout”的理解
Aug 28 #Javascript
Vue的编码技巧与规范使用详解
Aug 28 #Javascript
JS开发自己的类库实例分析
Aug 28 #Javascript
详解Vue 换肤方案验证
Aug 28 #Javascript
You might like
php MsSql server时遇到的中文编码问题
2009/06/11 PHP
php ftp文件上传函数(基础版)
2010/06/03 PHP
PHP连接MySQL数据的操作要点
2015/03/20 PHP
php判断表是否存在的方法
2015/06/18 PHP
Yii2中使用join、joinwith多表关联查询
2016/06/30 PHP
Yii2中事务的使用实例代码详解
2016/09/07 PHP
Yii框架中sphinx索引配置方法解析
2016/10/18 PHP
设定php简写功能的方法
2019/11/28 PHP
jQuery对Select的操作大集合(收藏)
2013/12/28 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
2014/08/14 Javascript
freemarker判断对象是否为空的方法
2015/08/13 Javascript
详解Angular2响应式表单
2017/06/14 Javascript
详解在WebStorm中添加Vue.js单文件组件的高亮及语法支持
2017/10/21 Javascript
在vue项目中,将juery设置为全局变量的方法
2018/09/25 Javascript
用Python遍历C盘dll文件的方法
2015/05/06 Python
Python实现处理管道的方法
2015/06/04 Python
Python实现LRU算法的2种方法
2015/06/24 Python
python中文件变化监控示例(watchdog)
2017/10/16 Python
5款非常棒的Python工具
2018/01/05 Python
Python PyInstaller安装和使用教程详解
2020/01/08 Python
python GUI库图形界面开发之PyQt5动态(可拖动控件大小)布局控件QSplitter详细使用方法与实例
2020/03/06 Python
HTML5声音录制/播放功能的实现代码
2018/05/03 HTML / CSS
详解WebSocket跨域问题解决
2018/08/06 HTML / CSS
美国知名的女性服饰品牌:LOFT(洛芙特)
2016/08/05 全球购物
Falconeri美国官网:由羊绒和羊毛制成的针织服装
2018/04/08 全球购物
英国领先的体验日提供商:Buyagift
2019/04/19 全球购物
“三支一扶”支教教师思想汇报
2014/09/13 职场文书
公司员工离职证明书
2014/10/04 职场文书
店面出租协议书范本
2014/11/28 职场文书
大学生个人简历自我评价
2015/03/11 职场文书
专家推荐信范文
2015/03/26 职场文书
2016年小学生寒假总结
2015/10/10 职场文书
php微信小程序解包过程实例详解
2021/03/31 PHP
详解nodejs内置模块
2021/05/06 NodeJs
Spring mvc是如何实现与数据库的前后端的连接操作的?
2021/06/30 Java/Android
十大最强电系宝可梦,阿尔宙斯电系之一,第七被称为雷神
2022/03/18 日漫