0%

程序猿的情人节怎么过?

都说程序猿是一类不解风情的生物,“赚的多,花的少,死的早”已经成为了程序猿的标志,“眼镜、格子衫、垢面蓬头、拖鞋裤衩”已然也成了程序猿的代表形象,“代码、游戏、老湿”也已经快要成了程序猿的生命。 但!有的时候,比如情人节,我们就可以发挥我们的特长了,我们程序猿也可以有自己的浪漫! 不过这个第一步是,你得有一个女朋友(哦哦,是不是可以不用往下看了? 那么有了第一步之后,下面我们应该怎么办呢? 下面介绍一个比较实用的可以送给女朋友的礼物(这其实也是我今天送给女朋友的礼物嘿嘿。 首先想想,作为程序猿,我们的专长是什么?废话,当然是代码。 有了代码,还需要送口红吗?还需要送包包吗?还需要送鲜花吗?废话,都有了代码了,这些当然就….还是要送的。万一写的代码你女朋友看不懂那岂不是死翘翘了。 好那送完了口红或包包或鲜花之后,确保已经平安无事了,我们就可以再发挥我们的光和热了(听起来咋这么奇怪呢? 进入正题,那我们可以利用代码做点什么呢?想想可以做文章的地方有什么,你们的纪念日,你们曾经做过的事情,你们在一起的时间,这些都是属于你们的独一无二的,我们可以想方设法把它们和代码联系起来。 那怎么发给女朋友看呢?做个 App、小程序、网页什么的都是可以的吧,其中网页可能是做起来最快最方便的了,然后配上一个专属域名,简直美滋滋。 好,那一想,基本方向就确定了,直接开干,接下来就描述一下我准备这个礼物的历程吧。 对于我来说,我就计划做一个网页,同时用代码的形式把和女朋友在一起的时间呈现出来,通过网页的动效来呈现我们在一起的时间,另外还计划把我们之间的故事用代码关联表示出来。 本来我打算是从零开始手撸一个的,但是一些组件比如动画特效,还有一些倒计时的组件是相对比较难做的,于是我就在 GitHub 上逛了一下,看了几个示例,找到了一个和我理想作品差不多的项目,然后在它的基础上做了一些改动,就成了最终的效果。 主要功能如下:

  • 第一是通过代码来表述出来和女朋友之间的故事。由于我和女朋友是因为 Python 认识的,而且我们两个平时都会写一些 Python,所以我决定用 Python 来写出我们之间的故事,加上 Python 的注释来辅助描述每一行代码的意义。
  • 第二是通过代码来呈现我和女朋友在一起的时间。这里就用上了一些动画特效和秒数计时方案,实时地呈现出来我和女朋友在一起已经有多久了。

最终完成之后的效果是这样子的: 预览图 然后由于我自己有一个域名,叫做 cuiqingcai.com,然后我就把它设置了二级域名解析,二级域名名称就叫做 love,域名最终就是 love.cuiqingcai.com。 最终的效果大家可以扫码或者复制链接查看一下最终的效果:http://love.cuiqingcai.com/,二维码如下: 二维码 感觉还可以吧?如果你也想送这样的礼物的话,可以根据我现有的代码来进行修改,我已经将源码放到 GitHub 了,地址为:https://github.com/Germey/ValentinesDay,大家可以修改源码,把它变成属于你和你女朋友的专属页面,然后送给女朋友。 下面说一些关键的技术和需要修改的点。

代码动画

打开页面之后,我们可以看到页面的代码是一个字一个字敲出来的,这实际上是利用了一个定时器来实现的。 首先我们可以预定义好所有的文本,然后动画播放的时候,首先把所有的文本隐藏,然后每隔几十毫秒读取一个字符,然后将其呈现出来。由于文本本身就是换行的,所以在呈现的时候就会一行一行地像打字机一样呈现出来。 另外为了模拟打字的效果,在呈现的时候可以在最后的字符后面添加一个下划线符号,模拟打字的效果。 其关键的实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(function (a) {
a.fn.typewriter = function () {
this.each(function () {
var d = a(this), c = d.html(), b = 0;
d.html("");
var e = setInterval(function () {
var f = c.substr(b, 1);
if (f == "<") {
b = c.indexOf(">", b) + 1
} else {
b++
}
d.html(c.substring(0, b) + (b & 1 ? "_" : ""));
if (b >= c.length) {
clearInterval(e)
}
}, 75)
});
return this
}
})(jQuery);

这里可以看到,首先获取了页面代码区域的内容,然后通过 DOM 操作将代码先清空,然后利用 setInterval 方法设置一个定时器,定时间隔 75 毫秒,也就是说 75 毫秒循环调用一次。每调用一次,就会从原来的字符上多取一个字符,然后尾部拼接一个下划线就好了。

代码内容

接下来就是代码内容了,这里面要想好怎样把一些关键时间来表示出来。比如和女朋友怎样认识的,后来什么时间在一起的,一起做过什么事情,将来有什么计划和打算,都可以来描述出来,另外编程语言可以选择你喜欢的语言,然后配以一定的注释来描述代码所代表的含义。 我和女朋友是在 PyCon 认识的,也算是因为 Python 结缘,然后平时我们都会写一些 Python,所以我就选用 Python 作为编程语言了。 然后我又加上了我们认识的时间、在一起的时间、一起做过的事情,然后再配以一段代码来表达自己的想法,其中的一些灵感也是我看了一些案例想出来的,在表述过程中我使用了面向对象的思维声明了两个对象,一个代表我,一个代表我女朋友,然后一起做过的事情就可以通过对象调用方法的形式来表述出来了,另外一些动作和标志可以通过自定义方法或者代码的参数来表示出来,其中每一行代码的动作我都配以一条 Python 的注释来完成,注释当然是用英文,一些话我还用了翻译软件一句句查的。 然后最后我用了一段 Python 代码来表达了自己的感情,内容如下:

1
2
3
4
5
6
# You are the greatest love of my life.
while True:
if u.with(i):
you = everything
else:
everything = u

这个代码的含义叫做“无论天涯海角,你都是我的一切。“,一个 while True 循环代表了永久。 这些代码其实都是在 HTML 代码中预定义好的,其中注释需要用 span 标签配以 comments 的 class 来修饰,缩进需要用 span 标签配以 placeholder 的 class 来修饰,例如:

1
2
3
4
5
6
<span class="comments"># You are the greatest love of my life.</span><br/>
while <span class="keyword">True</span>:<br/>
<span class="placeholder"></span><span class="keyword">if</span> u.with(i):<br/>
<span class="placeholder"></span><span class="placeholder"></span>you = everything<br/>
<span class="placeholder"></span><span class="keyword">else</span>:<br/>
<span class="placeholder"></span><span class="placeholder"></span>everything = u<br/>

这里不同的格式用 span 的不同 class 来标识,空格缩进一个 placeholder 是两个空格,comments 代表注释格式,关键词使用 keyword 来标识。如果你需要自定义自己的内容,通过控制这些内容穿插写入就好了。

纪念日计时

关于纪念日,这个实现起来其实挺简单的,就是首先定义好你们的纪念日,然后获取当前系统时间,然后计算秒数差值,然后将其转化为天数、小时数即可,关键核心代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function timeElapse(c) {
var e = Date();
var f = (Date.parse(e) - Date.parse(c)) / 1000;
var g = Math.floor(f / (3600 * 24));
f = f % (3600 * 24);
var b = Math.floor(f / 3600);
if (b < 10) {
b = "0" + b
}
f = f % 3600;
var d = Math.floor(f / 60);
if (d < 10) {
d = "0" + d
}
f = f % 60;
if (f < 10) {
f = "0" + f
}
}

另外它也是通过一个定时器来实现的时间刷新,每隔 500 毫秒调用一次:

1
2
3
setInterval(function () {
timeElapse(together);
}, 500);

动画心形

动画心形,其实这个实现起来是很巧妙的。这里在画的时候实际上是利用了贝塞尔曲线来绘制一个心形,同时在在画的过程中还加了花开的效果,花开的效果使用了随机数和随机颜色生成。 其中动画画心形的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Petal.prototype = {
draw: function () {
var a = this.bloom.garden.ctx;
var e, d, c, b;
e = new Vector(0, this.r).rotate(Garden.degrad(this.startAngle));
d = e.clone().rotate(Garden.degrad(this.angle));
c = e.clone().mult(this.stretchA);
b = d.clone().mult(this.stretchB);
a.strokeStyle = this.bloom.c;
a.beginPath();
a.moveTo(e.x, e.y);
a.bezierCurveTo(c.x, c.y, b.x, b.y, d.x, d.y);
a.stroke()
}, render: function () {
if (this.r <= this.bloom.r) {
this.r += this.growFactor;
this.draw()
} else {
this.isfinished = true
}
}
};

这里最关键的一个部分就是 bezierCurveTo,这里传入的是绘制贝塞尔曲线的参数坐标,那这些坐标怎么生成的呢,这里是利用了数学上的一个桃心线方程,如图所示: 贝塞尔曲线 其中心形线的解析方程为: 这个公式代表了绘制坐标点的 x、y 的解析方程,用代码表示出来就是:

1
2
3
4
5
6
function getHeartPoint(c) {
var b = c / Math.PI;
var a = 19.5 * (16 * Math.pow(Math.sin(b), 3));
var d = -20 * (13 * Math.cos(b) - 5 * Math.cos(2 * b) - 2 * Math.cos(3 * b) - Math.cos(4 * b));
return new Array(offsetX + a, offsetY + d)
}

这里是生产了心形线方程的 x、y 坐标,然后再以此绘制出带有动画效果的心形。 最终呈现的效果就是现在你看到的样子。 不过这些在改代码的时候实际上不用关心,只需要修改你们在一起的时间就好了,就是代码中的这一行:

1
2
together.setFullYear(2018, 10, 5);
together.setHours(15);

这里修改你们在一起的时间和小时就可以了,然后页面就会自动更新你们在一起多久了,并动态呈现出来了。

域名解析

对于域名解析,这个建议大家可以申请一个域名,比如我的域名就是 cuiqingcai.com,我可以设置一个二级域名解析,叫做 love.cuiqingcai.com。 如果没有域名的话可以现买一个,比如阿里云、腾讯云购买,然后设置解析即可。 如果没有域名,也可以使用一些虚拟云服务器,他们会帮你设置二级域名,当然也可以使用 GitHub Pages,甚至你使用 IP 地址来访问也是没问题的。

项目代码

项目的代码我都放在了:https://github.com/Germey/ValentinesDay,大家可以自行修改成想要的样子送给女朋友,只能帮你到这里啦。 嘿嘿,这就是我今天送给女朋友的礼物,女朋友收到了开心得不得了,开心。

我的礼物

其实我今天也收到了女朋友送的特殊的礼物,可以说她确实花了不少心思啊,她送了我什么呢?令我没想到的是,她居然刚申请了一个微店,然后她微店上架了好多商品,我看到时候惊呆了,店铺如图所示: image-20190214182451019 里面上架了什么商品?洗水果服务?做饭刷碗服务?捏肩膀服务?还有自动哄老婆机?我惊了。 她把商品发给我,我好奇问她这是干嘛的。 她说:要获得我的洗水果服务,捏肩膀服务,只需要在我的小店里购买使用就好了(作掐腰状)!还有自动哄老婆机,你要惹我生气了,只需要购买一个自动哄老婆机,我就会不生气了!嘿嘿合不合算? 我说:多少钱?999!这么贵的吗! 她说:当然不是啦,亲亲我们店里有活动的,使用优惠券满 999 减 998 呢,您是我的 VIP 唯一专属客户,我会给您发优惠券的呀,使用优惠券只需要一块钱就可以购买了。购买之后,您每次使用一张,我就可以给您洗水果、捏肩膀了!这个情人节的话呢,我要送亲亲 10 张!可省着点话,不能累到店长我啊! 哦哦,卧槽真牛逼啊!于是乎我就快快乐乐领取到了十张优惠券购买了女朋友的这些服务,等着时不时用一张,享受一下帝王级的待遇,美滋滋!哈哈~ 最后,祝大家情人节快乐!幸福!