說到撩妹這個話題,估計不少人都以爲和程序員沾不上邊,大多數人對程序員的印象是這樣的:木訥,老實,內向,不愛社交。眼裏只有代碼,不懂浪漫!做爲一個多年的程序員老磚員,我決定爲廣大程序員夥伴澄清這個謠言,告訴你們,咱們程序員也是很浪漫的!
爲了避免讓你們痛失女神的芳心,我作了一個表白神器,在此和各位程序員小哥哥們分享分享!最終贏取白富美,走上人生巔峯!
咱們須要一些工具方法,將之抽離出來以便公用,最好不要污染業務代碼,這裏用了一個詞「污染」,在咱們作項目的時候,其實不少代碼都是和業務無關的,若是都寫到一塊兒了,這樣會讓咱們的業務很是不清晰,之因此要抽離出來,就是爲了讓咱們的業務邏輯清晰可見,當抽離出來後,你會發現,業務代碼就幾行,看上去很是的簡潔。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這個類還能夠進一步的優化,好比把數據做爲參數傳到類裏面,這樣作會更靈活!這些就是後來所謂的優化,迭代環節了。算法