马黑黑 发表于 2022-7-8 12:15

CSS+JS:文本散聚

<style>
#papa {
        margin: auto;
        width: 720px;
        height: 560px;
        box-shadow: 4px 4px 24px #000;
        position: relative;
}
#txtbox {
        position: absolute;
        right: 50px;
        top: 50px;
        cursor: pointer;
}
.piece {
        position: absolute;
        font: normal 35px / 40px sans-serif; /* 重要 : JS参考行高值,修改时需同步修改 lineHeight 变量 */
        text-shadow: 1px 1px 2px rgba(0,0,0,.8);
        user-select: none;
        transition: all 1.2s;
}
</style>

<div id="papa">
        <div id="txtbox"></div>
</div>

<script>
let txt = '君问归期未有期,巴山夜雨涨秋池。何当共剪西窗烛,却话巴山夜雨时。';
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;
breakup(txt,txtbox);
let pieces = document.querySelectorAll('.piece');
txtbox.onmousemove = () => pieces.forEach((ele) => ele.style.transform = 'rotate(0deg) translate(0px,0px)');
txtbox.onmouseout = () => pieces.forEach((ele) => ele.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-20,20)}px,${num(-20,20)}px)`);

function breakup(text,ele) {
        let txtAr = text.split('');
        let lineChars = 8, lineHeight = 40; //lineChars : 每行字数,liengHeight : 行高(依据CSS设定的行高)
        ele.style.width = lineChars * lineHeight + 'px';
        ele.style.height = Math.ceil(txtAr.length / lineChars) * lineHeight + 'px';
        txtAr.forEach((e,k) => {
                let span = document.createElement('span');
                span.className = 'piece';
                span.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-30,30)}px,${num(-30,30)}px)`;
                span.style.color = `rgb(${num(0,255)},${num(0,255)},${num(0,255)})`;
                span.innerText = e;
                span.style.left =(k % lineChars) * lineHeight + 'px';
                span.style.top = Math.floor(k / lineChars) * lineHeight + 'px';
                ele.appendChild(span);
        });
}
</script>

马黑黑 发表于 2022-7-8 12:16

代码:
<style>
#papa {
        margin: auto;
        width: 720px;
        height: 560px;
        box-shadow: 4px 4px 24px #000;
        position: relative;
}
#txtbox {
        position: absolute;
        right: 50px;
        top: 50px;
        cursor: pointer;
}
.piece {
        position: absolute;
        font: normal 35px / 40px sans-serif; /* 重要 : JS参考行高值,修改时需同步修改 lineHeight 变量 */
        text-shadow: 1px 1px 2px rgba(0,0,0,.8);
        user-select: none;
        transition: all 1.2s;
}
</style>

<div id="papa">
        <div id="txtbox"></div>
</div>

<script>
let txt = '君问归期未有期,巴山夜雨涨秋池。何当共剪西窗烛,却话巴山夜雨时。';
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;
breakup(txt,txtbox);
let pieces = document.querySelectorAll('.piece');
txtbox.onmousemove = () => pieces.forEach((ele) => ele.style.transform = 'rotate(0deg) translate(0px,0px)');
txtbox.onmouseout = () => pieces.forEach((ele) => ele.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-20,20)}px,${num(-20,20)}px)`);

function breakup(text,ele) {
        let txtAr = text.split('');
        let lineChars = 8, lineHeight = 40; //lineChars : 每行字数,liengHeight : 行高(依据CSS设定的行高)
        ele.style.width = lineChars * lineHeight + 'px';
        ele.style.height = Math.ceil(txtAr.length / lineChars) * lineHeight + 'px';
        txtAr.forEach((e,k) => {
                let span = document.createElement('span');
                span.className = 'piece';
                span.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-30,30)}px,${num(-30,30)}px)`;
                span.style.color = `rgb(${num(0,255)},${num(0,255)},${num(0,255)})`;
                span.innerText = e;
                span.style.left =(k % lineChars) * lineHeight + 'px';
                span.style.top = Math.floor(k / lineChars) * lineHeight + 'px';
                ele.appendChild(span);
        });
}
</script>


马黑黑 发表于 2022-7-8 12:17

本帖最后由 马黑黑 于 2022-7-8 13:27 编辑

代码解释:

一、CSS部分

共三个 选择器:
① #papa

position: relative; 必须。这是父盒子样式,定位规矩。

② #txtbox

用于装载文本的爷爷元素(文本将逐字拆分装一一进 span 标签)。position: absulte; 必须,为其在父盒子 #papa 中定位提供条件。本例,将之定位在右上角,高宽不设定,将由JS根据字数、行数完成。

③ .piece

span 标签所依托的类选择器。绝对定位:必须。font属性的设定至关重要,行高要略大于文本大小,行高也将是JS进行相关计算的主要依据。transition的定义也重要,是JS设定的鼠标滑入滑出的变化时长与态势。

二、HTML部分(简单的,无需解释)

三、JS部分

难度不大,但需要JS基础。这里就简单解释一下:

① let txt = '君问归期未有期,巴山夜雨涨秋池。何当共剪西窗烛,却话巴山夜雨时。';

把要输出的文本赋值给 txt 变量。

② let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;

这其实是一个自定义函数,在 min 和 max 两个数之间随机取整数。

③ breakup(txt,txtbox);

执行后面定义的自定义函数 breakup(),两个参数,参数一是待处理的文本串,参数二是文本的爷爷元素。函数后面再解释。

④ let pieces = document.querySelectorAll('.piece');

获得所有的类名为 .piece 的 span 标签(单字的容器),数组。

⑤ txtbox.onmousemove = () => pieces.forEach((ele) => ele.style.transform = 'rotate(0deg) translate(0px,0px)');

文本爷爷元素鼠标经过时的事件: 让文本回归初始位置(之前它们随机 rotate 和 translate过)。

⑥ txtbox.onmouseout = () => pieces.forEach((ele) => ele.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-20,20)}px,${num(-20,20)}px)`);

文本爷爷元素鼠标滑出时的事件: 让文本随机 rotate 和 translate。其实是文本是跟着爸爸变。

⑦ function breakup(text,ele) 函数(通过逐行注释解释):

function breakup(text,ele) { //text:待处理文本串,ele:文本爷爷容器
      let txtAr = text.split(''); //拆分字符串并赋值给数组变量 txtAr
      let lineChars = 8, lineHeight = 40; //lineChars : 每行字数,liengHeight : 行高(依据CSS设定的行高)
      ele.style.width = lineChars * lineHeight + 'px'; // 爷爷容器的宽度 字数乘以行高(行高与字宽基本一致)
      ele.style.height = Math.ceil(txtAr.length / lineChars) * lineHeight + 'px'; // 爷爷容器的高度 总字数除以每行字数且往上要整数(如 4.1视为5)
      txtAr.forEach((e,k) => { // 遍历每一个字
                let span = document.createElement('span'); // 每一个字创建一个 span
                span.className = 'piece'; // span 的CSS类名
                span.style.transform = `rotate(${num(-180,180)}deg) translate(${num(-30,30)}px,${num(-30,30)}px)`; // 随机旋转、移动(rotate 放在translate的前面会产生移位,转动的随机角度设定再 -180 至 180之间,移位的随机数设定再 -30到30之间)
                span.style.color = `rgb(${num(0,255)},${num(0,255)},${num(0,255)})`; // 每 span 的前景色(随机)
                span.innerText = e; // 每一个 span 的字
                span.style.left =(k % lineChars) * lineHeight + 'px'; // 每一个 span 的left值,计算依据:第 k 个字 的 k,取每行字数的余数,然后乘以行高(即字宽)
                span.style.top = Math.floor(k / lineChars) * lineHeight + 'px'; // 每一个 span 的top值,计算依据:第 k 个字的 k,除以每行字数并向下取整(例如 4.1 视为4),然后再乘以行高。
                ele.appendChild(span); // 爷爷元素追加爸爸元素(爸爸已经把每一个字都安排好,爸爸的各种属性也都已经高清楚)
      });
}


就酱,有啥再说。

马黑黑 发表于 2022-7-8 13:28

无序之美在于,它是有序的好的反证。

——马黑

红影 发表于 2022-7-8 13:41

马黑黑 发表于 2022-7-8 13:28
无序之美在于,它是有序的好的反证。

——马黑

这还带马黑语录的呢{:4_173:}

红影 发表于 2022-7-8 13:41

马黑黑 发表于 2022-7-8 13:28
无序之美在于,它是有序的好的反证。

——马黑

把好好的诗词变得像一堆碎纸屑一样,你还说它美{:4_196:}

红影 发表于 2022-7-8 13:42

不过好神奇啊,鼠标滑过,整整齐齐的诗词就出来了{:4_187:}

马黑黑 发表于 2022-7-8 19:24

红影 发表于 2022-7-8 13:42
不过好神奇啊,鼠标滑过,整整齐齐的诗词就出来了

这是JS mousemove 和 mouseout 事件共同完成的,等同于 CSS 的 hover,不过二者是有区别的,JS的东东可以更强大

马黑黑 发表于 2022-7-8 19:24

红影 发表于 2022-7-8 13:41
这还带马黑语录的呢

挺好的

马黑黑 发表于 2022-7-8 19:24

红影 发表于 2022-7-8 13:41
把好好的诗词变得像一堆碎纸屑一样,你还说它美

美总是相对的

红影 发表于 2022-7-8 21:40

马黑黑 发表于 2022-7-8 19:24
这是JS mousemove 和 mouseout 事件共同完成的,等同于 CSS 的 hover,不过二者是有区别的,JS的东东可以 ...

可以调得更细致吧。

红影 发表于 2022-7-8 21:41

马黑黑 发表于 2022-7-8 19:24
美总是相对的

哈哈,开始真的看不出是诗词呢{:4_173:}

马黑黑 发表于 2022-7-8 21:52

红影 发表于 2022-7-8 21:41
哈哈,开始真的看不出是诗词呢

这个特效还是很有创意的

马黑黑 发表于 2022-7-8 21:53

红影 发表于 2022-7-8 21:40
可以调得更细致吧。

JS能调CSS跳不出的东东

红影 发表于 2022-7-9 12:01

马黑黑 发表于 2022-7-8 21:52
这个特效还是很有创意的

可以玩猜诗词了,不准用鼠标去划,让人猜猜诗词的内容是什么{:4_173:}

红影 发表于 2022-7-9 12:02

马黑黑 发表于 2022-7-8 21:53
JS能调CSS跳不出的东东

真棒{:4_187:}

马黑黑 发表于 2022-7-9 12:08

红影 发表于 2022-7-9 12:01
可以玩猜诗词了,不准用鼠标去划,让人猜猜诗词的内容是什么

这个可以玩玩

红影 发表于 2022-7-10 16:13

马黑黑 发表于 2022-7-9 12:08
这个可以玩玩

但越是不准的事,越是会让人忍不住去点的{:4_189:}

马黑黑 发表于 2022-7-10 17:04

红影 发表于 2022-7-10 16:13
但越是不准的事,越是会让人忍不住去点的

这心理学也学的挺好

红影 发表于 2022-7-10 21:32

马黑黑 发表于 2022-7-10 17:04
这心理学也学的挺好

没学过,我只是凭自己感觉{:4_189:}
页: [1] 2
查看完整版本: CSS+JS:文本散聚