微信刷屏的「给我一面国旗」如果要做到,技术原理是什么?
- 2019 年 10 月 7 日
- 筆記
十年前,在qq群里流传的是这么一段话。

十年后,朋友圈里出现了这么一群人。

时代在变,但是套路没变。割完一茬韭菜,总会有新的一茬韭菜长出来了。
但如果真要做到,内含多少种技术原理呢?场主做了大胆推测:
首先不可能@微信官方,就给你duang一下换好头像。
合理的打开方式是,进入它的活动页面,然后存出加了国旗的头像,最后手动换上。
第一步:先用photoshop做好活动页面,然后切图

第二步:用 HTML5+CSS3+JS 制作出页面
拷贝的活动页代码,侵删,仅供学习参考
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="description" content="迎国庆换新颜" /> <meta name="keywords" content="" /> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" /> <meta name="renderer" content="webkit" /> <meta name="format-detection" content="telphone=no,email=no,address=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta http-equiv="x-dns-prefetch-control" content="on" /> <link rel="dns-prefetch" href="//open.mobile.qq.com" /> <link rel="dns-prefetch" href="//pingjs.qq.com" /> <link rel="dns-prefetch" href="//qnlite.gtimg.com" /> <link rel="preconnect" href="//qnlite.gtimg.com" /> <link rel="preconnect" href="//open.mobile.qq.com" /> <link rel="preconnect" href="//pingjs.qq.com" /> <link rel="icon" href="https://qnlite.gtimg.com/qqnewslite/logo.png" /> <title>迎国庆换新颜</title> <script>!function(){var i=0;!function e(t){var n=40;(document.documentElement.clientWidth!==window.innerWidth||0===document.documentElement.clientWidth&&0===window.innerWidth)&&i<10?(document.documentElement.style.opacity=0,window.setTimeout(e,0),i++):(document.documentElement.style.opacity=0,setTimeout(function(){var e=500<window.innerWidth?500:window.innerWidth;n=parseInt(e/750*1e4*40)/1e4,document.documentElement.style.opacity=1,document.documentElement.style.fontSize=n+"px"},0))}()}()</script> <script src="https://mat1.gtimg.com/bbs/qqnewslite/js/TGMobileShare-noadtag19.min.js"></script> <script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){function e(){t.media=a}var a=t.media||"all";t.addEventListener?t.addEventListener("load",e):t.attachEvent&&t.attachEvent("onload",e),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(e,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this)</script> <link href="https://qnlite.gtimg.com/qqnewslite/css/chunk-nationaldayhead-vendors.0f433423.css" rel="preload" as="style" onload="this.onload=null,this.rel="stylesheet"" /> <noscript> <link href="https://qnlite.gtimg.com/qqnewslite/css/chunk-nationaldayhead-vendors.0f433423.css" rel="stylesheet" /> </noscript> </head> <body> <div id="app"></div> <script>function changeThemeType(){}</script> <script src="https://qnlite.gtimg.com/qqnewslite/js/chunk-vendors.836075e1.js"></script> <script src="https://qnlite.gtimg.com/qqnewslite/js/chunk-nationaldayhead-vendors.0ea1c589.js"></script> <script src="https://qnlite.gtimg.com/qqnewslite/js/nationaldayhead.5241bf47.js"></script> </body>
第三步:获取微信用户的头像
1、用户同意授权,获取code
2、通过code换取网页授权access_token
3、刷新access_token(如果需要)
4、拉取用户信息(需scope为 snsapi_userinfo)
5、检验授权凭证(access_token)是否有效
具体看这里→_→:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
最后一步:把覆盖了国旗透明素材的头像导出来
用html2canvas.js,具体:
1、生成图片可以用canvas,html2canvas开源库引用
/** * 根据window.devicePixelRatio获取像素比 */ function DPR() { if (window.devicePixelRatio && window.devicePixelRatio > 1) { return window.devicePixelRatio; } return 1; } /** * 将传入值转为整数 */ function parseValue(value) { return parseInt(value, 10); }; /** * 绘制canvas */ async function drawCanvas (selector) { // 获取想要转换的 DOM 节点 const dom = document.querySelector(selector); const box = window.getComputedStyle(dom); // DOM 节点计算后宽高 const width = parseValue(box.width); const height = parseValue(box.height); // 获取像素比 const scaleBy = DPR(); // 创建自定义 canvas 元素 var canvas = document.createElement('canvas'); // 设定 canvas 元素属性宽高为 DOM 节点宽高 * 像素比 canvas.width = width * scaleBy; canvas.height = height * scaleBy; // 设定 canvas css宽高为 DOM 节点宽高 canvas.style.width = `${width}px`; canvas.style.height = `${height}px`; // 获取画笔 const context = canvas.getContext('2d'); // 将所有绘制内容放大像素比倍 context.scale(scaleBy, scaleBy); let x = width; let y = height; return await html2canvas(dom, {canvas}).then(function () { convertCanvasToImage(canvas, x ,y) }) } /** * 图片转base64格式 */ function convertCanvasToImage(canvas, x, y) { let image = new Image(); let _container = document.getElementsByClassName('container')[0]; let _body = document.getElementsByTagName('body')[0]; image.width = x; image.height = y; image.src = canvas.toDataURL("image/png"); _body.removeChild(_container); document.body.appendChild(image); return image; } drawCanvas('.container')
2、由于现在的手机都是高清屏,所以如果你不做处理就会出现模糊的情况,设备像素比 devicePixelRatio js 提供了 window.devicePixelRatio 可以获取设备像素比。
function DPR() { if (window.devicePixelRatio && window.devicePixelRatio > 1) { return window.devicePixelRatio; } return 1; }
这个DPR函数就是获取设备的像素比, 那获取像素比之后要做什么呢?
var canvas = document.createElement('canvas'); // 设定 canvas 元素属性宽高为 DOM 节点宽高 * 像素比 canvas.width = width * scaleBy; canvas.height = height * scaleBy; // 设定 canvas css宽高为 DOM 节点宽高 canvas.style.width = `${width}px`; canvas.style.height = `${height}px`; // 获取画笔 const context = canvas.getContext('2d'); // 将所有绘制内容放大像素比倍 context.scale(scaleBy, scaleBy);
3、获取设备像素比之后将canavs.width 和 canvas.height 去乘以设备像素比,也就是 scaleBy; 这个时候在去设置canvas.style.width 和 canvas.style.height 为dom的宽和高。

6plus DPR=3
