摘要:谷歌是通过来实现这个组件的,比较复杂谷歌的工具加载文件和截图文件有兴趣的同学可以看一下。高亮区域核心部分截图搞定了,接下来就是高亮区域了。
几乎所有的APP应用包括Web应用都需要一个意见反馈,这样才能了解用户对产品的意见和建议,以便于不断提升完善自己的产品。目前的反馈组件一般有两种,一种是打开一个反馈页面填写表单,另一种则是通过弹窗来完成,相比较而言第二种更加方便,而且更加容易组件化。
国内比较典型的有像知乎,百度这样类型的反馈组件
国外则有谷歌的
由于本人比较喜欢谷歌的material design,而且谷歌的反馈组件功能也比较齐全,仿照谷歌的组件写一个自己的通用组件。
下面是PC和手机上的效果图:
demo演示
项目github地址
首先根据谷歌的反馈插件分析需要实现哪些功能,这个组件在很多谷歌页面中都会出现,谷歌搜索页出现的位置是底部。
根据实际操作能知道这个组件至少要包含这些功能:
截取当前屏幕;
能编辑页面的高亮或者遮挡区域;
可以适应pc于手机;
知道功能后就能一步步开始实现它了。谷歌是通过iframe来实现这个组件的,比较复杂
谷歌的feedback工具加载文件:load.js和截图文件screenshot.min.js有兴趣的同学可以看一下。
这里使用自己的思路,使用现成模块来简单实现这个功能。
需要获取当前屏幕内容,第一时间反应是使用canvas了,先把dom元素画到canvas如何再生成图片,幸好有一个牛掰的模块叫做html2canvas,它可以将指定的DOM元素绘制到canvas上。
安装html2canvas
npm i html2canvas
html2canvas 1.0.0版本中可以使用作者提供的html2canvas-proxy模块来实现跨越资源代理。具体配置可以参考文档。顺便提一下,之前0.5.0版本中,html2canvas提供的代理方便不太好使,解决的方法是自己启动一个处理服务,在页面中遇到跨域图片资源,使用服务将图片转成base64格式然后回填到图片src属性上,这样来实现跨越图片截图。
如果页面上不仅仅有图片还有视频该怎么办呢,怎么截取视频图片呢?html2canvas是不支持截取video标签内容的,但是html2canvas截图时可以渲染元素的背景图片。那么如果可以获取视频当前播放的帧,把这一帧作为video标签的background,html2canvas就能读取到了。
如何读取video的帧,这个canvas的drawImage()方法就能做到(注意不能获取跨域的视频资源)。
let video = videoItem[0]; if(!video.style.backgroundImage) { let w = $(video).width(); let h = $(video).height(); $(video).after(""); let canvas = $(video).next("canvas").css({display: "none"}); let ctx = canvas.get(0).getContext("2d"); ctx.drawImage(video, 0, 0, w, h); try { video.style.backgroundImage = "url("+ canvas.get(0).toDataURL("image/png") +")"; }catch (e) { console.log(e) }finally { canvas.remove(); } }
做完这些准备就可以开始时截图了
html2canvas(document.body, { proxy: this.props.proxy || "", width: window.innerWidth, height: window.innerHeight, x: document.documentElement.scrollLeft || document.body.scrollLeft, y: document.documentElement.scrollTop || document.body.scrollTop, }).then((canvas) => { let src = canvas.toDataURL("image/png"); ... }).catch((e) => { });
注意:html2canvas v1.0.0使用promise,v0.5.0采用的是回调函数。
2.高亮区域核心部分截图搞定了,接下来就是高亮区域了。高亮分为两部分:
鼠标放在页面上识别当前鼠标是在哪个DOM元素上然后将这个DOM元素高亮,给用户提供一个快捷选区方式。
用户自己用鼠标选区一个高亮区域。
第二点很容易实现,只有鼠标按下时记录点击点位置,然后随着鼠标移动计算与初始点位置的差值就能得到一个区域了,那么怎么识别鼠标是放在哪个DOM元素上呢?有一个Web API可以轻松实现这个功能那就是elementsFromPoint。
elementsFromPoint() 方法可以获取到当前视口内指定坐标处,由里到外排列的所有元素。
使用方法很简单,只要给x,y坐标就行了。
var elements = document.elementsFromPoint(x, y);
这个方法返回的是一个包含当前鼠标所在位置的DOM元素数组。元素在数组中的位置与元素的z轴位置和元素包含关系有关,z轴越大位置越靠前,子元素比父元素靠前。
如果是这个结构那么当鼠标在img标签上document.elementsFromPoint(x, y)返回的值是这样的
[img, p, div]
得到元素后那么后续的操作就简单了,在一个半透明的黑色区域上抠出透明部分,显然css是实现不了的,那么就上canvas吧。
首先要画一个半透明的遮罩:
let canvas = this.refs.canvas; if (!this.ctx) { this.ctx = canvas.getContext("2d"); } let docWidth = document.body.clientWidth, docHeight = document.body.clientHeight; if(docHeight < window.innerHeight) { docHeight = window.innerHeight; } canvas.width = docWidth; canvas.height = docHeight; canvas.style.width = docWidth; canvas.style.height = docHeight; this.ctx.fillStyle = "rgba(0,0,0,0.3)"; this.ctx.fillRect(0, 0, docWidth, docHeight);
准备完遮罩就可以开始扣图了。通过elementsFromPoint的到元素后使用getBoundingClientRect()方法得到元素的位置信息。 getBoundingClientRect()用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置以及元素宽高。
宽高,位置信息都有了就可以开始绘制了:
this.ctx.lineWidth = "5"; this.ctx.strokeStyle = "#FEEA4E"; this.ctx.rect(x, y, width, height); this.ctx.stroke(); this.ctx.clearRect(x, y, width, height);
同理如果不是高亮而是遮挡只要把清除区域换成绘制一个半透明黑色区域就可以了。
要注意每次画新区域时要清除上次绘制的内容所以每次都得初始化一次canvas内容。
由于手机页面中的反馈界面与PC差距太大所以不能采用同一套模板,通过一个state来区分该渲染那种类型。在组件willMount的时候判断设备类型
let device = "pc"; let ua = navigator.userAgent; let ipad = ua.match(/(iPad).*OSs([d_]+)/), isIphone = !ipad && ua.match(/(iPhonesOS)s([d_]+)/), isAndroid = ua.match(/(Android)s+([d.]+)/), isMobile = isIphone || isAndroid; if (isMobile) { device = "mobile"; this.setState({ device: device, }); }
得到设备后根据设备进行渲染
{ this.state.device == "pc"?: }
需要注意的是有些手机浏览器在打开输入法后会导致页面窗口变化所以需要监听窗口变化去做适配调整
2.使用 1.安装:使用npm
npm install react-googlefeedback --save-dev2.使用
react中:
import React from "react"; import ReactDOM from "react-dom"; import Feedback from "react-googlefeedback"; import "react-googlefeedback/dist/style.css"; const license = `如出于法律原因需要请求更改内容,请前往 法律帮助 页面。系统可能已将部分 帐号和系统信息 发送给Google。我们将根据自己的 隐私权政策和服务条款 使用您提供的信息帮助解决技术问题和改进我们的服务。`; class Page extends React.Component { constructor() { super(); this.state = { open: false, } } open() { this.setState({ open: true, }) } cancel() { this.setState({ open: false, }) } send(data) { console.log(data) } render() { return ({ this.state.open?) } } ReactDOM.render(:null } , document.getElementById("main"));
在页面中引入js文件使用:
3.参数说明
react 组件:
参数 | 功能 | 类型 | 是否必填 |
---|---|---|---|
theme | 设置组件主题颜色 | string | ✗ 默认值 #3986FF |
cancel | 取消按钮处理函数 | function | ✓ |
send | 发送按钮处理函数,会传回收集的数据 | function | ✓ |
license | 协议内容 | html字符串 | ✗ 默认值为谷歌的隐私条款协议 |
proxy | 代理地址,如果页面中存在跨域资源可以设置这个值 | string | ✗ 默认空值 |
页面中直接引用:
参数 | 功能 | 类型 | 是否必填 |
---|---|---|---|
container | 组件容器元素 | element | ✓ |
trigger | 用于触发组件打开的元素 | element | ✓ |
theme | 设置组件主题颜色 | string | ✗ 默认值 #3986FF |
license | 协议内容 | html字符串 | ✗ 默认值为谷歌的隐私条款协议 |
proxy | 代理地址,如果页面中存在跨域资源可以设置这个值 | string | ✗ 默认空值 |
send | 发送按钮处理函数,会传回收集的数据 | function | ✓ |
需要启动一个服务用于代理。
首先安装html2canvas-proxy
npm install html2canvas-proxy --save
在node中使用代理
var proxy = require("html2canvas-proxy"); var express = require("express"); var app = express(); app.use("/", proxy());
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/95083.html
摘要:实现不定期更新技巧前端掘金技巧,偶尔更新。统一播放效果实现打字效果动画前端掘金前端开源项目周报前端掘金由出品的前端开源项目周报第四期来啦。 Web 推送技术 - 掘金腾讯云技术社区-掘金主页持续为大家呈现云计算技术文章,欢迎大家关注! 作者:villainthr 摘自 前端小吉米 伴随着今年 Google I/O 大会的召开,一个很火的概念--Progressive Web Apps ...
摘要:官网地址聊天机器人插件开发实例教程一创建插件在系统技巧使你的更加专业前端掘金一个帮你提升技巧的收藏集。我会简单基于的简洁视频播放器组件前端掘金使用和实现购物车场景前端掘金本文是上篇文章的序章,一直想有机会再次实践下。 2道面试题:输入URL按回车&HTTP2 - 掘金通过几轮面试,我发现真正那种问答的技术面,写一堆项目真不如去刷技术文章作用大,因此刷了一段时间的博客和掘金,整理下曾经被...
摘要:你可以利用渐变和填充等功能来创建简单的形状,并且可以访问几乎所有苹果默认提供的控件。可以帮你生成苹果指导方针所说的各种分辨率图标,包括设备和非设备。是一个用来管理苹果推送通知的脚本。 这里推荐20个可以帮你简化iOS app开发流程的工具。很多开发者都使用过这些工具,涉及原型和设计、编程、测试以及最后的营销,基本上涵盖了整个开发过程。 原型和设计 有了一个很好的创意后,你要做...
阅读 1048·2021-11-18 10:02
阅读 1304·2021-09-23 11:22
阅读 2606·2021-08-21 14:08
阅读 1636·2019-08-30 15:55
阅读 1720·2019-08-30 13:45
阅读 3139·2019-08-29 16:52
阅读 3091·2019-08-29 12:18
阅读 1636·2019-08-26 13:36