viewerjs 如何新增下载图片功能(npm包补丁)

文章目录

    • 先实现正常的效果
    • 实现下载图片
    • 改变viewerjs的build函数
    • 源码改变之后,执行npm i 之后node_modules源码又变回了原样

1、viwerjs所有功能都很完善,但唯独缺少了图片的下载
2、需求:在用viwerjs旋转图片后,可以直接下载旋转后的图片

效果:
在这里插入图片描述

先实现正常的效果

1、安装v-viewer(一个对viwerjs的使用方式优化的npm包)

npm i v-viewer

2、

main.js文件 (vue2版本)

import Vue from 'vue'
import App from './App.vue'
//哪怕使用v-viewer也需要导入正常的viwerjs的css文件
import 'viewerjs/dist/viewer.css'
import Viewer from 'v-viewer'Vue.use(Viewer, {defaultOptions: {//里面可以填一些配置项,这里我先不填}
})new Vue({render: h => h(App),
}).$mount('#app')

app.vue文件中使用组件

<template><div class="main"><viewer ref="viewer"><imgsrc="https://img1.baidu.com/it/u=413643897,2296924942&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500"alt=""data-uid="uid字段"ref="img"/></viewer></div>
</template>
<script>export default {data() {return {};},props: {},watch: {},mounted() {},created() {},methods: {},};
</script>
<style scoped>
</style>

效果
在这里插入图片描述

实现下载图片

在main.js中添加配置项
可以先看下面build函数的改动,再看main中的download

import Vue from 'vue'
import App from './App.vue'
import 'viewerjs/dist/viewer.css'
import Viewer from 'v-viewer'
Vue.config.productionTip = false
//可以先忽略base64toBlob函数,就是个base64文件转blob的函数
function base64toBlob(dataurl) {var arr = dataurl.split(','),mime = arr[0].match(/:(.*?);/)[1],bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new Blob([u8arr], {type: mime});
}
Vue.use(Viewer, {defaultOptions: {//下载事件的回调download(viewer) {//当前显示图片的索引const index = viewer.index//所有图片构成的数组const list = viewer.images//当前显示的图片const ima = list[index]const canvas = document.createElement('canvas') //获取canvas//对应的CanvasRenderingContext2D对象(画笔)let img = new Image() //创建新的图片对象let base64 = ''; //base64 img.src = ima.src + '?' + new Date().getTime();//如果您仅仅是下载当前图片, img.src便是当前的图片地址   //下面的内容就完全可以不用看了//自行百度:前端拿到图片地址,如何下载图片const rotate = viewer.imageData.rotatelet x, yconst type = rotate / 90 % 4img.setAttribute("crossOrigin", 'Anonymous')img.onload = function () { //图片加载完,再draw 和 toDataURLlet width = img.widthlet height = img.heightconst flg = width == height//这里写的不是很好(4个if判断),有更好的书写方式可以告知我一下,除了(switch、改成object的形式)//0、1、2、3对应旋转0°、90°、180°、270°//0的时候不需要特处理if (type == 0) {x = 0;y = 0} else if (type == 1) {//1的时候需要考虑一种清空,如果他是个矩形图片,也就是宽高不相等//在旋转90°后,我们需要调整canvas的宽高、同理270°一样x = height;y = 0;if (!flg) {const blg = widthwidth = heightheight = blg}} else if (type == 2) {x = width;y = height;} else if (type == 3) {x = 0;y = height;if (!flg) {const blg = widthwidth = heightheight = blg}}canvas.width = widthcanvas.height = heightlet ctx = canvas.getContext("2d")ctx.translate(x, y);ctx.rotate(rotate * Math.PI / 180);ctx.drawImage(img, 0, 0, img.width, img.height);//图片转base64base64 = canvas.toDataURL("image/png");//base64转链接,该链接便是用户旋转后的图片了//如果想下载该图片,直接定义a标签,然后触发点击事件下载即可,可自行百度拿到链接,如何下载链接的内容console.log('url___', URL.createObjectURL(base64toBlob(base64)));}}}
})new Vue({render: h => h(App),router,
}).$mount('#app')

找到viwerjs源文件
/node_modules/viewerjs/dist/viewer.js
为什么不去v-viewer文件下找呢?上面说了,v-viewer是对viwwerjs的封装使用,似乎没有改动源码
在这里插入图片描述
在该文件下搜索

toolbar.appendChild(list)

该代码存在于build函数下面,作用是构建底部的工具按钮

改变viewerjs的build函数

build函数源代码(看我写的注释)
其中注释最多的地方便是对源码的改动

{key: "build",value: function build() {if (this.ready) {return;}//关键变量之一,当前viewerjs挂载的domvar element = this.element,//关键变量,当前的viewer的option配置项options = this.options;var parent = element.parentNode;var template = document.createElement('div');template.innerHTML = TEMPLATE;var viewer = template.querySelector(".".concat(NAMESPACE, "-container"));var title = viewer.querySelector(".".concat(NAMESPACE, "-title"));//toolbar 关键变量之一,下面代码是获取toolbar的dom元素var toolbar = viewer.querySelector(".".concat(NAMESPACE, "-toolbar"));var navbar = viewer.querySelector(".".concat(NAMESPACE, "-navbar"));var button = viewer.querySelector(".".concat(NAMESPACE, "-button"));var canvas = viewer.querySelector(".".concat(NAMESPACE, "-canvas"));this.parent = parent;this.viewer = viewer;this.title = title;this.toolbar = toolbar;this.navbar = navbar;this.button = button;this.canvas = canvas;this.footer = viewer.querySelector(".".concat(NAMESPACE, "-footer"));this.tooltipBox = viewer.querySelector(".".concat(NAMESPACE, "-tooltip"));this.player = viewer.querySelector(".".concat(NAMESPACE, "-player"));this.list = viewer.querySelector(".".concat(NAMESPACE, "-list"));viewer.id = "".concat(NAMESPACE).concat(this.id);title.id = "".concat(NAMESPACE, "Title").concat(this.id);addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar));toggleClass(button, CLASS_HIDE, !options.button);if (options.keyboard) {button.setAttribute('tabindex', 0);}if (options.backdrop) {addClass(viewer, "".concat(NAMESPACE, "-backdrop"));if (!options.inline && options.backdrop !== 'static') {setData(canvas, DATA_ACTION, 'hide');}}if (isString(options.className) && options.className) {// In case there are multiple class namesoptions.className.split(REGEXP_SPACES).forEach(function (className) {addClass(viewer, className);});}if (options.toolbar) {var list = document.createElement('ul');var custom = isPlainObject(options.toolbar);var zoomButtons = BUTTONS.slice(0, 3);var rotateButtons = BUTTONS.slice(7, 9);var scaleButtons = BUTTONS.slice(9);if (!custom) {addClass(toolbar, getResponsiveClass(options.toolbar));}//关键函数之一,forEach,是对传统foreach的1封装//BUTTONS关键变量之一,是一个数组,里面存放的是底部操作工具栏信息//下面的foreach的解读:根据BUTTONS这个数组构建出底部工具栏按钮,并且给对应的按钮添加一些属性信息forEach(custom ? options.toolbar : BUTTONS, function (value, index) {var deep = custom && isPlainObject(value);var name = custom ? hyphenate(index) : value;var show = deep && !isUndefined(value.show) ? value.show : value;if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) {return;}var size = deep && !isUndefined(value.size) ? value.size : value;var click = deep && !isUndefined(value.click) ? value.click : value;var item = document.createElement('li');if (options.keyboard) {item.setAttribute('tabindex', 0);}item.setAttribute('role', 'button');addClass(item, "".concat(NAMESPACE, "-").concat(name));if (!isFunction(click)) {setData(item, DATA_ACTION, name);}if (isNumber(show)) {addClass(item, getResponsiveClass(show));}if (['small', 'large'].indexOf(size) !== -1) {addClass(item, "".concat(NAMESPACE, "-").concat(size));} else if (name === 'play') {addClass(item, "".concat(NAMESPACE, "-large"));}if (isFunction(click)) {addListener(item, EVENT_CLICK, click);}list.appendChild(item);});toolbar.appendChild(list);} else {addClass(toolbar, CLASS_HIDE);}//代码走到这一步,表示toolbar基本按钮已经配置完成了//在这里来添加我们自己想加的按钮//下面代码是我添加的功能//开始//isFunction:判断传递的download是不是对象,isFunction是viwerjs作者封装好的方法//addListener:给某个dom元素添加事件监听,同样是viwerjs作者封装好的//addListener(参数一是dom元素,参数二是事件名称,参数三是事件回调)//addListener会有参数4,参数4是元素监听器的一些配置项,非必填if(isFunction(options.download)){//创建保存按钮var download = document.createElement("li")var that = this//给按钮加事件addListener(download,EVENT_CLICK,function(){// options.download就是我上面main.js传递的download函数//在点击该按钮后,同时执行download回调//传递参数,that.element是viwerjs挂载的dom,//that.element.viewer,viwerjs挂载后会为挂载的元素添加viewer属性(巨全的属性,里面啥都有),可以说我们拿到viewer基本所有的内容都可以拿到了options.download(that.element.viewer)})//addclass是别人封装好的,给元素加类名,加完类名后直接改变css样式就行了,或者直接用行内styleaddClass(download,'viewerjs-download')list.appendChild(download)}///结束if (!options.rotatable) {var rotates = toolbar.querySelectorAll('li[class*="rotate"]');addClass(rotates, CLASS_INVISIBLE);forEach(rotates, function (rotate) {toolbar.appendChild(rotate);});}if (options.inline) {addClass(button, CLASS_FULLSCREEN);setStyle(viewer, {zIndex: options.zIndexInline});if (window.getComputedStyle(parent).position === 'static') {setStyle(parent, {position: 'relative'});}parent.insertBefore(viewer, element.nextSibling);} else {addClass(button, CLASS_CLOSE);addClass(viewer, CLASS_FIXED);addClass(viewer, CLASS_FADE);addClass(viewer, CLASS_HIDE);setStyle(viewer, {zIndex: options.zIndex});var container = options.container;if (isString(container)) {container = element.ownerDocument.querySelector(container);}if (!container) {container = this.body;}container.appendChild(viewer);}if (options.inline) {this.render();this.bind();this.isShown = true;}this.ready = true;if (isFunction(options.ready)) {addListener(element, EVENT_READY, options.ready, {once: true});}if (dispatchEvent(element, EVENT_READY) === false) {this.ready = false;return;}if (this.ready && options.inline) {this.view(this.index);}}/*** Get the no conflict viewer class.* @returns {Viewer} The viewer class.*/}

源码改变之后,执行npm i 之后node_modules源码又变回了原样

利用patch-package解决该问题

安装

npm i patch-package

安装完成后,执行命令

 npx patch-package viewerjs//viewerjs是我们修改node_modules中的源码文件名 npx patch-package为固定内容

执行命令后发现,项目多了一个patches文件,这个便是对源码的补丁,我们需要把这个文件上传至项目仓库中,然后你同事拉下代码,执行npm i后会自动使用我们写的补丁
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/77027.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

规划模型Matlab代码

文章目录 数学规划定义一般形式分类 1.线性规划(linear programming)2.非线性规划(nonlinear programming)3. 整数规划(integer programming)4. 0-1规划(0-1 programming)5. 最大最小化模型6. 多目标规划模型7.敏感性分析&#xff08;对权重&#xff09;[例题] 数学规划定义 数…

Stable Diffusion - SDXL 1.0 全部样式设计与艺术家风格的配置与提示词

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132072482 来源于 Anna Dittmann 安娜迪特曼&#xff0c;艺术家风格的图像&#xff0c;融合幻想、数字艺术、纹理等样式。 SDXL 是 Stable Diffus…

Git常见问题

git clone 提示OpenSSL SSL_read git clone 时提示Connection was reset, errno 10054类错误 fatal: unable to acce ss https://github.com/fex-team/ueditor.git/: OpenSSL SSL_read: Connection was reset, errno 10054 备注&#xff1a;以下方法只是归纳整理&#xff0c;…

【零基础学Rust | 基础系列 | 基础语法】变量,数据类型,运算符,控制流

文章目录 简介&#xff1a;一&#xff0c;变量1&#xff0c;变量的定义2&#xff0c;变量的可变性3&#xff0c;变量的隐藏 二、数据类型1&#xff0c;标量类型2&#xff0c;复合类型 三&#xff0c;运算符1&#xff0c;算术运算符2&#xff0c;比较运算符3&#xff0c;逻辑运算…

Apache Flink概述

Flink 是构建在数据流之上的一款有状态的流计算框架&#xff0c;通常被人们称为第三代大数据分析方案 第一代大数据处理方案&#xff1a;基于Hadoop的MapReduce 静态批处理 | Storm 实时流计算 &#xff0c;两套独立的计算引擎&#xff0c;难度大&#xff08;2014年9月&#x…

Hyperledger Fabric 使用 CouchDB 和复杂智能合约开发

前言 在上个实验中&#xff0c;我们已经实现了简单智能合约实现及客户端开发&#xff0c;但该实验中智能合约只有基础的增删改查功能&#xff0c;且其中的数据管理功能与传统 MySQL 比相差甚远。本文将在前面实验的基础上&#xff0c;将 Hyperledger Fabric 的默认数据库支持 …

Kafka3.0.0版本——Broker(Zookeeper服务端存储的Kafka相关信息)

目录 一、启动zookeeper集群及kafka集群服务启动1.1、先启动三台zookeeper集群服务&#xff0c;再启动三台kafka集群服务1.2、使用PrettyZoo连接zookeeper客户端工具 二、在zookeeper服务端存储的Kafka相关信息 一、启动zookeeper集群及kafka集群服务启动 1.1、先启动三台zook…

C++初阶引用

目录 引用引用的特性使用输出型参数作返回值小总结引用的权限引用和指针 引用 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如周树人&#xff0c;在外…

探索创意之路:稳定扩散AI绘画指南

文章目录 引言第一部分&#xff1a;了解稳定扩散AI绘画1.1 稳定扩散AI绘画简介1.2 稳定扩散AI绘画的优势 第二部分&#xff1a;使用稳定扩散AI绘画2.1 获取稳定扩散AI绘画工具2.2 准备绘画素材和设置参数2.3 进行AI绘画 第三部分&#xff1a;发挥创意&#xff0c;创作精彩绘画3…

阿里云AK创建

要在阿里云上创建 Access Key&#xff08;AK&#xff09;&#xff0c;您需要按照以下步骤进行操作&#xff1a; 登录到阿里云控制台&#xff08;[https://www.aliyun.com/?utm_contentse_1014243503)&#xff09;。 点击右上方的主账号&#xff0c;点击“AccessKey管理”。 …

P1064 [NOIP2006 提高组] 金明的预算方案 (依赖背包问题)(内附封面)

[NOIP2006 提高组] 金明的预算方案 题目描述 金明今天很开心&#xff0c;家里购置的新房就要领钥匙了&#xff0c;新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是&#xff0c;妈妈昨天对他说&#xff1a;“你的房间需要购买哪些物品&#xff0c;怎么布置&#xff0…

R语言【Tidyverse、Tidymodel】的机器学习方法

机器学习已经成为继理论、实验和数值计算之后的科研“第四范式”&#xff0c;是发现新规律&#xff0c;总结和分析实验结果的利器。机器学习涉及的理论和方法繁多&#xff0c;编程相当复杂&#xff0c;一直是阻碍机器学习大范围应用的主要困难之一&#xff0c;由此诞生了Python…

python人工智能可以干什么,python人工智能能干什么

大家好&#xff0c;给大家分享一下python做人工智能需要什么水平&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 人工智能包含常用机器学习和深度学习两个很重要的模块&#xff0c;而python拥有matplotlib、Numpy、sklearn、keras等大量的…

【深度学习笔记】深度学习框架

本专栏是网易云课堂人工智能课程《神经网络与深度学习》的学习笔记&#xff0c;视频由网易云课堂与 deeplearning.ai 联合出品&#xff0c;主讲人是吴恩达 Andrew Ng 教授。感兴趣的网友可以观看网易云课堂的视频进行深入学习&#xff0c;视频的链接如下&#xff1a; 神经网络和…

snap xxx has “install-snap“ change in progress

error description * 系重复安装&#xff0c;进程冲突 solution 展示snap的改变 然后sudo snap abort 22即可终止该进程 之后重新运行install command&#xff5e;&#xff5e; PS: ubuntu有时候加载不出来&#xff0c;执行resolvectl flush-caches&#xff0c;清除dns缓存…

【计算机视觉 | 图像分割】arxiv 计算机视觉关于图像分割的学术速递(8 月 1 日论文合集)

文章目录 一、分割|语义相关(16篇)1.1 DPMix: Mixture of Depth and Point Cloud Video Experts for 4D Action Segmentation1.2 Investigating and Improving Latent Density Segmentation Models for Aleatoric Uncertainty Quantification in Medical Imaging1.3 Domain Ada…

网络音频终端音频编码解码终端

网络对讲终端SV-7011V 网络对讲终端SV-7011V&#xff0c;采用了ARM音频DSP架构&#xff0c;集网络对讲、网络广播、监听等功能于一身&#xff0c;内置麦克风、配置line out、line in、Mic in功能输出接口&#xff0c;适用于学校&#xff0c;机场&#xff0c;广场等场所。 产品…

纯css实现九宫格图片

本篇文章所分享的内容主要涉及到结构伪类选择器&#xff0c;不熟悉的小伙伴可以了解一下&#xff0c;在常用的css选择器中我也有分享相关内容。 话不多说&#xff0c;接下来我们直接上代码&#xff1a; <!DOCTYPE html> <html lang"en"><head>&l…

51单片机(普中HC6800-EM3 V3.0)实验例程软件分析 实验一 点亮第一个LED

目录 前言 一、原理图及知识点介绍 1.1、LED原理图 1.2、MCU51原理图 二、代码分析 知识点一&#xff1a;#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 知识点二&#xff1a;你知道sfr P0 0x80;是怎么来的呢为什么要赋值0x80&#xff…

Stable Diffusion AI绘画学习指南【本地环境搭建win+mac】

一、硬件配配置要求 系统&#xff1a;windows 10 / Mac os 硬盘&#xff1a;C 盘预留 15GB 以上&#xff0c;其他盘 50GB 以上,Stable Ddiffusion的很多大模型都是以 GB 起步。 显卡&#xff1a;4GB 以上&#xff0c;建议 8GB, 效率高&#xff0c;能玩大尺寸的图 CPU&…