如何作一個會liao妹的程序員?

說到撩妹這個話題,估計不少人都以爲和程序員沾不上邊,大多數人對程序員的印象是這樣的:木訥,老實,內向,不愛社交。眼裏只有代碼,不懂浪漫!做爲一個多年的程序員老磚員,我決定爲廣大程序員夥伴澄清這個謠言,告訴你們,咱們程序員也是很浪漫的!

圖片描述

爲了避免讓你們痛失女神的芳心,我作了一個表白神器,在此和各位程序員小哥哥們分享分享!最終贏取白富美,走上人生巔峯!

圖片描述

首先看看效果。掃描下方二維碼便可預覽

圖片描述

【看看代碼的實現】

1、寫代碼前首先須要考慮如下幾點

  1. 兼容不一樣手機分辨率
  2. 採用CSS3動畫,更流暢
  3. 文字的定位採用一個算法,將其豎排居中顯示
  4. 後期的可拓展性

2、代碼之工具方法

咱們須要一些工具方法,將之抽離出來以便公用,最好不要污染業務代碼,這裏用了一個詞「污染」,在咱們作項目的時候,其實不少代碼都是和業務無關的,若是都寫到一塊兒了,這樣會讓咱們的業務很是不清晰,之因此要抽離出來,就是爲了讓咱們的業務邏輯清晰可見,當抽離出來後,你會發現,業務代碼就幾行,看上去很是的簡潔。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;
}

3、抽取公共類

其實咱們的文字能夠單獨抽離成一個類進行管理,這個類須要包含文字相關的一些方法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);
    };
}

4、文案拓展性,可自定義文案

爲了能夠自定義文案,我單獨把文案拿了出來程序員

export const texts = [
    '我想在你那裏買一塊地。買什麼地?買你的死心塌地',
    '你知道你和星星有什麼區別嗎?星星在天上而你在我內心',
    '我十拿九穩 就只差你一吻了',
    '可愛不是長久之計,可愛我是',
    '小豬佩奇,你配我',
    '有謠言說我喜歡你,我澄清一下,那不是謠言',
    '只許州官放火 不準……你離開我',
    '你昨天晚上應該很累吧,由於你在我夢裏一直跑個不停',
    '我以爲你接近我就是在害我,害得我好喜歡你呀',
    '你今天好奇怪,怪可愛的',
    '我以爲我好花心,你天天的樣子我都好喜歡',
    '你有打火機嘛?沒有?那你是如何點燃個人心的',
    '我說不清我爲何愛你,我只知道,只要有你,我就不可能愛上別人',
    '我喜歡你,像你媽打你,不講道理',
    '知道你爲何這麼冷嗎?由於你沒有像我這麼暖的對象在身邊啊。',
    '無事獻殷勤,非……很是喜歡你',
    '子曰:三思然後行,1,2,3~嗯~我喜歡你。',
    '小女子不才,掐指一算,公子此生缺我。',
    '你有地圖嗎?我在你的眼睛裏迷路了。',
    '你知道我最喜歡什麼神嗎?是你的眼神。',
    '你要是醜點,我或許能夠帶你逛街看電影吃西餐散散步看星星看月亮,從詩詞歌賦談到人生哲學,可你長的那麼好看,讓我只想和你戀愛。',
    ' 我房租到期了,能夠去你內心住嗎?',
    '「要是我和你生一個孩子你以爲他會是什麼座?」「什麼座?雙子座?」「不,咱們的傑做。」',
    '「你能夠笑一個嗎?」「爲何啊?」「由於個人咖啡忘加糖了。」',
    '「你想喝點什麼?」「我想呵護你。」',
    '「我以爲你長得像我一個親戚。」「???」「我媽的兒媳婦。」',
    '「你知道情人眼裏出什麼嗎?」「西施啊。」「不,出現你。」',
    '「你最近是否是又胖了?」「沒有啊,爲何這麼說?」「那你爲何在我內心的份量愈來愈重了呢?」',
    '落葉歸根,你歸我。',
    '苦海無涯,回頭是我。',
    '不想撞南牆了,只想撞撞先生胸膛。',
    '你上輩子必定是碳酸飲料吧,否則我怎麼一看到你就開心地冒泡呢。',
    '你會彈鋼琴嗎?不會?那你是怎麼撩動個人心絃的呢。',
    '第一次見到你時,上帝在我耳旁說了幾個字,在劫難逃。',
    '你知道喝什麼酒最容易醉嗎?是你的天長地久。',
    '「你屬什麼?」「我屬虎。」「你不要再騙人了,你屬於我。」',
    '「你是什麼星座? 雙子座嗎?」「 不是。我是爲你量身定作。」',
    '你知道我最大的缺點是什麼嗎?是缺點你。',
    '若是我把你推到花園裏面,我就會找不到你。由於你像花兒同樣美麗。',
    '有時候生活有些苦難,你不要去抱怨,抱我就行了。'
];

5、業務代碼

其實當咱們抽離了類,抽取了非業務相關的公共方法。業務代碼就很是簡單了,下面就是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);
            });
    });
});

6、總結

在作一個項目的時候,咱們儘量的剝離出業務不相關的代碼,讓編程的思想盡量的清晰,任何API接口的設計都是爲了讓用戶更好的實現本身的業務,固然,若是對底層的實現邏輯有興趣的朋友,也能夠去具體的瞭解下每一個方法內部的實現,進一步提高自身的實力,固然,Text這個類還能夠進一步的優化,好比把數據做爲參數傳到類裏面,這樣作會更靈活!這些就是後來所謂的優化,迭代環節了。算法

最後嗶嗶兩句,做爲一個程序員,不管工做如何繁忙,請不要忘記撩妹,祝你們早日脫單!獻上github地址:https://github.com/mtsee/vale...

相關文章
相關標籤/搜索