环形文字旋转的实现

需求如下图:

中间的地球是个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;
}

最后实现效果如下:

相关推荐
小马哥编程1 小时前
原型链(Prototype Chain)入门
css·vue.js·chrome·node.js·原型模式·chrome devtools
cwj&xyp2 小时前
Python(二)str、list、tuple、dict、set
前端·python·算法
dlnu20152506222 小时前
ssr实现方案
前端·javascript·ssr
古木20192 小时前
前端面试宝典
前端·面试·职场和发展
轻口味4 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王4 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发4 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀5 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪5 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word