vue2.x tui-image-editor图片编辑器的使用

贴个官网: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>

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值