「用技术创造浪漫」前端工程师示爱指南❤️

简介: 「用技术创造浪漫」前端工程师示爱指南❤️

前奏 🎵


前几天在知乎看到了一些代码情书,就像这种:


#倘若你回首看看我
ifyou.turn_round_aguang()
#我永远在你背后
I.behind(you).forever()
#关注着你
see(you)


其实萌生了总结前端示爱方式的想法,可是看了半天,觉得也就普普通通,甚至有很多示爱小程序给我一种 2000 年代的感觉,比如这个:


网络异常,图片无法展示
|


于是我就有了一个想法,自己动手做一个,寒草设计并动手实现的前端工程师特制。


间奏 🎵


网络异常,图片无法展示
|


本章涵盖以下内容:

  • 从效果看设计
  • 讲述效果的实现方式

下面,我们开始本文的主要内容。


设计 🤔


网络异常,图片无法展示
|


页面分为两部分

  • 左侧的类终端窗口
  • 右侧的效果显示区


类终端窗口

  • 要有彩蛋
  • 要和右侧效果区呼应


效果显示区

  • 倒计时 ⏰
  • 心 ❤️
  • 奇特的弹幕 📖
  • 月亮 🌛
  • 雨落在水面的涟漪 🌧️
  • 彩色的雨 🌈


开发 😪

将事件串联起来 —— Deferred


首先,我需要把事件串联起来,而这个动画中的事件比较复杂,需要把这些事件串联起来,总不能用 setTimeout 回调函数进行嵌套,那样会十分恶心并且不利于管理,于是我使用了 Deferred:


function Deferred() {
  if (typeof (Promise) != 'undefined' && Promise.defer) {
    return Promise.defer();
  } else if (this && this instanceof Deferred) {
    this.resolve = null;
    this.reject = null;
    const _this = this;
    this.promise = new Promise((resolve, reject) => {
      _this.resolve = resolve;
      _this.reject = reject;
    });
    Object.freeze(this);
  } else {
    throw new Error();
  }
}


说白了就是把 promise 中的 resolve 和 reject 拿出来,用了之后我这套事件顺序就会比较连贯:


stepWord('致 9.15', 'rgb(228, 231, 12)')
    .then(() => stepWord('开始倒计时', '#c1e8fa'))
    .then(() => stepWord('start the countdown', '#db61ac'))
    .then(() => stepSpace())
    .then(() => stepWord('🌟🌟🌟🌟🌟🌟'))
    .then(() => stepSpace())
    .then(() => stepTime())
    .then(() => stepWord('心跳加速,藏獒开始进化', '#c1e8fa'))
    .then(() => stepWord('The heart rate quickens and the Tibetan mastiff begins to evolve.', '#db61ac'))
    .then(() => stepSpace())
    .then(() => stepWord('🐶🐶🐶🐶🐶🐶'))
    .then(() => stepSpace())
    .then(() => stepDown())
    .then(() => stepWord('致 9.21', 'rgb(228, 231, 12)'))
    .then(() => stepWord('但愿人长久,千里共婵娟', '#c1e8fa'))
    .then(() => stepWord('you are my fairy forever', 'red'))
    .then(() => stepSpace())
    .then(() => stepWord('🌛🌛🌛🌛🌛🌛'))
    .then(() => stepSpace())
    .then(() => stepMoon())
    .then(() => stepWord('大崽崽', '#c1e8fa'))
    .then(() => stepWord('big zaizai', '#db61ac'))
    .then(() => stepSpace())
    .then(() => stepWord('☀️☀️☀️☀️☀️☀️'))
    .then(() => stepSpace())
    .then(() => stepRemove())
    .then(() => stepWord('但盼风雨来,能留你在此', '#c1e8fa'))
    .then(() => stepWord("Don't leave me!", '#db61ac'))
    .then(() => stepSpace())
    .then(() => stepWord('🌧️🌧️🌧️🌧️🌧️🌧️'))
    .then(() => stepSpace())
    .then(() => stepRain())
    .then(() => stepWord('留你在此,赏彩色的雨', '#c1e8fa'))
    .then(() => stepWord("I'll create more surprises for you", 'red'))
    .then(() => stepSpace())
    .then(() => stepWord('🌈🌈🌈🌈🌈🌈'))
    .then(() => stepColorFulRain())
    .then(() => stepHanzi())


从前到后一口气写下来,为后面的一大串动画衔接做了铺垫。


终端文案统一处理方法 —— stepWord & stepSpace


stepWord 方法可以配置终端的文案和字体颜色


function stepWord(str, color) {
  const step = str;
  const deferred = new Deferred();
  const len = step.length;
  let site = 0;
  content.appendChild(document.createElement('div'));
  const child = content.children[content.children.length - 1];
  if (color) {
    child.style.color = color;
  }
  const timer = setInterval(() => {
    child.innerHTML = step.slice(0, site + 1);
    if (site == len) {
      clearInterval(timer);
      deferred.resolve();
    } else {
      site++;
    }
  }, 100)
  return deferred.promise;
}


stepSpace 方法可以加入空白行


function stepSpace() {
  content.appendChild(document.createElement('br'));
  return Promise.resolve();
}


倒计时 —— stepTime


很简单的替换 dom 元素的内容,并让文字颜色逐渐加深。


function stepTime() {
  const deferred = new Deferred();
  const time = document.getElementsByClassName('time')[0];
  time.style.opacity = 1;
  const number = time.children[3];
  const list = ['二', '三', '四', '五'];
  let site = 0;
  const timer = setInterval(() => {
    if (site == list.length) {
      document.getElementsByClassName('heart')[0].style.opacity = 1;
      clearInterval(timer);
      time.style.opacity = 0;
      deferred.resolve();
    } else {
      number.innerHTML = list[site];
      number.style.color = `rgba(233, 62, 59, ${(site + 2) * 0.2})`;
      site++;
    }
  }, 1000)
  return deferred.promise;
}


彩色的雨 —— stepColorFulRain


这里其实这个涟漪的扩散就是简单的帧动画,之后通过 js 在随机位置生成 dom 元素。

css


@keyframes rain {
      from {
        transform: scale(1, 1);
        opacity: 1;
      }
      50% {
        opacity: 1;
      }
      to {
        transform: scale(100, 100);
        opacity: 0;
      }
    }
    .rain {
      height: 3px;
      width: 3px;
      background: radial-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.3));
      border-radius: 50%;
      transform-origin: 50% 50%;
      opacity: 0;
      animation: rain 5s linear;
      position: absolute;
      z-index: 999;
    }


js


function stepColorFulRain() {
      const deferred = new Deferred();
      view.style.background = '#0E2744';
      view.style.overflow = 'auto';
      function Rain() {
        this.rain = document.createElement('div');
        this.rain.className = 'rain';
        this.rain.style.top = Math.random() * window.innerHeight * 0.9 + 0.1 * window.innerHeight + 'px';
        this.rain.style.left = Math.random() * window.innerWidth * 0.9 + 0.1 * window.innerWidth + 'px';
        this.rain.style.background = `radial-gradient(rgba(255, 255, 255, 0.1), rgba(${Math.random() * 155 + 100}, ${Math.random() * 155 + 100}, ${Math.random() * 155 + 100}, 0.5))`;
        this.rain.style.animation = 'rain 6s linear'
        document.body.appendChild(this.rain);
        const timer2 = setTimeout(() => {
          clearTimeout(timer2);
          document.body.removeChild(this.rain);
        }, 6000)
      }
      let starTimer = setInterval(() => {
        new Rain();
      }, 300)
      setTimeout(() => {
        deferred.resolve();
      }, 2000)
      return deferred.promise;
    }


其他的代码


其他的代码都是很简单的 css。

其中这个心形的背景用到了 codepen 的 心❤️


文案彩蛋


网络异常,图片无法展示
|


致 9.15
开始倒计时
start the countdown
🌟🌟🌟🌟🌟🌟
心跳加速,藏獒开始进化
The heart rate quickens and the Tibetan mastiff begins to evolve.
🐶🐶🐶🐶🐶🐶
致 9.21
但愿人长久,千里共婵娟
you are my fairy forever
🌛🌛🌛🌛🌛🌛
大崽崽
big zaizai
☀️☀️☀️☀️☀️☀️
但盼风雨来,能留你在此
Do not leave me!
🌧️🌧️🌧️🌧️🌧️🌧️
留你在此,赏彩色的雨
I will create more surprises for you
🌈🌈🌈🌈🌈🌈


寒草的示爱宣言 📖


网络异常,图片无法展示
|


本章的图片来自电影《侧耳倾听》


因为你,我愿意成为一个更好的人,不想成为你的包袱,因此发奋努力,只是为了想要证明我足以与你相配。


其实小的时候就会被无数作品塑造爱情观,无论是《数码宝贝3》中懵懂的喜欢,启人为救出树莉与基尔兽进化为真红莲形态的红莲骑士兽,还是《食梦者》中各自约定「完成梦想就结婚」后各自的努力拼搏(现实不要这样,否则...我国结婚率又要...),再到最近看《侧耳倾听》中上面的那句话,在我眼里都十分美好而纯粹。


我曾陷入迷茫困惑,也曾陷入焦虑不安,不停的向前,却不知路在何方,被琐事与噩梦缠身又无法自拔。



网络异常,图片无法展示
|


我想我是否可以改写一下上面的话:


因为你,我渴望成为更好的人,想予你炙热的心,想予你艳丽的羽,想呈现更朝气的自己。因此不仅想发奋努力,又想驻足停留,只是为了想证明我是唯一正确的选择,只为传达我想做你想拥抱的人。


尾奏 🎵


网络异常,图片无法展示
|


爱情很珍贵,寒草要努力🌿

深知自己不够优秀

却想要《食梦者》中那般纯粹的梦想与爱情:完成梦想就结婚

以及《侧耳倾听》中:因为你,我愿意成为更好的人。


以及知乎中看到的这句话:


我想,最好的感情是两个人都用力的活,一起体验人生的种种趣味,也能包容与鼓励对方。当对方为你打开新的世界,你就没有因为喜欢一个人而拒绝了整个世界。


-正文完,Hancao design,to be continued-

相关文章
|
5天前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
4天前
|
缓存 移动开发 前端开发
【专栏:HTML与CSS前端技术趋势篇】HTML与CSS在PWA(Progressive Web Apps)中的应用
【4月更文挑战第30天】PWA(Progressive Web Apps)结合现代Web技术,提供接近原生应用的体验。HTML在PWA中构建页面结构和内容,响应式设计、语义化标签、Manifest文件和离线页面的创建都离不开HTML。CSS则用于定制主题样式、实现动画效果、响应式布局和管理字体图标。两者协同工作,保证PWA在不同设备和网络环境下的快速、可靠和一致性体验。随着前端技术进步,HTML与CSS在PWA中的应用将更广泛。
|
4天前
|
前端开发 JavaScript 开发者
【专栏:HTML与CSS前端技术趋势篇】前端框架(React/Vue/Angular)与HTML/CSS的结合使用
【4月更文挑战第30天】前端框架React、Vue和Angular助力UI开发,通过组件化、状态管理和虚拟DOM提升效率。这些框架与HTML/CSS结合,使用模板语法、样式管理及组件化思想。未来趋势包括框架简化、Web组件标准采用和CSS在框架中角色的演变。开发者需紧跟技术发展,掌握新工具,提升开发效能。
|
4天前
|
前端开发 JavaScript UED
【专栏:HTML 与 CSS 前端技术趋势篇】Web 性能优化:CSS 与 HTML 的未来趋势
【4月更文挑战第30天】本文探讨了CSS和HTML在Web性能优化中的关键作用,包括样式表压缩、选择器优化、DOM操作减少等策略。随着未来趋势发展,CSS模块系统、自定义属性和响应式设计将得到强化,HTML新特性也将支持复杂组件构建。同时,应对浏览器兼容性、代码复杂度和性能功能平衡的挑战是优化过程中的重要任务。通过案例分析和持续创新,我们可以提升Web应用性能,创造更好的用户体验。
|
4天前
|
移动开发 前端开发 UED
【专栏:HTML与CSS前端技术趋势篇】渐进式增强与优雅降级在前端开发中的实践
【4月更文挑战第30天】前端开发中的渐进式增强和优雅降级是确保跨浏览器、跨设备良好用户体验的关键策略。渐进式增强是从基础功能开始,逐步增加高级特性,保证所有用户能访问基本内容;而优雅降级则是从完整版本出发,向下兼容,确保低版本浏览器仍能使用基本功能。实践中,遵循HTML5/CSS3规范,使用流式布局和响应式设计,检测浏览器特性,并提供备选方案,都是实现这两种策略的有效方法。选择合适策略优化网站,提升用户体验。
|
4天前
|
前端开发 开发者 UED
【专栏:HTML与CSS前端技术趋势篇】网页设计中的CSS Grid与Flexbox之争
【4月更文挑战第30天】本文对比了CSS Grid和Flexbox两种布局工具。Flexbox擅长一维布局,简单易用,适合导航栏和列表;CSS Grid则适用于二维布局,能创建复杂结构,适用于整个页面布局。两者各有优势,在响应式设计中都占有一席之地。随着Web标准发展,它们的结合使用将成为趋势,开发者需掌握两者以应对多样化需求。
|
4天前
|
前端开发 JavaScript 搜索推荐
【专栏:HTML 与 CSS 前端技术趋势篇】HTML 与 CSS 在 Web 组件化中的应用
【4月更文挑战第30天】本文探讨了HTML和CSS在Web组件化中的应用及其在前端趋势中的重要性。组件化提高了代码复用、维护性和扩展性。HTML提供组件结构,语义化标签增进可读性,支持用户交互;CSS实现样式封装、布局控制和主题定制。案例展示了导航栏、卡片和模态框组件的创建。响应式设计、动态样式、CSS预处理器和Web组件标准等趋势影响HTML/CSS在组件化中的应用。面对兼容性、代码复杂度和性能优化挑战,需采取相应策略。未来,持续发掘HTML和CSS潜力,推动组件化开发创新,提升Web应用体验。
|
4天前
|
前端开发 JavaScript 安全
【TypeScript技术专栏】TypeScript在微前端架构中的应用
【4月更文挑战第30天】微前端架构通过拆分应用提升开发效率和降低维护成本,TypeScript作为静态类型语言,以其类型安全、代码智能提示和重构支持强化这一架构。在实践中,TypeScript定义公共接口确保跨微前端通信一致性,用于编写微前端以保证代码质量,且能无缝集成到构建流程中。在微前端架构中,TypeScript是保障正确性和可维护性的有力工具。
|
5天前
|
缓存 前端开发 JavaScript
【JavaScript 技术专栏】JavaScript 前端路由实现原理
【4月更文挑战第30天】本文探讨了JavaScript前端路由在SPA中的重要性,阐述了其基本原理和实现方式,包括Hash路由和History路由。前端路由通过监听URL变化、匹配规则来动态切换内容,提升用户体验和交互性。同时,文章也提到了面临的SEO和页面缓存挑战,并通过电商应用案例分析实际应用。理解并掌握前端路由能助开发者打造更流畅的单页应用。
|
5天前
|
Dart 前端开发 测试技术
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
【4月更文挑战第30天】随着Flutter在跨平台开发的普及,保证代码质量成为开发者关注的重点。优质代码能确保应用性能与稳定性,提高开发效率。关键策略包括遵循最佳实践,编写可读性强的代码,实施代码审查和自动化测试。重构实践在项目扩展时尤为重要,适时重构能优化结构,降低维护成本。开发者应重视代码质量和重构,以促进项目成功。
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践