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 相关文章推荐
jQuery选中select控件 无法设置selected的解决方法
Sep 01 Javascript
15款优秀的jQuery导航菜单插件分享
Jul 19 Javascript
在jquery boxy中添加百度地图坐标拾取注意流程
Apr 03 Javascript
jQuery实现的多滑动门,多选项卡效果代码
Mar 28 Javascript
JS简单去除数组中重复项的方法
Sep 13 Javascript
原生JS实现的放大镜效果实例代码
Oct 15 Javascript
JavaScript变量作用域及内存问题实例分析
Jun 10 Javascript
es6中reduce的基本使用方法
Sep 10 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
Apr 26 Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
Jul 28 Javascript
vue如何使用rem适配
Feb 06 Vue.js
TypeScript实用技巧 Nominal Typing名义类型详解
Sep 23 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
支持生僻字且自动识别utf-8编码的php汉字转拼音类
2014/06/27 PHP
PHP的运行机制与原理(底层)
2015/11/16 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
PHP爬虫之百万级别知乎用户数据爬取与分析
2016/01/22 PHP
thinkPHP的表达式查询用法详解
2016/09/14 PHP
php版微信公众平台回复中文出现乱码问题的解决方法
2016/09/22 PHP
基于JQuery的Pager分页器实现代码
2010/07/17 Javascript
jQuery 常见操作实现方式和常用函数方法总结
2011/05/06 Javascript
jquery实现隐藏与显示动画效果/输入框字符动态递减/导航按钮切换
2013/07/01 Javascript
javascript实现在网页中运行本地程序的方法
2016/02/03 Javascript
javascript使用Promise对象实现异步编程
2016/03/01 Javascript
Bootstrap模仿起筷首页效果
2016/05/09 Javascript
Extjs4.0 ComboBox如何实现三级联动
2016/05/11 Javascript
javascript 将共享属性迁移到原型中去的实现方法
2016/08/31 Javascript
bootstrap实现二级下拉菜单效果
2017/11/23 Javascript
vue学习教程之带你一步步详细解析vue-cli
2017/12/26 Javascript
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
Vue实现的父组件向子组件传值功能示例
2019/01/19 Javascript
angular 实现同步验证器跨字段验证的方法
2019/04/11 Javascript
vue单页面在微信下只能分享落地页的解决方案
2019/04/15 Javascript
Easyui 关闭jquery-easui tab标签页前触发事件的解决方法
2019/04/28 jQuery
node.JS二进制操作模块buffer对象使用方法详解
2020/02/06 Javascript
vuex(vue状态管理)的特殊应用案例分享
2020/03/03 Javascript
[01:14:10]2014 DOTA2国际邀请赛中国区预选赛 SPD-GAMING VS Orenda
2014/05/22 DOTA
python运用sklearn实现KNN分类算法
2019/10/16 Python
Tensorflow的梯度异步更新示例
2020/01/23 Python
pytorch加载自己的图像数据集实例
2020/07/07 Python
使用CSS3实现多列布局与多背景的技巧
2016/02/29 HTML / CSS
html2 canvas生成清晰的图片实现打印功能
2019/09/23 HTML / CSS
学雷锋活动总结范文
2014/04/25 职场文书
2015迎新晚会开场白
2015/05/29 职场文书
消费者理赔投诉书
2015/07/02 职场文书
又涨知识了,自律到底多重要?
2019/06/27 职场文书
PHP实现rar解压读取扩展包小结
2021/06/03 PHP
一篇文章带你学习Mybatis-Plus(新手入门)
2021/08/02 Java/Android
使用Python+OpenCV进行卡类型及16位卡号数字的OCR功能
2021/08/30 Python