微信刷屏的「给我一面国旗」如果要做到,技术原理是什么?

十年前,在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=&quot;stylesheet&quot;" />
  <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

4、最后调用canvas.toDataURL("image/png");赋值给image.src,由于微信里面无法保存图片,所以只能生成图片文件,调用微信自带的长按保存到图片到相册功能。

本文分享自微信公众号 - 养码场(yangmachang0)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端开发随笔

tomcat下的Cookie特殊符号问题

案例: 在项目中通过Cookie方式临时存放检索条件,不小心在Cookie值中使用了特殊符号"@",导致在服务器端无法正确解析Cookie值。 之所以说"不小心...

8310
来自专栏姚红专栏

Python的Web应用框架--Django

python的web框架有很多,个人查了一下,有Django、Pylons、 Tornado、Bottle和Flask等,其中使用人数最多的是Djan...

11030
来自专栏授客的专栏

Python-Django 整合Django和jquery-easyui

jquery-easyui-1.5.1 下载地址1:http://www.jeasyui.com/download/index.php

14820
来自专栏姚红专栏

自动化运维—Ansible(上)

  ansible甚至都不用启动服务,仅仅只是一个工具,可以很轻松的实现分布式扩展

12110
来自专栏小蔚记录

jq ---- 实现浏览器全屏

16740
来自专栏后端开发随笔

Spring Boot系列之-logging

二. 更改Spring Boot日志组件为Log4j(注:Spring Boot仅仅支持Log4j 2.x版本):

12320
来自专栏后端开发随笔

权限系统设计概述

2. 权限系统要素 资源:授权访问。 角色:访问资源的证书,定义了资源访问的界限,作为一个粗粒度的资源访问权限控制。 主体:访问资源的对象,通常为登录用户。 权...

18930
来自专栏后端开发随笔

j2ee应用开发调试工具

j2ee应用程序不能独立运行,需要运行在一个servlet/jsp容器中,常用的servlet/jsp容器如:tomcat,jetty等。 在开发调试j2ee程...

9010
来自专栏小蔚记录

ajax 使用 与 缓存问题

  就是 一个相同的URL 只有一个结果[相同是指 整个URL字符串完全匹配]   所以 第二次访问的时候 如果 URL字符串没变化 浏览器是 直接拿出了第一次...

15020
来自专栏小蔚记录

JS --- 延迟加载的几种方式

标题:JS延迟加载,也就是等页面加载完成之后再加载 JavaScript 文件。    JS延迟加载有助于提高页面加载速度。

22420

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励