前言
最近用户提出了一个新的需要,老师能够批改学生的图片作业,须要对图片进行旋转、缩放、裁剪、涂鸦、标注、增加文本等。乍一听,又要掉不少头发。有没有功能强大的插件实现以上性能,让我有更多的工夫去阻止女票双十一剁手呢?答案当然是有的。
成果展现
涂鸦
裁剪
标注
旋转
滤镜
是不是很弱小!还有泛滥性能我就不一一展现了。那么还等什么,跟我一起用起来吧~
装置
npm i tui-image-editor
// or
yarn add tui-image-editor
应用
疾速体验
复制以下代码,将插件引入到本人的我的项目中。
<template>
<div class="drawing-container">
<div id="tui-image-editor"></div>
</div>
</template>
<script>
import "tui-image-editor/dist/tui-image-editor.css";
import "tui-color-picker/dist/tui-color-picker.css";
import ImageEditor from "tui-image-editor";
export default {data() {
return {instance: null,};
},
mounted() {this.init();
},
methods: {init() {
this.instance = new ImageEditor(document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
name: "image",
},
initMenu: "draw", // 默认关上的菜单项
menuBarPosition: "bottom", // 菜单所在的地位
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
document.getElementsByClassName("tui-image-editor-main")[0].style.top = "45px"; // 图片距顶部工具栏的间隔
},
},
};
</script>
<style lang="scss" scoped>
.drawing-container {height: 900px;}
</style>
能够看到活生生的图片编辑工具就呈现了,是不是很简略:
国际化
因为是老外开发的,默认的文字描述都是英文,这里咱们先汉化一下:
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": "锁定宽高比例",
};
this.instance = new ImageEditor(document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
name: "image",
},
initMenu: "draw", // 默认关上的菜单项
menuBarPosition: "bottom", // 菜单所在的地位
locale: locale_zh, // 本地化语言为中文
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
成果如下:
自定义款式
默认格调为暗黑系,如果想改成白底,或者想扭转按钮的大小、色彩等款式,能够应用自定义款式。
const customTheme = {
"common.bi.image": "", // 左上角 logo 图片"common.bisize.width":"0px","common.bisize.height":"0px","common.backgroundImage":"none","common.backgroundColor":"#f3f4f6","common.border":"1px solid #333",
// 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": "#8a8a8a",
"menu.activeIcon.color": "#555555",
"menu.disabledIcon.color": "#ccc",
"menu.hoverIcon.color": "#e9e9e9",
"submenu.normalIcon.color": "#8a8a8a",
"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",
};
this.instance = new ImageEditor(document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
name: "image",
},
initMenu: "draw", // 默认关上的菜单项
menuBarPosition: "bottom", // 菜单所在的地位
locale: locale_zh, // 本地化语言为中文
theme: customTheme, // 自定义款式
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
成果如下:
按钮优化
通过自定义款式,咱们看到右上角的 Load 和 Download 按钮曾经被暗藏了,接下来咱们再暗藏掉其余用不上的按钮(依据业务须要),并增加一个保留图片的按钮。
<template>
<div class="drawing-container">
<div id="tui-image-editor"></div>
<el-button class="save" type="primary" size="small" @click="save"> 保留 </el-button>
</div>
</template>
// ...
methods: {init() {
this.instance = new ImageEditor(document.querySelector("#tui-image-editor"),
{
includeUI: {
loadImage: {
path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
name: "image",
},
menu: ["resize", "crop", "rotate", "draw", "shape", "icon", "text", "filter"], // 底部菜单按钮列表 暗藏镜像 flip 和遮罩 mask
initMenu: "draw", // 默认关上的菜单项
menuBarPosition: "bottom", // 菜单所在的地位
locale: locale_zh, // 本地化语言为中文
theme: customTheme, // 自定义款式
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600, // canvas 最大高度
}
);
document.getElementsByClassName("tui-image-editor-main")[0].style.top ="45px"; // 调整图片显示地位
document.getElementsByClassName("tie-btn-reset tui-image-editor-item help") [0].style.display = "none"; // 暗藏顶部重置按钮
},
// 保留图片,并上传
save() {const base64String = this.instance.toDataURL(); // base64 文件
const data = window.atob(base64String.split(",")[1]);
const ia = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) {ia[i] = data.charCodeAt(i);
}
const blob = new Blob([ia], {type: "image/png"}); // blob 文件
const form = new FormData();
form.append("image", blob);
// upload file
},
}
<style lang="scss" scoped>
.drawing-container {
height: 900px;
position: relative;
.save {
position: absolute;
right: 50px;
top: 15px;
}
}
</style>
成果如下:
能够看到顶部的重置按钮,以及底部的镜像和遮罩按钮都曾经不见了。右上角多了一个咱们本人的保留按钮,点击按钮,能够获取到 base64 文件和 blob 文件。
残缺代码
<template>
<div class="drawing-container">
<div id="tui-image-editor"></div>
<el-button class="save" type="primary" size="small" @click="save"> 保留 </el-button>
</div>
</template>
<script>
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 #333",
// 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": "#8a8a8a",
"menu.activeIcon.color": "#555555",
"menu.disabledIcon.color": "#ccc",
"menu.hoverIcon.color": "#e9e9e9",
"submenu.normalIcon.color": "#8a8a8a",
"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 {data() {
return {instance: null}
},
mounted() {this.init()
},
methods: {init() {this.instance = new ImageEditor(document.querySelector('#tui-image-editor'), {
includeUI: {
loadImage: {
path: 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image',
name: 'image'
},
menu: ['resize', 'crop', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'], // 底部菜单按钮列表 暗藏镜像 flip 和遮罩 mask
initMenu: 'draw', // 默认关上的菜单项
menuBarPosition: 'bottom', // 菜单所在的地位
locale: locale_zh, // 本地化语言为中文
theme: customTheme // 自定义款式
},
cssMaxWidth: 1000, // canvas 最大宽度
cssMaxHeight: 600 // canvas 最大高度
})
document.getElementsByClassName('tui-image-editor-main')[0].style.top = '45px' // 调整图片显示地位
document.getElementsByClassName('tie-btn-reset tui-image-editor-item help')[0].style.display = 'none' // 暗藏顶部重置按钮
},
// 保留图片,并上传
save() {const base64String = this.instance.toDataURL() // base64 文件
const data = window.atob(base64String.split(',')[1])
const ia = new Uint8Array(data.length)
for (let i = 0; i < data.length; i++) {ia[i] = data.charCodeAt(i)
}
const blob = new Blob([ia], {type: 'image/png'}) // blob 文件
const form = new FormData()
form.append('image', blob)
// upload file
}
}
}
</script>
<style lang="scss" scoped>
.drawing-container {
height: 900px;
position: relative;
.save {
position: absolute;
right: 50px;
top: 15px;
}
}
</style>
总结
以上就是 tui.image-editor 的根本应用办法,相比其余插件,tui.image-editor 的劣势是功能强大,简略易上手。
插件诚然好用,但自己也发现一个小 bug,当放大图片,用手掌拖动显示地位,再点击重置按钮时,图片很可能就隐没不见了。解决办法有两个,一是改源码,在重置之前,先调用 resetZoom 办法,还原缩放比列;二是本人做一个重置按钮,点击之后调用 this.init 办法从新进行渲染。
赠人玫瑰,手有余香。如果感觉有用,就动动发财的小手,点个赞把~😜
更多 API 及 Demo 请参考:
github 地址:https://github.com/nhn/tui.im…
API 及 Examples 地址:http://nhn.github.io/tui.imag…
其余插件
每一款都是自己亲测,精挑细选、凤毛麟角。让你有更多工夫去摸🐟
Vue 1 分钟实现右键菜单,懒人的福音
Vue 如何疾速实现头像裁剪?办法比你设想的简略
如何在富文本中插入表情,word 文档,及数学公式?
1 分钟实现拖拽,让你划水更自在