写在前面
本来是没有准备写这个知识点,但是下载这个 js 的时候发现很多都是要钱或者是积分的,我就不明白了一个开源了这么久的 js 怎么还有人拿来挣钱的,同时还有一些只有原生 html 的例子,但是现在都是 框架主导的一些项目,显然是不行的,这篇文章就简单的写一下 怎么使用原生和 vue 分别使用 tagcloudjs 实现标签云,喜欢的可以直接拿去用,当然你也可以直接参考这个的例子写,我没有试过,但是 demo 是可行的tagcloudjs. 当然防止你们下载失败,我最后面会将源码贴出来,直接用就可以了,但是 vue 实现的和原生实现的 js 有一点点的差别,因为原来的 tagcloudjs 无法给 vue 使用。
结果展示
大概就是下面这个样子
原生代码实现
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div class="wrapper">
<div class="tagcloud fl">
<span id="pagetext">CSDN 玩家 1</span>
<span id="pagetext">CSDN 玩家 2</span>
<span id="pagetext">CSDN 玩家 3</span>
<span id="pagetext">CSDN 玩家 4</span>
<span id="pagetext">CSDN 玩家 5</span>
<span id="pagetext">CSDN 玩家 6</span>
<span id="pagetext">CSDN 玩家 7</span>
<span id="pagetext">CSDN 玩家 8</span>
<span id="pagetext">CSDN 玩家 9</span>
</div>
</div>
<script src="../assets/js/tagcloud.js"></script>
<script>
tagcloud({
selector: '.tagcloud', //元素选择器
fontsize: 16, //基本字体大小, 单位px
radius: 100, //滚动半径, 单位px
mspeed: 'normal', //滚动最大速度, 取值: slow, normal(默认), fast
ispeed: 'normal', //滚动初速度, 取值: slow, normal(默认), fast
direction: 135, //初始滚动方向, 取值角度(顺时针360): 0对应top, 90对应left, 135对应right-bottom(默认)...
keep: false //鼠标移出组件后是否继续随鼠标滚动, 取值: false, true(默认) 对应 减速至初速度滚动, 随鼠标滚动
});
</script>
</body>
<style>
.wrapper {
width: 50%;
height: 300px;
margin: 0 auto;
margin-top: 70px;
}
.tagcloud {
position: relative;
margin-top: 0px;
}
.tagcloud span {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
display: block;
padding: 11px 30px;
color: #60A2FF;
font-size: 16px;
border: 1px solid #e6e7e8;
border-radius: 18px;
background-color: #f2f4f8;
text-decoration: none;
white-space: nowrap;
-o-box-shadow: 6px 4px 8px 0 rgba(151, 142, 136, .34);
-ms-box-shadow: 6px 4px 8px 0 rgba(151, 142, 136, .34);
-moz-box-shadow: 6px 4px 8px 0 rgba(151, 142, 136, .34);
-webkit-box-shadow: 6px 4px 8px 0 rgba(151, 142, 136, .34);
box-shadow: 6px 4px 8px 0 rgba(151, 142, 136, .34);
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4,Direction=135, Color='#000000')";
/*兼容ie7/8*/
filter: progid:DXImageTransform.Microsoft.Shadow(color='#969696', Direction=125, Strength=9);
/*strength是阴影大小,direction是阴影方位,单位为度,可以为负数,color是阴影颜色 (尽量使用数字)使用IE滤镜实现盒子阴影的盒子必须是行元素或以行元素显示(block或inline-block;)*/
}
.tagcloud a:hover {
color: #3385cf;
}
</style>
</html>
给原生 HTML 实现用的tagcloud.js源码
js
/*
* 3d标签云
* 功能:鼠标移入标签,当前标签静止放大
* 说明:
* */
window.tagcloud = (function(win, doc) { // ns
// 判断对象
function isObject (obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
// 构造函数
function TagCloud (options) {
var self = this;
self.config = TagCloud._getConfig(options);
self.box = self.config.element; //组件元素
self.fontsize = self.config.fontsize; //平均字体大小
self.radius = self.config.radius; //滚动半径
self.depth = 2 * self.radius; //滚动深度
self.size = 2 * self.radius; //随鼠标滚动变速作用区域
self.mspeed = TagCloud._getMsSpeed(self.config.mspeed);
self.ispeed = TagCloud._getIsSpeed(self.config.ispeed);
self.items = self._getItems();
self.direction = self.config.direction; //初始滚动方向
self.keep = self.config.keep; //鼠标移出后是否保持之前滚动
//初始化
self.active = false; //是否为激活状态
self.lasta = 1;
self.lastb = 1;
self.mouseX0 = self.ispeed * Math.sin(self.direction * Math.PI / 180); //鼠标与滚动圆心x轴初始距离
self.mouseY0 = -self.ispeed * Math.cos(self.direction * Math.PI / 180); //鼠标与滚动圆心y轴初始距离
self.mouseX = self.mouseX0; //鼠标与滚动圆心x轴距离
self.mouseY = self.mouseY0; //鼠标与滚动圆心y轴距离
self.index = -1;
//鼠标移入
TagCloud._on(self.box, 'mouseover', function () {
self.active = true;
});
//鼠标移出
TagCloud._on(self.box, 'mouseout', function () {
self.active = false;
});
//鼠标在内移动
TagCloud._on(self.keep ? win : self.box, 'mousemove', function (ev) {
var oEvent = win.event || ev;
var boxPosition = self.box.getBoundingClientRect();
self.mouseX = (oEvent.clientX - (boxPosition.left + self.box.offsetWidth / 2)) / 5;
self.mouseY = (oEvent.clientY - (boxPosition.top + self.box.offsetHeight / 2)) / 5;
});
for (var j = 0, len = self.items.length; j < len; j++) {
self.items[j].element.index=j;
//鼠标移出子元素,当前元素静止放大
self.items[j].element.onmouseover = function(){
self.index = this.index;
};
//鼠标移出子元素,当前元素继续滚动
self.items[j].element.onmouseout = function(){
self.index = -1;
};
}
//定时更新
TagCloud.boxs.push(self.box);
self.update(self); //初始更新
self.box.style.visibility = "visible";
self.box.style.position = "relative";
self.box.style.minHeight = 1.2 * self.size + "px";
self.box.style.minWidth = 2.5 * self.size + "px";
for (var j = 0, len = self.items.length; j < len; j++) {
self.items[j].element.style.position = "absolute";
self.items[j].element.style.zIndex = j + 1;
}
self.up = setInterval(function() {
self.update(self);
}, 30);
}
//实例
TagCloud.boxs = []; //实例元素数组
// 静态方法们
TagCloud._set = function (element) {
if (TagCloud.boxs.indexOf(element) == -1) {//ie8不支持数组的indexOf方法
return true;
}
};
//添加数组IndexOf方法
if (!Array.prototype.indexOf){
Array.prototype.indexOf = function(elt /*, from*/){
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++){
if (from in this && this[from] === elt)
return from;
}
return -1;
};
}
TagCloud._getConfig = function (config) {
var defaultConfig = { //默认值
fontsize: 16, //基本字体大小, 单位px
radius: 60, //滚动半径, 单位px
mspeed: "normal", //滚动最大速度, 取值: slow, normal(默认), fast
ispeed: "normal", //滚动初速度, 取值: slow, normal(默认), fast
direction: 135, //初始滚动方向, 取值角度(顺时针360): 0对应top, 90对应left, 135对应right-bottom(默认)...
keep: true //鼠标移出组件后是否继续随鼠标滚动, 取值: false, true(默认) 对应 减速至初速度滚动, 随鼠标滚动
};
if(isObject(config)) {
for(var i in config) {
if(config.hasOwnProperty(i)) {//hasOwnProperty()用来判断一个属性是定义在对象本身而不是继承自原型链
defaultConfig[i] = config[i]; //用户配置
}
}
}
return defaultConfig;// 配置 Merge
};
TagCloud._getMsSpeed = function (mspeed) { //滚动最大速度
var speedMap = {
slow: 1.5,
normal: 3,
fast: 5
};
return speedMap[mspeed] || 3;
};
TagCloud._getIsSpeed = function (ispeed) { //滚动初速度
var speedMap = {
slow: 10,
normal: 25,
fast: 50
};
return speedMap[ispeed] || 25;
};
TagCloud._getSc = function(a, b) {
var l = Math.PI / 180;
//数组顺序0,1,2,3表示asin,acos,bsin,bcos
return [
Math.sin(a * l),
Math.cos(a * l),
Math.sin(b * l),
Math.cos(b * l)
];
};
TagCloud._on = function (ele, eve, handler, cap) {
if (ele.addEventListener) {
ele.addEventListener(eve, handler, cap);
} else if (ele.attachEvent) {
ele.attachEvent('on' + eve, handler);
} else {
ele['on' + eve] = handler;
}
};
// 原型方法
TagCloud.prototype = {
constructor: TagCloud, // 反向引用构造器
update: function () {
var self = this, a, b;
if (!self.active && !self.keep) {
self.mouseX = Math.abs(self.mouseX - self.mouseX0) < 1 ? self.mouseX0 : (self.mouseX + self.mouseX0) / 2; //重置鼠标与滚动圆心x轴距离
self.mouseY = Math.abs(self.mouseY - self.mouseY0) < 1 ? self.mouseY0 : (self.mouseY + self.mouseY0) / 2; //重置鼠标与滚动圆心y轴距离
}
a = -(Math.min(Math.max(-self.mouseY, -self.size), self.size) / self.radius ) * self.mspeed;
b = (Math.min(Math.max(-self.mouseX, -self.size), self.size) / self.radius ) * self.mspeed;
if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) { return; }
self.lasta = a;
self.lastb = b;
var sc = TagCloud._getSc(a, b);
for (var j = 0, len = self.items.length; j < len; j++) {
var rx1 = self.items[j].x,
ry1 = self.items[j].y*sc[1] + self.items[j].z*(-sc[0]),
rz1 = self.items[j].y*sc[0] + self.items[j].z*sc[1];
var rx2 = rx1 * sc[3] + rz1 * sc[2],
ry2 = ry1,
rz2 = rz1 * sc[3] - rx1 * sc[2];
if(self.index==j){
self.items[j].scale = 1; //取值范围0.6 ~ 3
self.items[j].fontsize = 16;
self.items[j].alpha = 1;
self.items[j].element.style.zIndex = 99;
}else{
var per = self.depth / (self.depth + rz2);
self.items[j].x = rx2;
self.items[j].y = ry2;
self.items[j].z = rz2;
self.items[j].scale = per; //取值范围0.6 ~ 3
self.items[j].fontsize = Math.ceil(per * 2) + self.fontsize - 6;
self.items[j].alpha = 1.5 * per - 0.5;
self.items[j].element.style.zIndex = Math.ceil(per*10-5);
}
self.items[j].element.style.fontSize = self.items[j].fontsize + "px";
self.items[j].element.style.left = self.items[j].x + (self.box.offsetWidth - self.items[j].offsetWidth) / 2 + "px";
self.items[j].element.style.top = self.items[j].y + (self.box.offsetHeight - self.items[j].offsetHeight) / 2 + "px";
self.items[j].element.style.filter = "alpha(opacity=" + 100 * self.items[j].alpha + ")";
self.items[j].element.style.opacity = self.items[j].alpha;
}
},
_getItems: function () {
var self = this,
items = [],
element = self.box.children, // children 全部是Element
length = element.length,
item;
for (var i = 0; i < length; i++) {
item = {};
item.angle = {};
item.angle.phi = Math.acos(-1 + (2 * i + 1) / length);
item.angle.theta = Math.sqrt((length + 1) * Math.PI) * item.angle.phi;
item.element = element[i];
item.offsetWidth = item.element.offsetWidth;
item.offsetHeight = item.element.offsetHeight;
item.x = self.radius * 1.5 * Math.cos(item.angle.theta) * Math.sin(item.angle.phi);
item.y = self.radius * 1.5 * Math.sin(item.angle.theta) * Math.sin(item.angle.phi);
item.z = self.radius * 1.5 * Math.cos(item.angle.phi);
item.element.style.left = item.x + (self.box.offsetWidth - item.offsetWidth) / 2 + "px";
item.element.style.top = item.y + (self.box.offsetHeight - item.offsetHeight) / 2 + "px";
items.push(item);
}
return items; //单元素数组
}
};
if (!doc.querySelectorAll) {//ie7不支持querySelectorAll,所以要重新定义
doc.querySelectorAll = function (selectors) {
var style = doc.createElement('style'), elements = [], element;
doc.documentElement.firstChild.appendChild(style);
doc._qsa = [];
style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
window.scrollBy(0, 0);
style.parentNode.removeChild(style);
while (doc._qsa.length) {
element = doc._qsa.shift();
element.style.removeAttribute('x-qsa');
elements.push(element);
}
doc._qsa = null;
return elements;
};
}
return function (options) { // factory
options = options || {}; // 短路语法
var selector = options.selector || '.tagcloud', //默认选择class为tagcloud的元素
elements = doc.querySelectorAll(selector),
instance = [];
for (var index = 0, len = elements.length; index < len; index++) {
options.element = elements[index];
if (!!TagCloud._set(options.element)) {
instance.push(new TagCloud(options));
}
}
return instance;
};
})(window, document);
vue 实现
vue
<template>
<div class="tagcloud">
<span v-for="i in 10">CSDN 玩家{{ i}}</span>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { tagcloud } from '../../src/assets/tagcloud.js'
onMounted(() => {
tagcloud({
selector: '.tagcloud', //元素选择器
fontsize: 16, //基本字体大小, 单位px
radius: 100, //滚动半径, 单位px
mspeed: 'normal', //滚动最大速度, 取值: slow, normal(默认), fast
ispeed: 'normal', //滚动初速度, 取值: slow, normal(默认), fast
direction: 135, //初始滚动方向, 取值角度(顺时针360): 0对应top, 90对应left, 135对应right-bottom(默认)...
keep: false //鼠标移出组件后是否继续随鼠标滚动, 取值: false, true(默认) 对应 减速至初速度滚动, 随鼠标滚动
});
})
</script>
- style 同原生的一致,这里不贴代码了,避免文章太长你们看着烦
给 vue 实现用的 tagcloud.js
js
export const tagcloud = (function (win = window, doc = document)
将原生js 中的第一行代码改为上面的即可,将 tagcloud 导出去就可以给 vue 直接使用了,这里需要注意的一点是用的时候需要保证页面DOM 元素全部加载结束再执行 tagcloud 的方法,否则是无法加载出来的,这个和 echartsjs 用法是保持一致的,因为这些图形类的 js 使用的前提条件就是你的 DOM 元素需要存在,否则都是徒劳,当你没有效果的时候检查一下是不是 DOM 加载失败了或者是没有加载出来即可
写在后面
以上就是关于 tagcloudjs 用法的讲解了,整好最近我手里有需求需要用到这块,顺手将这个分享出去,大家用的时候有什么问题随时下面留言即可!