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 相关文章推荐
JS 获取select(多选下拉)中所选值的示例代码
Aug 02 Javascript
JavaScript中双叹号(!!)作用示例介绍
Apr 10 Javascript
JQuery控制Radio选中方法分析
May 29 Javascript
ajax读取数据后使用jqchart显示图表的方法
Jun 10 Javascript
jQuery实现首页图片淡入淡出效果的方法
Jun 10 Javascript
JavaScript判断变量是否为数组的方法(Array)
Feb 24 Javascript
jQuery Mobile 触摸事件实例
Jun 04 Javascript
javascript设计模式之模块模式学习笔记
Feb 15 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
Mar 04 Javascript
解决vue 子组件修改父组件传来的props值报错问题
Nov 09 Javascript
JavaScript实现Tab标签页切换的最简便方式(4种)
Jun 28 Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
Sep 09 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
使用 eAccelerator加速PHP代码的目的
2007/03/16 PHP
php 需要掌握的东西 不做浮躁的人
2009/12/28 PHP
php实现无限级分类(递归方法)
2015/08/06 PHP
PHP基于yii框架实现生成ICO图标
2015/11/13 PHP
PHP长连接实现与使用方法详解
2018/02/11 PHP
PhpStorm本地断点调试的方法步骤
2018/05/21 PHP
PHP swoole和redis异步任务实现方法分析
2019/08/12 PHP
幻宇的层模拟窗口效果-提供演示和下载
2007/01/20 Javascript
javascript函数以及基础写法100多条实用整理
2013/01/13 Javascript
js的onload事件及初始化按钮事件示例代码
2013/09/25 Javascript
javascript中数组中求最大值示例代码
2013/12/18 Javascript
js读取cookie方法总结
2014/10/31 Javascript
js实现简单的验证码
2015/12/25 Javascript
详解AngularJS中的filter过滤器用法
2016/01/04 Javascript
slideToggle+slideup实现手机端折叠菜单效果
2017/05/25 Javascript
JavaScript之Map和Set_动力节点Java学院整理
2017/06/29 Javascript
ReactJS实现表单的单选多选和反选的示例
2017/10/13 Javascript
微信小程序 scroll-view实现锚点滑动的示例
2017/12/06 Javascript
微信小程序拍照和摄像功能实现方法示例
2019/02/01 Javascript
利用原生JS实现data方法示例代码
2019/05/28 Javascript
微信小程序实现星级评价
2019/11/20 Javascript
vue登录页实现使用cookie记住7天密码功能的方法
2021/02/18 Vue.js
Python每天必学之bytes字节
2016/01/28 Python
python3实现读取chrome浏览器cookie
2016/06/19 Python
Python中正则表达式详解
2017/05/17 Python
Python 读写文件的操作代码
2018/09/20 Python
使用CodeMirror实现Python3在线编辑器的示例代码
2019/01/14 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
python 实现压缩和解压缩的示例
2020/09/22 Python
HTML5 canvas基本绘图之图形组合
2016/06/27 HTML / CSS
瑞典最大的儿童用品网上商店:pinkorblue.se
2021/03/09 全球购物
酒店总经理欢迎词
2014/01/08 职场文书
店长职务说明书
2014/02/04 职场文书
销售辞职信范文
2015/03/02 职场文书
2015中学教师个人工作总结
2015/07/22 职场文书
阿里面试Nacos配置中心交互模型是push还是pull原理解析
2022/07/23 Java/Android