对于形如以下结构的Vue单文件组件:

1
2
3
4
5
6
7
<template>
<div class="container">
</div>
</template>
<script setup>
let str = "Hello world!"
</script>

如何将其中的str字符渲染进容器中?

Vue官方的做法

通过v-for语法来循环脚本的数组即可。

1
2
3
4
5
6
7
8
<template>
<div class="container">
<span v-for="(item, index) in str" :key="index">{{item}}</span>
</div>
</template>
<script setup>
let str = "Hello world!"
</script>

自定义的做法

script标签内,通过创建虚拟节点,将字符串内容添加进虚拟节点中

若是直接通过container.appendChild(...str.split("").map(char => h("span", { class: "char" }, char)));或者container.append(...str.split("").map(char => h("span", { class: "char" }, char)));都无法达到原有的目标。

因而需要借助一个临时容器,将字符串内容添加进临时容器中,再通过container.appendChild(tempContainer);将临时容器添加进父容器中。
做法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onMounted(() => {    
// 父容器
const container = document.querySelector(".container");
// 创建字符VNode数组
let charVNodes = str.split("").map(char => h("span", { class: "char" }, char));
// 把这些字符VNode包裹在一个父VNode中,然后渲染进去
const wrapperVNode = h('div', {}, charVNodes);
// 创建一个临时容器(防止替换掉原有 DOM)
const tempDiv = document.createElement('div');
render(wrapperVNode, tempDiv);
// 把 tempDiv 内部真实 DOM 插入到目标容器中
while (tempDiv.firstChild) {
container.appendChild(tempDiv.firstChild);
}

})

通过gsap动画库的做法

GSAP 是一个高性能、跨平台的JavaScript 动画库,广泛用于网页动画的制作。 它提供了丰富的API,使得开发者可以轻松创建复杂的动画效果,并且在不同浏览器和设备上都能获得一致的性能表现。

官网

可以通过CDN来免安装使用,当然也支持npmyarn安装。可以通过将里面的gsap替换成其他组件名(如SplitText)来引入其他组件。

1
2
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/SplitText.min.js"></script>

不过这种方法需要将原来组件的str先直接渲染到页面中。

1
2
3
4
5
6
7
8
<template>
<div class="container">
{{str}}
</div>
</template>
<script setup>
let str = "Hello world!"
</script>

使用方法如下:

1
2
3
4
gsap.registerPlugin(SplitText)
let split = SplitText.create(el, {
type: "chars,words",// 或者去掉words只形成字符div
})

最后形如下所示的html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div aria-hidden="true" style="position: relative; display: inline-block;">
<div aria-hidden="true" style="position: relative; display: inline-block;">H</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">e</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">l</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">l</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">o</div>
</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">
<div aria-hidden="true" style="position: relative; display: inline-block;">w</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">o</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">r</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">l</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">d</div>
<div aria-hidden="true" style="position: relative; display: inline-block;">!</div>
</div>