文章目录
因为之前觉得这个打字特效很好玩,但是字数不一样就要重写或者改代码,麻烦,之前就看到网上有一些自动生成代码的工具,很好奇怎么实现的?于是我就想能不能自己也写一个自动生成代码的网页,别光想,戴上耳机,音乐陪伴,行动起来,30分钟,完成了下面的300行代码,实现了这个功能,通过这个,你大概就能理解一些所谓简单复杂的工具,其实也不过如此,你也可以🏄🏼
先写个打字特效
首先先写一个固定字长的打字特效,这就很easy了,思路就是使用
ch
单位,1ch表示一个字长,再借助等宽字体,开局宽度0ch
,动画过渡到字长,借助伪元素实现打字时的小横杠,这里使用了 css 变量,因为方便后期对变量的替换以及维护,推荐👍🏼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>typora</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="https://img.fy6b.com/2022/04/26/f8fd03d60efd6.png" type="image/x-icon">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--Length: 6ch;
--num: 6;
--Time: 3s;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
p {
position: relative;
font-size: 60px;
font-family: monospace;
width: 0ch;
overflow: hidden;
white-space: nowrap;
animation: Lengthen var(--Time) steps(var(--num)) forwards;
}
p::after {
content: "";
position: absolute;
right: 0;
width: 2px;
height: 100%;
background-color: #454545;
animation: Flash 1s infinite;
}
@keyframes Lengthen {
to {
width: var(--Length);
}
}
@keyframes Flash {
50% {
background-color: transparent;
}
}
</style>
</head>
<body>
<p>typora</p>
</body>
</html>
借助Vue完成变量的替换
接下来就是重点了,这里我使用了Vue框架,更快速点,原生js一样的,重点是获取css变量,根据输入的length为css变量从新赋值,然后通过字符串拼接,完成代码的重用,可能很笨,但说起来只能这样,哈哈,还有就是点击复制这个实现,通过input框,这里切记不要使用display隐藏input,而是使用opacity = 进行隐藏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>在线生成打字特效</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="http://zhouql.vip/images/ali/键盘,打字.png" type="image/x-icon">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
}
:root {
--Length: 24ch;
--num: 24;
--Time: 4s;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.inputText {
display: flex;
align-items: center;
justify-content: center;
width: 90%;
margin: 15px auto;
}
input {
outline: none;
width: calc(100% - 90px);
height: 40px;
text-indent: .3em;
font-size: 14px;
font-family: "Microsoft YaHei UI Light";
letter-spacing: .1em;
border: 1px solid #69F;
border-right: transparent;
border-radius: 5px 0 0 5px;
}
button {
border: none;
background-color: #69F;
height: 40px;
width: 90px;
color: #FFF;
letter-spacing: .1em;
padding: 5px;
font-size: 16px;
border-radius: 0 5px 5px 0;
cursor: pointer;
outline: none;
font-family: "Microsoft YaHei UI Light";
}
.code {
position: relative;
width: 90%;
height: 30px;
background-color: transparent;
overflow: auto;
}
p {
position: relative;
font-size: 20px;
font-family: monospace;
width: 0ch;
overflow: hidden;
white-space: nowrap;
animation: Lengthen var(--Time) steps(var(--num)) forwards;
}
p::after {
content: "";
position: absolute;
right: 0;
width: 2px;
height: 100%;
background-color: #454545;
animation: Flash 1s infinite;
}
@keyframes Lengthen {
to {
width: var(--Length);
}
}
@keyframes Flash {
50% {
background-color: transparent;
}
}
.co {
position: relative;
width: 90%;
height: calc(100vh - 250px);
overflow: auto;
border: 1px solid pink;
}
.co .copyButton {
position: absolute;
width: 80px;
height: 30px;
border-radius: 0px;
top: 5px;
right: 8px;
font-size: 13px;
}
.preView {
width: 90%;
display: inline-block;
text-align: left;
padding: 10px 1px;
font-size: 15px;
color: #555;
}
footer {
position: absolute;
bottom: 0px;
width: 100%;
height: 30px;
background-color: #f3f3f3;
display: flex;
align-items: center;
justify-content: center;
}
footer span {
font-size: 12px;
color: #999;
}
footer span a {
text-decoration: none;
color: #008600;
}
[v-clock] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<div class="inputText">
<input autofocus @input="cleanCode" maxlength="28" type="text" placeholder="输入字" v-model="typing">
<button @click="generateCode">生成代码</button>
</div>
<span class="preView" v-show="flag">预览</span>
<div class="code" v-show="flag">
<p>{{zi}}</p>
</div>
<span class="preView viewCode" v-show="flag">源码</span>
<div class="co" v-show="flag">
<button class="copyButton" @click="copyCode">点击复制</button>
<pre>
<code v-cloak id="copyCodeAll">
{{daziCode}}
</code>
</pre>
</div>
<input type="text" class="preCopyCode" style="opacity: 0;">
<footer>
<span>学习使用,豫备案号 <a href="https://seo.chinaz.com/zhouql.vip">zhouql.vip</a></span>
</footer>
</div>
<!--引入Vue2-->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!--创建Vue实例对象-->
<script>
const vm = new Vue({
el: '#app',
data: {
//要打的字
typing: 'I Love You zhang yu miao',
//决定显示还是隐藏
flag:false,
zi: '',
//待复制的代码
preCopyCode:''
},
computed: {
daziCode() {
return '\n' +
'<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <title>'+this.typing+'</title>\n' +
' <meta http-equiv="X-UA-Compatible" content="IE=edge">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <link rel="shortcut icon" href="https://img.fy6b.com/2022/04/26/f8fd03d60efd6.png" type="image/x-icon">\n' +
' <style>\n' +
' * {\n' +
' margin: 0;\n' +
' padding: 0;\n' +
' box-sizing: border-box;\n' +
' }\n' +
'\n' +
' :root {\n' +
' --Length: '+this.typing.length+'ch;\n' +
' --num: '+this.typing.length+';\n' +
' --Time: '+(this.typing.length * 0.5)+'s;\n' +
' }\n' +
'\n' +
' body {\n' +
' display: flex;\n' +
' align-items: center;\n' +
' justify-content: center;\n' +
' min-height: 100vh;\n' +
' }\n' +
'\n' +
' p {\n' +
' position: relative;\n' +
' font-size: 60px;\n' +
' font-family: monospace;\n' +
' width: 0ch;\n' +
' overflow: hidden;\n' +
' white-space: nowrap;\n' +
' animation: Lengthen var(--Time) steps(var(--num)) forwards;\n' +
' }\n' +
'\n' +
' p::after {\n' +
' content: "";\n' +
' position: absolute;\n' +
' right: 0;\n' +
' width: 2px;\n' +
' height: 100%;\n' +
' background-color: #454545;\n' +
' animation: Flash 1s infinite;\n' +
' }\n' +
'\n' +
' @keyframes Lengthen {\n' +
' to {\n' +
' width: var(--Length);\n' +
' }\n' +
' }\n' +
'\n' +
' @keyframes Flash {\n' +
' 50% {\n' +
' background-color: transparent;\n' +
' }\n' +
' }\n' +
' </style>\n' +
'</head>\n' +
'<body>\n' +
'<p>'+this.typing+'</p>\n' +
'</body>\n' +
'</html>\n'
}
},
methods: {
generateCode() {
this.zi = this.typing;
document.documentElement.style.setProperty("--Length", (this.typing.length) + 'ch');
document.documentElement.style.setProperty("--num", this.typing.length + "");
document.documentElement.style.setProperty("--Time", this.typing.length * 0.4 + "s");
if (this.typing.length != 0) {
this.flag = true;
}
},
cleanCode() {
this.flag = false;
this.typing = this.typing.replace(/[^a-zA-Z .() 0-9;:""?{}=+-]/g, '');
},
copyCode() {
let code = document.querySelector(".preCopyCode");
code.value = this.daziCode;
code.select();
document.execCommand("Copy");
alert("复制成功")
}
}
})
</script>
</body>
</html>