说到撩妹这个话题,估计不少人都以为和程序员沾不上边,大多数人对程序员的印象是这样的:木讷,老实,内向,不爱社交。眼里只有代码,不懂浪漫!做为一个多年的程序员老砖员,我决定为广大程序员伙伴澄清这个谣言,告诉你们,咱们程序员也是很浪漫的!
为了避免让你们痛失女神的芳心,我作了一个表白神器,在此和各位程序员小哥哥们分享分享!最终赢取白富美,走上人生巅峰!
咱们须要一些工具方法,将之抽离出来以便公用,最好不要污染业务代码,这里用了一个词“污染”,在咱们作项目的时候,其实不少代码都是和业务无关的,若是都写到一块儿了,这样会让咱们的业务很是不清晰,之因此要抽离出来,就是为了让咱们的业务逻辑清晰可见,当抽离出来后,你会发现,业务代码就几行,看上去很是的简洁。javascript
如下是我抽离的非业务代码css
/** * * @desc 生成指定范围随机数 * @param {Number} min * @param {Number} max * @return {Number} */ export function randomNum(min, max) { return Math.floor(min + Math.random() * (max - min)); } /** * @desc 数组打乱顺序 */ export function randomArrSort(arr) { arr.sort(() => 0.5 - Math.random()); return arr; } /** * * @desc 随机生成颜色 * @return {String} */ export function randomColor() { return '#' + ('00000' + ((Math.random() * 0x1000000) << 0).toString(16)).slice(-6); } /** * 生成一个用不重复的ID */ export function getRandomID(randomLength = 8) { return 'id_' + Number( Math.random() .toString() .substr(3, randomLength || 8) + Date.now() ).toString(36); } /** * @desc 设置自动适配的尺寸 */ export function setSize($box, scale, fixed) { let width = fixed ? appWidth : $box.width(), height = fixed ? appHeight : $box.height(); const { innerWidth, innerHeight } = window; let top = (innerHeight - height * scale) / 2; if (top < 0) { top = 0; } $box.css({ left: (innerWidth - width * scale) / 2, top: top, transform: `scale(${scale})` }); } /** * @desc 计算sacle 和 偏移 */ export function getScale() { const width = 320; const height = 514; // 自动适配 const { innerWidth, innerHeight } = window; // 假设宽度适配 scale * width = innerWidth let scale1 = innerWidth / width; // 假设高度适配 scale * height = innerHeigh let scale2 = innerHeight / height; return scale1 > scale2 ? scale2 : scale1; }
其实咱们的文字能够单独抽离成一个类进行管理,这个类须要包含文字相关的一些方法html
一、获取随机文案
二、获取所有文字
三、渲染所有的文字
四、执行文字动画
五、计算目标文案的位置
六、寻找目标文字的位置,而后clone一个
七、初始化
八、从新执行java
我大体评估了,须要这些方法。jquery
因此文字的类构造以下:git
import * as tool from '../utils/tools'; import { texts } from './texts'; /** * @desc 文字的方法 */ export default class Text { constructor(set) { this.set = Object.assign( { target: '#phone', width: 320, height: 514, callback: () => {} }, set ); this.dom = $(set.target); } // 获取随机文案 getText() { const index = tool.randomNum(0, texts.length - 1); const t1 = texts[index]; return t1.split(''); } // 获取所有文字 getAllText() { let all = []; const { width, height } = this.set; texts.forEach(d => { // let str = d.replace(/[,,。,?,!,……,~,:”,“,\s]/gm, ''); all = [...all, ...d.split('')]; }); // 去重 all = Array.from(new Set(all)); all = all.map(text => { const a = tool.randomNum(5, 10); const iskey = this.targetText.indexOf(text) === -1 ? false : true; return { id: tool.getRandomID(), y: height / 2 - a / 2, x: width / 2 - a / 2, opacity: Math.random() * 0.5, scale: Math.random() * 1.2, iskey, width: a, height: a, text }; }); return tool.randomArrSort(all); } // 渲染allText renderTexts(arr) { let shtml = ''; arr.forEach(d => { const { id, x, y, scale, opacity, iskey, width, height, text } = d; shtml += `<span id="${id}" class="${ iskey ? 'text text-active' : 'text' }" style="width: ${width}px; height: ${height}px; transform: translate(${x}px, ${y}px) scale(${scale}); opacity: ${opacity};">${text}</span>`; }); this.dom.append(shtml); } // 计算目标文字的位置 getTargetCoord(targetText) { const tlen = targetText.length; let val = 10; // 10个换行 let size = 20, arr = [], boxWidth = Math.ceil(tlen / val) * size, boxHeight = size * val; // 10个字换行 const { width, height } = this.set; // 坐标起点 const start = { x: (width - boxWidth) / 2, y: (height - boxHeight) / 2 - 100 }; for (let i = 0; i < tlen; i++) { let a = Math.floor(i / val); arr.push({ width: size, height: size, x: start.x + a * size, y: start.y + (i - a * val) * size }); } return arr; } // 找到对应的字,而后clone一个对象 cloneTargetStyle(d, tArr) { const obj = tArr.filter(a => { return a.text === d; })[0]; obj.id = tool.getRandomID(); return { ...obj }; } // 目标文字动画 targetTextAimate() { let index = 0; let tArr = []; this.allText.forEach(d => { if (d.iskey) { tArr.push(d); } $(`#${d.id}`).css({ opacity: 0 }); }); // 获取目标数组 const targetArr = []; this.targetText.forEach(d => { targetArr.push(this.cloneTargetStyle(d, tArr)); }); // 设置坐标 const arr = this.getTargetCoord(targetArr); // 渲染dom this.renderTexts.bind(this)(targetArr); targetArr.forEach((d, index) => { let item = arr[index]; $(`#${d.id}`).css({ opacity: 1, width: item.width, height: item.height, transform: `translate(${item.x}px, ${item.y}px) scale(1)` }); }); setTimeout(() => { this.set.callback(); }, 3000); } // allText 文字动画 allTextAnimate() { const { width, height } = this.set; let count = 0; const doAnimate = () => { count++; this.allText = this.allText.map(d => { d.y = tool.randomNum(0, height); d.x = tool.randomNum(0, width); d.scale = Math.random() * 1.5; // d.opacity = Math.random() * 0.5; return d; }); this.allText.forEach(d => { const { x, y, scale } = d; $(`#${d.id}`).css({ transform: `translate(${x}px, ${y}px) scale(${scale})` }); }); }; const runTime = () => { if (count > 2) { setTimeout(() => { this.targetTextAimate.bind(this)(); }, 3000); return; } setTimeout(() => { doAnimate(); runTime(); }, 3000); }; doAnimate(); runTime(); } // 从新执行 restart = () => { this.dom.empty(); this.targetText = this.getText(); this.allText = this.getAllText.bind(this)(); this.renderTexts.bind(this)(this.allText); setTimeout(() => { this.allTextAnimate.bind(this)(); }, 10); }; // 初始化 init = () => { // 获取文案 this.targetText = this.getText(); this.allText = this.getAllText.bind(this)(); // 渲染文字 this.dom.addClass('h5ds-text7'); this.renderTexts.bind(this)(this.allText); setTimeout(() => { this.allTextAnimate.bind(this)(); }, 0); }; }
为了能够自定义文案,我单独把文案拿了出来程序员
export const texts = [ '我想在你那里买一块地。买什么地?买你的死心塌地', '你知道你和星星有什么区别吗?星星在天上而你在我内心', '我十拿九稳 就只差你一吻了', '可爱不是长久之计,可爱我是', '小猪佩奇,你配我', '有谣言说我喜欢你,我澄清一下,那不是谣言', '只许州官放火 不准……你离开我', '你昨天晚上应该很累吧,由于你在我梦里一直跑个不停', '我以为你接近我就是在害我,害得我好喜欢你呀', '你今天好奇怪,怪可爱的', '我以为我好花心,你天天的样子我都好喜欢', '你有打火机嘛?没有?那你是如何点燃个人心的', '我说不清我为何爱你,我只知道,只要有你,我就不可能爱上别人', '我喜欢你,像你妈打你,不讲道理', '知道你为何这么冷吗?由于你没有像我这么暖的对象在身边啊。', '无事献殷勤,非……很是喜欢你', '子曰:三思然后行,1,2,3~嗯~我喜欢你。', '小女子不才,掐指一算,公子此生缺我。', '你有地图吗?我在你的眼睛里迷路了。', '你知道我最喜欢什么神吗?是你的眼神。', '你要是丑点,我或许能够带你逛街看电影吃西餐散散步看星星看月亮,从诗词歌赋谈到人生哲学,可你长的那么好看,让我只想和你恋爱。', ' 我房租到期了,能够去你内心住吗?', '“要是我和你生一个孩子你以为他会是什么座?”“什么座?双子座?”“不,咱们的杰做。”', '“你能够笑一个吗?”“为何啊?”“由于个人咖啡忘加糖了。”', '“你想喝点什么?”“我想呵护你。”', '“我以为你长得像我一个亲戚。”“???”“我妈的儿媳妇。”', '“你知道情人眼里出什么吗?”“西施啊。”“不,出现你。”', '“你最近是否是又胖了?”“没有啊,为何这么说?”“那你为何在我内心的份量愈来愈重了呢?”', '落叶归根,你归我。', '苦海无涯,回头是我。', '不想撞南墙了,只想撞撞先生胸膛。', '你上辈子必定是碳酸饮料吧,否则我怎么一看到你就开心地冒泡呢。', '你会弹钢琴吗?不会?那你是怎么撩动个人心弦的呢。', '第一次见到你时,上帝在我耳旁说了几个字,在劫难逃。', '你知道喝什么酒最容易醉吗?是你的天长地久。', '“你属什么?”“我属虎。”“你不要再骗人了,你属于我。”', '“你是什么星座? 双子座吗?”“ 不是。我是为你量身定作。”', '你知道我最大的缺点是什么吗?是缺点你。', '若是我把你推到花园里面,我就会找不到你。由于你像花儿同样美丽。', '有时候生活有些苦难,你不要去抱怨,抱我就行了。' ];
其实当咱们抽离了类,抽取了非业务相关的公共方法。业务代码就很是简单了,下面就是HTML + 业务相关的代码。github
<!DOCTYPE html> <html lang="zh-cn"> <head> <title></title> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <!-- <script src="https://cdn.bootcss.com/jquery.qrcode/1.0/jquery.qrcode.min.js"></script> --> </head> <body> <!--[if lt IE 10]> <p class="browse-tips"> 您正在使用<strong>过期的</strong>浏览器。 请<a href='http://browsehappy.com/'>更新浏览器</a>,以保证良好的用户体验。 </p> <![endif]--> <div class="logo"> <span>由开源H5编辑器h5ds.com提供</span> </div> <div id="app"> <div class="title" id="title"> <h1> <span>七</span> <span>夕</span> <span>必</span> <span>备</span> <span>甜</span> <span>言</span> <span>蜜</span> <span>语</span> </h1> <button id="run">生成情话</button> </div> <div id="phone"> </div> <div class="qrcodebox"> <div id="qrcode"> <img src="/assets/images/qrcode.jpg" alt=""> </div> <br> <button id="restart">再玩一次</button> <br> <button id="saveImg">生成图片</button> </div> </div> </body> </html>
import * as tool from '../utils/tools'; import Text from './Text'; import domtoimage from 'dom-to-image'; // 设置尺寸 function setSize() { const scale = tool.getScale(); tool.setSize($('#app'), scale); } $(function() { setSize(); $(window).resize(() => { setSize(); }); $('#title') .find('span') .each(function() { $(this).css({ 'animation-delay': `${Math.random()}s` }); }); setTimeout(() => { $('#title') .find('button') .show(); }, 2000); const textAnim = new Text({ target: '#phone', callback: () => { $('.qrcodebox').show(); } }); // 开始 $('#run').on('click', () => { $('#title').hide(); textAnim.init(); }); // 从新选择 $('#restart').on('click', () => { $('.qrcodebox').hide(); textAnim.restart(); }); // 保存图 $('#saveImg').on('click', () => { domtoimage .toPng($('body')[0]) .then(function(dataUrl) { $('body').append(`<img id="toimg" src="${dataUrl}" />`); alert('图片已经生成,长按屏幕保存到手机!') }) .catch(function(error) { console.error('oops, something went wrong!', error); }); }); });
在作一个项目的时候,咱们尽量的剥离出业务不相关的代码,让编程的思想尽量的清晰,任何API接口的设计都是为了让用户更好的实现本身的业务,固然,若是对底层的实现逻辑有兴趣的朋友,也能够去具体的了解下每一个方法内部的实现,进一步提高自身的实力,固然,Text这个类还能够进一步的优化,好比把数据做为参数传到类里面,这样作会更灵活!这些就是后来所谓的优化,迭代环节了。算法