环形文字旋转的实现

需求如下图:

中间的地球是个gif图哈,但是我记得通过无缝滚动也可以实现地球滚动,这里主要看的是地球周围的滚动文字,要实现这个效果,有两种方法:

  1. SVG直接绘制
  2. CSS+JS

因为我这次用的是uniapp,它老是把SVG标签内的 text 标签解析成 uni-text,跟个癫公一样,因此这里只能放弃了SVG的方案。

SVG方案

代码如下:

html 复制代码
<svg width="400" height="400">
  <path id="circlePath" d="M200,50 A150,150 0 1,1 200,349.999" fill="none" />
  <text>
    <textPath xlink:href="#circlePath">
      环形文本
    </textPath>
  </text>
</svg>

CSS+JS

实现思路

首先是一个容器view,设置为相对定位,然后内部每一个字都是一个text元素,通过绝对定位定位到同一个位置(也就是每个字都重叠在一起),然后通过js代码控制每个text元素的transform属性,最后给容器加上旋转动画即可。

实现代码

模板代码

html 复制代码
<div class="container">
	环形文字环形文字
</div>

样式代码

scss 复制代码
// 容器样式
.container {
	width: 430px;
	height: 430px;
	position: relative;
	text-align: center;
	animation: spin 20s linear infinite;
	// 文字样式
	.text {
		position: absolute;
		left: 0;
		top: 0;
		right: 0;
		bottom: 0;
		font-size: 25px;
	}
}
// 旋转动画
@keyframes spin {
	0% {
		transform: rotate(360deg);
	}
	100% {
		transform: rotate(0);
	}
}

逻辑代码

首先获取容器元素,然后复制其内部的文本,再然后将内部文本清空:

js 复制代码
const container = document.querySelector('.container')
const textContent = container.innerText
container.innerText = ''

接着遍历保存的文本内容,逐个字的遍历,每次遍历都会创建一个span元素,然后通过下标计算出其rotate的值,然后将span元素添加到容器元素中:

js 复制代码
for (let i = 0; i < textContent.length; i++) {
	const span = document.createElement('span')
	span.className = 'text'
	span.innerText = textContent[i]
	const r = i * 360 / textContent.length
	span.style.transform = `rotate(${r}deg)`
	container.appendChild(span)
}

此时在页面上就可以看到效果了:

uniapp中实现

如果是在uniapp中,可以像下面这样实现(因为我是要在移动端使用,因此尽量不操作DOM)。

模板代码

vue 复制代码
<view class="text-container">
	<template v-for="(item,index) in list">
		<view v-if="item==='n'" class="text" :style="getRoateStyle(index)">&nbsp;</view>
		<view v-else class="text" :style="getRoateStyle(index)">{{item}}</view>
	</template>
</view>

逻辑代码

首先定义一个list变量,里面存放要显示的字符:

js 复制代码
list: "nnn碎冰岛nnn雪贼岛nnn海风岛nnn费力墩补给站nnn哈尔滨补给站nnn雷霆军港nnn萨拉补给站"

这个字符串中的n是用来占位的,因为需要预留一些位置给图片。

然后定义一个getRoateStyle方法,传入index,就会返回一个计算好的动态style,如下:

js 复制代码
getRoateStyle(index) {
	const len = this.list.length
	const r = (360 / len) * index
	return {
		transform: `rotate(${r}deg)`
	}
}

此时的效果如下:

然后就到最后一步,把小岛的图片放到缝隙中,我本来是在遍历list的时候把图片给遍历出来的,结果发现,每个小岛图片的top和left值是不同的,而且是不成规律的,因此只能手写这些小岛的样式了,在模板 .text-container 中加入一个小岛的图片:

vue 复制代码
<view class="text-container">
	<!-- ... -->
	<image class="island-icon sb-island" src="/static/imgs/smartEarth/islandIcons/island1.gif" mode="aspectFill"></image>
</view>

然后手动调整位置:

css 复制代码
.island-icon {
	width: 70rpx;
	height: 70rpx;
	position: absolute;
}

// 碎冰岛
.sb-island {
	top: -20rpx;
	left: 210rpx;
}

最后实现效果如下:

相关推荐
糕冷小美n14 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥14 小时前
Technical Report 2024
java·服务器·前端
沐墨染14 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion15 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks15 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼15 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴16 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
shadow fish16 小时前
react学习记录(三)
javascript·学习·react.js
小疙瘩17 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui
Aliex_git17 小时前
浏览器 API 兼容性解决方案
前端·笔记·学习