贴个官网:http://nhn.github.io/tui.image-editor/latest/ImageEditor#getImageName
引入tui-image-editor
npm install tui-image-editor
1.基础使用,实现效果
<template>
<div class="image-view">
<div class="container">
<div ref="tui-image-editor" id="tui-image-editor"></div>
</div>
<div class="bottom">
<el-button @click="downloadImg">下载</el-button>
<el-button type="primary" @click="upload">上传</el-button>
</div>
</div>
</template>
<script>
import { base64ToFile, fileLocalDownLoad } from "@/utils/file-util";
import "tui-image-editor/dist/tui-image-editor.css";
import "tui-color-picker/dist/tui-color-picker.css";
import ImageEditor from "tui-image-editor";
const locale_zh = {
ZoomIn: "放大",
ZoomOut: "缩小",
Hand: "手掌",
History: "历史",
Resize: "调整宽高",
Crop: "裁剪",
DeleteAll: "全部删除",
Delete: "删除",
Undo: "撤销",
Redo: "反撤销",
Reset: "重置",
Flip: "镜像",
Rotate: "旋转",
Draw: "画",
Shape: "形状标注",
Icon: "图标标注",
Text: "文字标注",
Mask: "遮罩",
Filter: "滤镜",
Bold: "加粗",
Italic: "斜体",
Underline: "下划线",
Left: "左对齐",
Center: "居中",
Right: "右对齐",
Color: "颜色",
"Text size": "字体大小",
Custom: "自定义",
Square: "正方形",
Apply: "应用",
Cancel: "取消",
"Flip X": "X 轴",
"Flip Y": "Y 轴",
Range: "区间",
Stroke: "描边",
Fill: "填充",
Circle: "圆",
Triangle: "三角",
Rectangle: "矩形",
Free: "曲线",
Straight: "直线",
Arrow: "箭头",
"Arrow-2": "箭头2",
"Arrow-3": "箭头3",
"Star-1": "星星1",
"Star-2": "星星2",
Polygon: "多边形",
Location: "定位",
Heart: "心形",
Bubble: "气泡",
"Custom icon": "自定义图标",
"Load Mask Image": "加载蒙层图片",
Grayscale: "灰度",
Blur: "模糊",
Sharpen: "锐化",
Emboss: "浮雕",
"Remove White": "除去白色",
Distance: "距离",
Brightness: "亮度",
Noise: "噪音",
"Color Filter": "彩色滤镜",
Sepia: "棕色",
Sepia2: "棕色2",
Invert: "负片",
Pixelate: "像素化",
Threshold: "阈值",
Tint: "色调",
Multiply: "正片叠底",
Blend: "混合色",
Width: "宽度",
Height: "高度",
"Lock Aspect Ratio": "锁定宽高比例",
};
const customTheme = {
"common.bi.image": "", // 在这里换上你喜欢的logo图片
"common.bisize.width": "0px",
"common.bisize.height": "0px",
"common.backgroundImage": "none",
"common.backgroundColor": "#f3f4f6",
"common.border": "1px solid #444",
// header
"header.backgroundImage": "none",
"header.backgroundColor": "#f3f4f6",
"header.border": "0px",
// load button
"loadButton.backgroundColor": "#fff",
"loadButton.border": "1px solid #ddd",
"loadButton.color": "#222",
"loadButton.fontFamily": "NotoSans, sans-serif",
"loadButton.fontSize": "12px",
"loadButton.display": "none", // 可以直接隐藏掉
// download button
"downloadButton.backgroundColor": "#fdba3b",
"downloadButton.border": "1px solid #fdba3b",
"downloadButton.color": "#fff",
"downloadButton.fontFamily": "NotoSans, sans-serif",
"downloadButton.fontSize": "12px",
"downloadButton.display": "none", // 可以直接隐藏掉
// icons default
"menu.normalIcon.color": "#666",
"menu.activeIcon.color": "#555555",
"menu.disabledIcon.color": "#434343",
"menu.hoverIcon.color": "#e9e9e9",
"submenu.normalIcon.color": "#666",
"submenu.activeIcon.color": "#e9e9e9",
"menu.iconSize.width": "24px",
"menu.iconSize.height": "24px",
"submenu.iconSize.width": "32px",
"submenu.iconSize.height": "32px",
// submenu primary color
"submenu.backgroundColor": "#1e1e1e",
"submenu.partition.color": "#858585",
// submenu labels
"submenu.normalLabel.color": "#858585",
"submenu.normalLabel.fontWeight": "lighter",
"submenu.activeLabel.color": "#fff",
"submenu.activeLabel.fontWeight": "lighter",
// checkbox style
"checkbox.border": "1px solid #ccc",
"checkbox.backgroundColor": "#fff",
// rango style
"range.pointer.color": "#fff",
"range.bar.color": "#666",
"range.subbar.color": "#d1d1d1",
"range.disabledPointer.color": "#414141",
"range.disabledBar.color": "#282828",
"range.disabledSubbar.color": "#414141",
"range.value.color": "#fff",
"range.value.fontWeight": "lighter",
"range.value.fontSize": "11px",
"range.value.border": "1px solid #353535",
"range.value.backgroundColor": "#151515",
"range.title.color": "#fff",
"range.title.fontWeight": "lighter",
// colorpicker style
"colorpicker.button.border": "1px solid #1e1e1e",
"colorpicker.title.color": "#fff",
};
export default {
name: "imageViewer",
data() {
return {
instance: null,
};
},
created() {
this.init();
},
methods: {
init() {
this.$nextTick(() => {
this.instance = new ImageEditor(
document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg",
name: "image",
},
menu: [
"resize",
"crop",
"rotate",
"draw",
"shape",
"icon",
"text",
"filter",
], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
initMenu: "resize", // 默认打开的菜单项
menuBarPosition: "bottom", // 菜单所在的位置
locale: locale_zh, // 本地化语言为中文
theme: customTheme, // 自定义样式
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
// 调整图片显示位置
document.getElementsByClassName("tui-image-editor-main")[0].style.top =
"0px";
});
},
// 文件下载
downloadImg() {
const base64String = this.instance.toDataURL();
const file = base64ToFile(base64String, "图片");
fileLocalDownLoad(file, "图片");
},
//上传
upload() {
// blob 转换成 File 对象
let blob = base64ToFile(this.instance.toDataURL(), "图片");
let file = new window.File([blob], blob.name, { type: blob.type });
let form = new FormData();
form.append("file", file);
},
},
};
</script>
<style lang="scss" scoped>
.image-view {
height: 100%;
width: 100%;
.container {
height: 86vh;
text-align: center;
}
.bottom {
display: flex;
justify-content: flex-end;
margin: 10px;
}
}
</style>
file-utils方法
// 将文base64转文件对象
export const base64ToFile = (base64, fileName = '') => {
let arr = base64.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
let blob = new Blob([u8arr], {
type: mime
})
blob.lastModifiedDate = new Date()
blob.name = fileName
// console.log('functionbase64ToFile -> blob', blob) // file
return blob
}
// 文件下载
export const fileLocalDownLoad = (blob, fileName) => {
let downloadElement = document.createElement('a')
let href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = decodeURIComponent(fileName)
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement)
window.URL.revokeObjectURL(href)
}
// 节流
export function rafThrottle(fn) {
let locked = false;
return function (...args) {
if (locked) return;
locked = true;
window.requestAnimationFrame(_ => {
fn.apply(this, args);
locked = false;
});
};
}
2.根据需求通过滚轮实现图片编辑器内,图片放大缩小、拖拽功能
<template>
<div class="image-view">
<div class="container">
<div ref="tui-image-editor" id="tui-image-editor"></div>
</div>
<div class="bottom">
<el-button @click="downloadImg">下载</el-button>
<el-button type="primary" @click="upload">上传</el-button>
</div>
</div>
</template>
<script>
import {
base64ToFile,
fileLocalDownLoad,
rafThrottle,
} from "@/utils/file-util";
import "tui-image-editor/dist/tui-image-editor.css";
import "tui-color-picker/dist/tui-color-picker.css";
import ImageEditor from "tui-image-editor";
const locale_zh = {
ZoomIn: "放大",
ZoomOut: "缩小",
Hand: "手掌",
History: "历史",
Resize: "调整宽高",
Crop: "裁剪",
DeleteAll: "全部删除",
Delete: "删除",
Undo: "撤销",
Redo: "反撤销",
Reset: "重置",
Flip: "镜像",
Rotate: "旋转",
Draw: "画",
Shape: "形状标注",
Icon: "图标标注",
Text: "文字标注",
Mask: "遮罩",
Filter: "滤镜",
Bold: "加粗",
Italic: "斜体",
Underline: "下划线",
Left: "左对齐",
Center: "居中",
Right: "右对齐",
Color: "颜色",
"Text size": "字体大小",
Custom: "自定义",
Square: "正方形",
Apply: "应用",
Cancel: "取消",
"Flip X": "X 轴",
"Flip Y": "Y 轴",
Range: "区间",
Stroke: "描边",
Fill: "填充",
Circle: "圆",
Triangle: "三角",
Rectangle: "矩形",
Free: "曲线",
Straight: "直线",
Arrow: "箭头",
"Arrow-2": "箭头2",
"Arrow-3": "箭头3",
"Star-1": "星星1",
"Star-2": "星星2",
Polygon: "多边形",
Location: "定位",
Heart: "心形",
Bubble: "气泡",
"Custom icon": "自定义图标",
"Load Mask Image": "加载蒙层图片",
Grayscale: "灰度",
Blur: "模糊",
Sharpen: "锐化",
Emboss: "浮雕",
"Remove White": "除去白色",
Distance: "距离",
Brightness: "亮度",
Noise: "噪音",
"Color Filter": "彩色滤镜",
Sepia: "棕色",
Sepia2: "棕色2",
Invert: "负片",
Pixelate: "像素化",
Threshold: "阈值",
Tint: "色调",
Multiply: "正片叠底",
Blend: "混合色",
Width: "宽度",
Height: "高度",
"Lock Aspect Ratio": "锁定宽高比例",
};
const customTheme = {
"common.bi.image": "", // 在这里换上你喜欢的logo图片
"common.bisize.width": "0px",
"common.bisize.height": "0px",
"common.backgroundImage": "none",
"common.backgroundColor": "#f3f4f6",
"common.border": "1px solid #444",
// header
"header.backgroundImage": "none",
"header.backgroundColor": "#f3f4f6",
"header.border": "0px",
// load button
"loadButton.backgroundColor": "#fff",
"loadButton.border": "1px solid #ddd",
"loadButton.color": "#222",
"loadButton.fontFamily": "NotoSans, sans-serif",
"loadButton.fontSize": "12px",
"loadButton.display": "none", // 可以直接隐藏掉
// download button
"downloadButton.backgroundColor": "#fdba3b",
"downloadButton.border": "1px solid #fdba3b",
"downloadButton.color": "#fff",
"downloadButton.fontFamily": "NotoSans, sans-serif",
"downloadButton.fontSize": "12px",
"downloadButton.display": "none", // 可以直接隐藏掉
// icons default
"menu.normalIcon.color": "#666",
"menu.activeIcon.color": "#555555",
"menu.disabledIcon.color": "#434343",
"menu.hoverIcon.color": "#e9e9e9",
"submenu.normalIcon.color": "#666",
"submenu.activeIcon.color": "#e9e9e9",
"menu.iconSize.width": "24px",
"menu.iconSize.height": "24px",
"submenu.iconSize.width": "32px",
"submenu.iconSize.height": "32px",
// submenu primary color
"submenu.backgroundColor": "#1e1e1e",
"submenu.partition.color": "#858585",
// submenu labels
"submenu.normalLabel.color": "#858585",
"submenu.normalLabel.fontWeight": "lighter",
"submenu.activeLabel.color": "#fff",
"submenu.activeLabel.fontWeight": "lighter",
// checkbox style
"checkbox.border": "1px solid #ccc",
"checkbox.backgroundColor": "#fff",
// rango style
"range.pointer.color": "#fff",
"range.bar.color": "#666",
"range.subbar.color": "#d1d1d1",
"range.disabledPointer.color": "#414141",
"range.disabledBar.color": "#282828",
"range.disabledSubbar.color": "#414141",
"range.value.color": "#fff",
"range.value.fontWeight": "lighter",
"range.value.fontSize": "11px",
"range.value.border": "1px solid #353535",
"range.value.backgroundColor": "#151515",
"range.title.color": "#fff",
"range.title.fontWeight": "lighter",
// colorpicker style
"colorpicker.button.border": "1px solid #1e1e1e",
"colorpicker.title.color": "#fff",
};
export default {
name: "imageViewer",
data() {
return {
instance: null,
transform: {
scale: 1,
offsetX: 0,
offsetY: 0,
},
flag: false,
};
},
computed: {
imageEditor() {
return this.$refs["tui-image-editor"].querySelector(
".tui-image-editor-align-wrap"
);
},
imgStyle() {
return this.$refs["tui-image-editor"].querySelector(".tui-image-editor");
},
},
watch: {
instance: {
//监听当前是否选中工具栏,如果选中图片不可进行拖拽
// 不然就会导致如文字编辑图片跟随移动问题
handler(newVal) {
if (newVal.ui.submenu) {
this.flag = true;
//是否需要重置图片的放大缩小
// this.transform.offsetX = 0
// this.transform.offsetY = 0
// this.imgStyle.style.marginLeft = `0px`
// this.imgStyle.style.marginTop = `0px`
} else {
this.flag = false;
}
},
deep: true,
},
},
created() {
this.$nextTick(async () => {
await this.init();
await this.deviceSupportInstall();
document.addEventListener("mouseup", this.mouseup);
});
},
// 离开时销毁实例
beforeDestroy() {
document.removeEventListener("mouseup", this.mouseup);
this.imageEditor.removeEventListener("mousewheel", this._mouseWheelHandler);
this.imageEditor.removeEventListener("mousedown", this.mousedown);
this._mouseWheelHandler = null;
},
methods: {
mouseup() {
this.imageEditor.removeEventListener("mousemove", this._dragHandler);
},
deviceSupportInstall() {
this._mouseWheelHandler = rafThrottle((e) => {
const delta = e.wheelDelta ? e.wheelDelta : -e.detail;
if (delta > 0) {
this.handleActions("zoomIn", {
zoomRate: 0.05,
});
} else {
this.handleActions("zoomOut", {
zoomRate: 0.05,
});
}
});
this.imageEditor.addEventListener("mousewheel", this._mouseWheelHandler);
this.imageEditor.addEventListener("mousedown", this.mousedown);
},
mousedown(e) {
if (e.button !== 0) return;
const { offsetX, offsetY } = this.transform;
const startX = e.pageX;
const startY = e.pageY;
this._dragHandler = (ev) => {
// if (!ev) return this.imageEditor.removeEventListener('mousemove', this._dragHandler)
if (this.flag) return;
this.transform.offsetX = offsetX + ev.pageX - startX;
this.transform.offsetY = offsetY + ev.pageY - startY;
this.imgStyle.style.marginLeft = `${offsetX + ev.pageX - startX}px`;
this.imgStyle.style.marginTop = `${offsetY + ev.pageY - startY}px`;
};
this.imageEditor.addEventListener("mousemove", this._dragHandler);
},
handleActions(action, options = {}) {
const { zoomRate } = {
zoomRate: 0.2,
...options,
};
const { transform } = this;
switch (action) {
case "zoomOut":
if (transform.scale > 0.2) {
transform.scale = parseFloat(
(transform.scale - zoomRate).toFixed(3)
);
}
break;
case "zoomIn":
transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3));
break;
}
const { scale } = this.transform;
this.imgStyle.style.transform = `scale(${scale})`;
},
init() {
this.$nextTick(() => {
this.instance = new ImageEditor(
document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg",
name: "image",
},
menu: [
"resize",
"crop",
"rotate",
"draw",
"shape",
"icon",
"text",
"filter",
], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
initMenu: "resize", // 默认打开的菜单项
menuBarPosition: "bottom", // 菜单所在的位置
locale: locale_zh, // 本地化语言为中文
theme: customTheme, // 自定义样式
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
document.getElementsByClassName("tui-image-editor-main")[0].style.top =
"0px"; // 调整图片显示位置
});
},
// 文件下载
downloadImg() {
const base64String = this.instance.toDataURL();
const file = base64ToFile(base64String, "图片");
fileLocalDownLoad(file, "图片");
},
//上传
upload() {
// blob 转换成 File 对象
let blob = base64ToFile(this.instance.toDataURL(), "图片");
let file = new window.File([blob], blob.name, { type: blob.type });
let form = new FormData();
form.append("file", file);
},
},
};
</script>
<style lang="scss" scoped>
.image-view {
height: 100%;
width: 100%;
.container {
height: 86vh;
text-align: center;
// 防止图片放大缩小时上下滚动
>>> .tui-image-editor-wrap {
overflow: hidden;
}
>>> .tui-image-editor-canvas-container {
cursor: pointer;
}
>>> .tui-image-editor-container
.tui-image-editor-submenu
.tui-image-editor-submenu-item
label
> span {
padding-top: 0;
}
}
.bottom {
display: flex;
justify-content: flex-end;
margin: 10px;
}
}
</style>