国庆节到了,利用JS实现一个生成国庆风头像的小工具 详解实现过程


Posted in Javascript onOctober 05, 2021

这里用到的技术:

  • HTML+ CSS+ JavaScript;
  • download.js库;
  • fabric.js库;

先上体验链接:g.cuggz.com/ 。​

注:可以点击上方的连接进行使用,不过我的域名被TX屏蔽了,还在申诉中,所以无法在QQ、微信中打开,需要复制链接到浏览器进行查看、使用。​

下面是这个小工具的截图:

国庆节到了,利用JS实现一个生成国庆风头像的小工具 详解实现过程

1. 页面布局

这部分不多说,直接上代码:

<div class="wrapper">
    <!-- 选择框 -->
    <div class="main-box">
      <a class="prev" onClick='changeHat()'></a>
      <div class="main-img">
        <div id="content">
          <canvas id='cvs'></canvas>
        </div>
      </div>
      <a class="next" onClick='changeHat()'></a>
    </div>
    <!-- 导出图 -->
    <img id='export-img' alt='国庆专属头像' src='' crossorigin="anonymous"/>
    <!-- 操作按钮 -->
    <div class="operation-btns">
      <a class="upload-btn">
        <input id='upload' type='file' onchange='viewer()' style='opacity: 0;'/>
      </a>
      <a class="export-btn" onClick='exportFunc()'></a>
    </div>
  </div>
 <!-- 模板 -->
  <div style='display: none'>
    <img id='img' src='' alt='' />
    <img class='hide' id='hat0' src='img/1.png' />
    <img class='hide' id='hat1' src='img/2.png' />
    <img class='hide' id='hat2' src='img/3.png' />
    <img class='hide' id='hat3' src='img/4.png' />
    <img class='hide' id='hat4' src='img/5.png' />
    <img class='hide' id='hat5' src='img/6.png' />
    <img class='hide' id='hat6' src='img/7.png' />
  </div>

这个页面比较简单,外面就是一个大的背景图,中间就是一个头像的展示框以及模板的切换按钮,下面就是一个上传按钮和一个下载按钮。页面布局完之后,就是写样式了,CSS代码如下:

body,
html {
    min-height: 100%;
    width: 100%;
    user-select: none;
    font-size: 18px;
}

.wrapper {
    width: 100%;
    height: 100%;
    max-width: 620px;
    max-height: 800px ;
    margin: 0 auto;
    background-image: url('../img/bg.png');
    background-repeat: no-repeat;
    background-size: 100% 100%;
    padding-top: 13em;
}

#export-img {
    display:none;
    margin:0 auto;
    width:250px;
    height:250px;
}

.main-box {
    display: flex;
    align-items: center;
    justify-content: center;
}

.main-box .next,
.main-box .prev {
    background-image: url('../img/next.png');
    background-size: contain;
    border-radius: 50%;
    width: 2.275rem;
    height: 2.275rem
}

.main-box .prev {
    transform: rotate(180deg)
}

.main-box .main-img {
    margin: 0 .75rem;
    background: #fff;
    border: .25rem solid #fbe6b5;
    border-radius: .75rem;
    font-size: 0
}

#content {
    border-radius: .5rem;
    position: relative;
    width: 9.5rem;
    height: 9.5rem;
    margin-left: 50%;
    transform: translateX(-50%);
    overflow: hidden
}

.operation-btns {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    margin-top: .75rem
}

.operation-btns .upload-btn {
    width: 11.6rem;
    height: 3.6rem;
    background-size: 100% 100%;
    background-image: url('../img/upload.png')
}

.operation-btns .export-btn {
    display: none;
    width: 11.6rem;
    height: 3.75rem;
    background-size: 100% 100%;
    background-image: url('../img/export.png')
}

这里只是简单的实现,仅供参考。还有很多可以优化的地方,这里不在修改,有兴趣的可以自己进行个性化定制。

2. 图片上传和展示

接下来就是逻辑部分的实现了。首先,有几个全局变量需要先定义,后面会用到:

let canvasFabric;   // 画布实例
let hat = "hat0";  // 当前的模板class
let hatInstance;  // 模板图层实例
const screenWidth = document.getElementById("content").scrollHeight;  // 内容框的高度

之后就需要处理上传的图片并将他展示在页面上:

function viewer() {
  // 获取上传的图片文件
  const file = document.getElementById("upload").files[0];
  // 获取需要展示图片的标签
  const img = document.getElementById("img");
  // 创建文件读取文件对象
  const reader = new FileReader();
  if (file) {
    // 将文件转化为Base64
    reader.readAsDataURL(file);
    // 当文件读取成功之后触发
    reader.onload = () => {
      // 将base64的url赋值给要展示图片的标签
      img.src = reader.result;
      // 图片加载完成触发
      img.onload = () => img2Cvs(img);
    }
  } else {
    img.src = ""
  }
}

这里使用到了HTML5FileReader对象,它提供了读取文件的方法和包含读取结果的事件模型。可以使用new来初始化对象,FileReader对象包含四个方法,其中 3 个用以读取文件,另一个用来中断读取。需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result 属性中。这里用到了readAsDataURL方法,MDN对该方法的介绍如下:

readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend (en-US) 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。

也就是说将上传的图片转化为了一个Base64格式的URL,并赋值给了展示图片的标签,这样这个标签就显示出现这个头像了,效果如下:

国庆节到了,利用JS实现一个生成国庆风头像的小工具 详解实现过程

这样就完成了图片的上传和展示,接下来就该初始化一个画布了。

3. 初始化画布

在上面的代码的最后执行了 img.load,这里的 onload 事件会在图片加载完成后立即执行。在图片展示完成之后会执行img2Cvs方法,这个方法主要用来初始化一块画布,顺便展示和隐藏页面的部分元素。

img2Cvs方法中使用到了 fabric库,Fabric.js是一个可以简化Canvas程序编写的库。 Fabric.jsCanvas提供所缺少的对象模型, svg parser, 交互和一整套其他不可或缺的工具。Canvas提供一个好的画布能力, 但是Api不够友好。Fabric.js就是为此而开发,它主要就是用对象的方式去编写代码。Fabric.js能做的事情如下:

  • Canvas上创建、填充图形(包括图片、文字、规则图形和复杂路径组成图形)。
  • 给图形填充渐变颜色。
  • 组合图形(包括组合图形、图形文字、图片等)。
  • 设置图形动画集用户交互。
  • 生成JSON, SVG数据等。
  • 生成Canvas对象自带拖拉拽功能。

可以通过npm命令来安装fabric.js库:

npm install fabric --save

也可以通过cdn来引用:

<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>

下面就来看看img2Cvs方法是如何实现的:

function img2Cvs(img) {
   // 获取并展示canvas画布,并将画布的大小设置为图片的大小
    const cvs = document.getElementById("cvs");
    cvs.width = img.width;
    cvs.height = img.height;
    cvs.style.display = "block";
   
   // 创建一个画布,并设置其位置和背景图
    canvasFabric = new fabric.Canvas("cvs", {
      width: screenWidth,
      height: screenWidth,
      backgroundImage: new fabric.Image(img, {
        scaleX: screenWidth / img.width,
        scaleY: screenWidth / img.height
      })
    });
   // 切换模板
    changeHat();
  // 隐藏上传图片按钮,展示下载图片按钮
    document.getElementsByClassName("upload-btn")[0].style.display = "none";
    document.getElementsByClassName("export-btn")[0].style.display = "block";
  }

这里面的fabric.Canvas()方法有两个参数,第一个参数是canvas画布的id,第二个参数是初始化画布时的配置项,这里我们设置了初始的画布的大小以及背景图,使用我们上传的头像作为背景图。这里的背景图是实例化的fabric.Image对象,该对象初始化时的第一个参数是图片对象,第二个参数是图片的样式设置配置对象。​

当创建好画布之后,就需要切换出第一个模板,并将上传图片按钮隐藏,以及将下载头像按钮显示出来。这样就完成了第一步的工作。下面就在来看看如何切换已有的模板。

4. 切换模板

接下来就来看看切换模板是如何实现的:

function changeHat() {
   // 隐藏当前的模板
    document.getElementById(hat).style.display = "none";
   // 获取所有的模板
    const hats = document.getElementsByClassName("hide");
    hat = "hat" + (+hat.replace("hat", "") + 1) % hats.length;
   // 获取当前的模板并展示出来
    const hatImage = document.getElementById(hat);
    hatImage.style.display = "block";
   // 如果当前存在图层,就将其移除
    if (hatInstance) {
      canvasFabric.remove(hatInstance)
    }
   // 将当前的模板添加为图层对象
    hatInstance = new fabric.Image(hatImage, {
      top: 0,
      left: 0,
      scaleX: screenWidth / hatImage.width,
      scaleY: screenWidth / hatImage.height,
      cornerColor: "#0b3a42",
      cornerStrokeColor: "#fff",
      cornerStyle: "circle",
      transparentCorners: false,
      rotatingPointOffset: 30
    });
   // 将图层对象设置为不可拉伸
    hatInstance.setControlVisible({
       mt: false, 
       mb: false, 
       ml: false, 
       mr: false, 
       bl: false, 
       br: false, 
       tl: false, 
       tr: false, 
       mtr: false, 
    })
   // 将图层添加到画布中
    canvasFabric.add(hatInstance);
  }

在默认情况下,fabric.js元素带有八个点来缩放任何对象,这里我们是不希望用户在水平或垂直方向对fabric对象进行拉伸的,可以通过setControlsVisibility()方法来设置其不可拉伸,该方法需要传入一个配置对象,该对象包含八个缩放点,都设置为false即可。​

最后我们将使用模板生成的图层添加到了画布中,这里使用到了add方法,这是fabric提供的事件,以下为fabric.js官方提供的常用事件:

  • object:added 添加图层
  • object:modified 编辑图层
  • object:removed 移除图层
  • selection:created 初次选中图层
  • selection:updated 图层选择变化
  • selection:cleared 清空图层选中

5. 输出图片

经过上面的步骤,我们就初始化了一个画布,画布的背景是我们上传的图片,画布上还有一个图层,这个图层是我们自己选择的模板。最后一步就是输出合成之后的图片了。下面来看看点击下载图片按钮之后会执行哪些操作:

function exportFunc() {
  // 隐藏选择框、上传下载按钮、canvas画布
  document.getElementsByClassName("main-box")[0].style.display = "none";
  document.getElementsByClassName("operation-btns")[0].style.display = "none";
  document.getElementById("cvs").style.display = "none";

  // 将画布生成URL,并赋值给对应标签进行展示
  const exportImage = document.getElementById("export-img");
  exportImage.style.display = "block";
  exportImage.src = canvasFabric.toDataURL({
    width: screenWidth,
    height: screenWidth
  });
  // 下载生成的图片
  window.confirm("是否下载头像") ? download(exportImage.src, "国庆风头像", 'image/png') : void 0
}

这里我们使用toDataURL方法来将画布实例对象生成图片,这是fabric对象的方法,可以将画布导出为图片,导出的一个Base64格式的URL。这样img标签获取到这个URL之后就能显示出来最终的图片了。​

最后,还添加了一个可有可无的功能,就是下载生成的头像,这里使用到了download.js库,该方法的第一个参数是图片的URL,第二个参数是下载图片的名称,第三个参数是图片的格式。​

这就是这个小应用的所有功能了,只是一个简单的实现,还存在一个BUG,主要提供一个实现的思路。我之前是没有接触过canvas以及画布的概念的,这次涨知识了。以后有时间多学习了一下相关的使用,interesting!​

到此这篇关于国庆节到了,利用JS实现一个生成国庆风头像的小工具 详解实现过程的文章就介绍到这了,更多相关利用JS实现一个生成国庆风头像内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript背投广告代码的完善
Apr 08 Javascript
JavaScript中的onerror事件概述及使用
Apr 01 Javascript
JavaScript动态创建div属性和样式示例代码
Oct 09 Javascript
浅谈javascript中createElement事件
Dec 05 Javascript
Javascript中call和apply函数的比较和使用实例
Feb 03 Javascript
通过设置CSS中的position属性来固定层的位置
Dec 14 Javascript
H5实现中奖记录逐行滚动切换效果
Mar 13 Javascript
Angular5中调用第三方js插件的方法
Feb 26 Javascript
小程序云开发教程如何使用云函数实现点赞功能
May 18 Javascript
vue中filters 传入两个参数 / 使用两个filters的实现方法
Jul 15 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
Aug 23 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
Nov 12 Javascript
Javascript设计模式之原型模式详细
JS数组方法some、every和find的使用详情
8个JS的reduce使用实例和reduce操作方式
Oct 05 #Javascript
JS 4个超级实用的小技巧 提升开发效率
Oct 05 #Javascript
JavaScript实现简单拖拽效果
Sep 15 #Javascript
一小时迅速入门Mybatis之bind与多数据源支持 Java API
Sep 15 #Javascript
Javascript之datagrid查询详解
Sep 15 #Javascript
You might like
缅甸的咖啡简史
2021/03/04 咖啡文化
asp和php下textarea提交大量数据发生丢失的解决方法
2008/01/20 PHP
PHP常用的文件操作函数经典收藏
2013/04/02 PHP
PHP编程之设置apache虚拟目录
2016/07/08 PHP
Laravel的Auth验证Token验证使用自定义Redis的例子
2019/09/30 PHP
js滚动条回到顶部的代码
2011/12/06 Javascript
jQuery中append()方法用法实例
2015/01/08 Javascript
jquery动态改变div宽度和高度
2015/02/09 Javascript
jQuery实现html表格动态添加新行的方法
2015/05/28 Javascript
jQuery实现的个性化返回底部与返回顶部特效代码
2015/10/30 Javascript
精通JavaScript的this关键字
2020/05/28 Javascript
Vue 2.0+Vue-router构建一个简单的单页应用(附源码)
2017/03/14 Javascript
VUE实现表单元素双向绑定(总结)
2017/08/08 Javascript
详解vue-router数据加载与缓存使用总结
2018/10/29 Javascript
对sklearn的使用之数据集的拆分与训练详解(python3.6)
2018/12/14 Python
Python给定一个句子倒序输出单词以及字母的方法
2018/12/20 Python
Python简单基础小程序的实例代码
2019/04/28 Python
Python Excel处理库openpyxl使用详解
2019/05/09 Python
windows10下安装TensorFlow Object Detection API的步骤
2019/06/13 Python
PyCharm+Qt Designer+PyUIC安装配置教程详解
2019/06/13 Python
对Python函数设计规范详解
2019/07/19 Python
基于pytorch中的Sequential用法说明
2020/06/24 Python
python 将html转换为pdf的几种方法
2020/12/29 Python
python中Pexpect的工作流程实例讲解
2021/03/02 Python
深入剖析webstorage[html5的本地数据处理]
2016/07/11 HTML / CSS
挪威太阳镜和眼镜网上商城:SmartBuyGlasses挪威
2016/08/20 全球购物
茱莉蔻美国官网:Jurlique美国
2020/11/24 全球购物
升职自荐书范文
2013/11/28 职场文书
DIY蛋糕店的创业计划书范文
2013/12/26 职场文书
《春雨》教学反思
2014/04/24 职场文书
汽修专业自荐信
2014/07/07 职场文书
党委书记个人对照检查材料
2014/09/15 职场文书
2014年库房工作总结
2014/11/26 职场文书
离职信范文
2015/06/23 职场文书
九年级化学教学反思
2016/02/22 职场文书
SQL Server表分区删除详情
2021/10/16 SQL Server