经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
Vue中实现3D标签云的详细代码
来源:jb51  时间:2021/7/19 19:53:57  对本文有异议

预览:

代码:
页面部分:

  1. <template>
  2. <div class="tagcloud-all"
  3. ref="tagcloudall">
  4. <a v-for="item in tagList" :href="item.url" rel="external nofollow" :style="'color:' + item.color + ';top: 0;left: 0;filter:none;'">{{item.name}}</a>
  5. </div>
  6. </template>

CSS部分:

  1. // 标签云
  2. .tagcloud-all {
  3. position: relative;
  4. a {
  5. position: absolute;
  6. top: 0px;
  7. left: 0px;
  8. color: #fff;
  9. font-weight: bold;
  10. text-decoration: none;
  11. padding: 3px 6px;
  12. &:hover {
  13. color: #FF0000;
  14. letter-spacing: 2px;
  15. }
  16. }
  17. }

JS部分:

  1. export default {
  2. name: "tagcloud",
  3. data() {
  4. return {
  5. tagList: [],
  6. radius: 120,
  7. dtr: Math.PI / 180,
  8. d: 300,
  9. mcList: [],
  10. active: false,
  11. lasta: 1,
  12. lastb: 1,
  13. distr: true,
  14. tspeed: 10,
  15. size: 250,
  16. mouseX: 0,
  17. mouseY: 0,
  18. howElliptical: 1,
  19. oList: null,
  20. oA: null,
  21. sa: 0,
  22. ca: 0,
  23. sb: 0,
  24. cb: 0,
  25. sc: 0,
  26. cc: 0
  27. }
  28. },
  29. methods: {
  30. // 生成随机数
  31. getRandomNum() {
  32. return Math.floor(Math.random() * (255 + 1));
  33. },
  34. // 三角函数角度计算
  35. sineCosine(a, b, c) {
  36. this.sa = Math.sin(a * this.dtr);
  37. this.ca = Math.cos(a * this.dtr);
  38. this.sb = Math.sin(b * this.dtr);
  39. this.cb = Math.cos(b * this.dtr);
  40. this.sc = Math.sin(c * this.dtr);
  41. this.cc = Math.cos(c * this.dtr);
  42. },
  43. // 设置初始定位
  44. positionAll() {
  45. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  46. var phi = 0;
  47. var theta = 0;
  48. var max = this.mcList.length;
  49. var aTmp = [];
  50. var oFragment = document.createDocumentFragment();
  51. // 随机排序
  52. for (let i = 0; i < this.tagList.length; i++) {
  53. aTmp.push(this.oA[i]);
  54. }
  55. aTmp.sort(() => {
  56. return Math.random() < 0.5 ? 1 : -1;
  57. });
  58. for (let i = 0; i < aTmp.length; i++) {
  59. oFragment.appendChild(aTmp[i]);
  60. }
  61. this.oList.appendChild(oFragment);
  62. for (let i = 1; i < max + 1; i++) {
  63. if (this.distr) {
  64. phi = Math.acos(-1 + (2 * i - 1) / max);
  65. theta = Math.sqrt(max * Math.PI) * phi;
  66. } else {
  67. phi = Math.random() * (Math.PI);
  68. theta = Math.random() * (2 * Math.PI);
  69. }
  70. // 坐标变换
  71. this.mcList[i - 1].cx = this.radius * Math.cos(theta) * Math.sin(phi);
  72. this.mcList[i - 1].cy = this.radius * Math.sin(theta) * Math.sin(phi);
  73. this.mcList[i - 1].cz = this.radius * Math.cos(phi);
  74. this.oA[i - 1].style.left = this.mcList[i - 1].cx + this.oList.offsetWidth / 2 - this.mcList[i - 1].offsetWidth / 2 + 'px';
  75. this.oA[i - 1].style.top = this.mcList[i - 1].cy + this.oList.offsetHeight / 2 - this.mcList[i - 1].offsetHeight / 2 + 'px';
  76. }
  77. })
  78. },
  79. // 坐标更新 让标签动起来
  80. update() {
  81. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  82. var a;
  83. var b;
  84. if (this.active) {
  85. a = (-Math.min(Math.max(-this.mouseY, -this.size), this.size) / this.radius) * this.tspeed;
  86. b = (Math.min(Math.max(-this.mouseX, -this.size), this.size) / this.radius) * this.tspeed;
  87. } else {
  88. a = this.lasta * 0.98;
  89. b = this.lastb * 0.98;
  90. }
  91. this.lasta = a;
  92. this.lastb = b;
  93. if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
  94. return
  95. }
  96. var c = 0;
  97. this.sineCosine(a, b, c);
  98. for (var j = 0; j < this.mcList.length; j++) {
  99. var rx1 = this.mcList[j].cx;
  100. var ry1 = this.mcList[j].cy * this.ca + this.mcList[j].cz * (-this.sa);
  101. var rz1 = this.mcList[j].cy * this.sa + this.mcList[j].cz * this.ca;
  102. var rx2 = rx1 * this.cb + rz1 * this.sb;
  103. var ry2 = ry1;
  104. var rz2 = rx1 * (-this.sb) + rz1 * this.cb;
  105. var rx3 = rx2 * this.cc + ry2 * (-this.sc);
  106. var ry3 = rx2 * this.sc + ry2 * this.cc;
  107. var rz3 = rz2;
  108. this.mcList[j].cx = rx3;
  109. this.mcList[j].cy = ry3;
  110. this.mcList[j].cz = rz3;
  111. var per = this.d / (this.d + rz3);
  112. this.mcList[j].x = (this.howElliptical * rx3 * per) - (this.howElliptical * 2);
  113. this.mcList[j].y = ry3 * per;
  114. this.mcList[j].scale = per;
  115. this.mcList[j].alpha = per;
  116. this.mcList[j].alpha = (this.mcList[j].alpha - 0.6) * (10 / 6);
  117. }
  118. this.doPosition();
  119. this.depthSort();
  120. })
  121. },
  122. //
  123. doPosition() {
  124. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  125. var l = this.oList.offsetWidth / 2;
  126. var t = this.oList.offsetHeight / 2;
  127. for (var i = 0; i < this.mcList.length; i++) {
  128. this.oA[i].style.left = this.mcList[i].cx + l - this.mcList[i].offsetWidth / 2 + 'px';
  129. this.oA[i].style.top = this.mcList[i].cy + t - this.mcList[i].offsetHeight / 2 + 'px';
  130. this.oA[i].style.fontSize = Math.ceil(12 * this.mcList[i].scale / 2) + 8 + 'px';
  131. // this.oA[i].style.filter = "alpha(opacity=" + 100 * this.mcList[i].alpha + ")";
  132. this.oA[i].style.opacity = this.mcList[i].alpha;
  133. }
  134. })
  135. },
  136. //
  137. depthSort() {
  138. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  139. var aTmp = [];
  140. for (let i = 0; i < this.oA.length; i++) {
  141. aTmp.push(this.oA[i]);
  142. }
  143. aTmp.sort(function (vItem1, vItem2) {
  144. if (vItem1.cz > vItem2.cz) {
  145. return -1;
  146. } else if (vItem1.cz < vItem2.cz) {
  147. return 1;
  148. } else {
  149. return 0;
  150. }
  151. });
  152. for (let i = 0; i < aTmp.length; i++) {
  153. aTmp[i].style.zIndex = i;
  154. }
  155. })
  156. },
  157. // 网络请求 拿到tagList
  158. query() {
  159. // 假装从接口拿回来的数据
  160. let tagListOrg = [
  161. { name: '标签1', url: 'www.baidu.com' },
  162. { name: '标签2', url: 'www.baidu.com' },
  163. { name: '标签3', url: 'www.baidu.com' },
  164. { name: '标签4', url: 'www.baidu.com' },
  165. { name: '标签5', url: 'www.baidu.com' },
  166. { name: '标签6', url: 'www.baidu.com' },
  167. { name: '标签7', url: 'www.baidu.com' },
  168. { name: '标签8', url: 'www.baidu.com' },
  169. { name: '标签9', url: 'www.baidu.com' },
  170. { name: '标签10', url: 'www.baidu.com' },
  171. { name: '标签11', url: 'www.baidu.com' },
  172. { name: '标签12', url: 'www.baidu.com' },
  173. { name: '标签13', url: 'www.baidu.com' },
  174. { name: '标签14', url: 'www.baidu.com' },
  175. { name: '标签15', url: 'www.baidu.com' },
  176. { name: '标签16', url: 'www.baidu.com' },
  177. { name: '标签16', url: 'www.baidu.com' },
  178. { name: '标签16', url: 'www.baidu.com' },
  179. { name: '标签16', url: 'www.baidu.com' },
  180. { name: '标签16', url: 'www.baidu.com' },
  181. { name: '标签16', url: 'www.baidu.com' },
  182. { name: '标签16', url: 'www.baidu.com' },
  183. { name: '标签16', url: 'www.baidu.com' },
  184. { name: '标签16', url: 'www.baidu.com' },
  185. { name: '标签16', url: 'www.baidu.com' },
  186. { name: '标签16', url: 'www.baidu.com' },
  187. { name: '标签16', url: 'www.baidu.com' },
  188. { name: '标签16', url: 'www.baidu.com' },
  189. { name: '标签16', url: 'www.baidu.com' },
  190. { name: '标签17', url: 'www.baidu.com' }
  191. ];
  192. // 给tagList添加随机颜色
  193. tagListOrg.forEach(item => {
  194. item.color = "rgb(" + this.getRandomNum() + "," + this.getRandomNum() + "," + this.getRandomNum() + ")";
  195. })
  196. this.tagList = tagListOrg;
  197. this.onReady();
  198. },
  199. // 生成标签云
  200. onReady() {
  201. this.$nextTick(() => {
  202. this.oList = this.$refs.tagcloudall;
  203. this.oA = this.oList.getElementsByTagName('a')
  204. var oTag = null;
  205. for (var i = 0; i < this.oA.length; i++) {
  206. oTag = {};
  207. oTag.offsetWidth = this.oA[i].offsetWidth;
  208. oTag.offsetHeight = this.oA[i].offsetHeight;
  209. this.mcList.push(oTag);
  210. }
  211. this.sineCosine(0, 0, 0);
  212. this.positionAll();
  213. this.oList.onmouseover = () => {
  214. this.active = true;
  215. }
  216. this.oList.onmouseout = () => {
  217. this.active = false;
  218. }
  219. this.oList.onmousemove = (event) => {
  220. var oEvent = window.event || event;
  221.  
  222. this.mouseX = oEvent.clientX - (this.oList.offsetLeft + this.oList.offsetWidth / 2);
  223. this.mouseY = oEvent.clientY - (this.oList.offsetTop + this.oList.offsetHeight / 2);
  224. this.mouseX /= 5;
  225. this.mouseY /= 5;
  226. }
  227. setInterval(() => {
  228. this.update()
  229. }, 30); // 定时器执行 不能写setInterval(this.update(), 30)
  230. })
  231. }
  232. },
  233. created() {
  234. this.$nextTick(() => {
  235. this.query();
  236. })
  237. }
  238. }

到此这篇关于Vue中实现3D标签云的文章就介绍到这了,更多相关Vue 3D标签云内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号