淘宝&天猫商品图片快捷复制

将商品图片拷贝到剪切板

// ==UserScript==
// @name         淘宝&天猫商品图片快捷复制
// @namespace    http://tampermonkey.net/
// @version      0.7
// @description  将商品图片拷贝到剪切板
// @author       lwj
// @match        *://detail.tmall.com/item*
// @match        *://item.taobao.com/item*
// @match        *://chaoshi.detail.tmall.com/item*
// @match        *://traveldetail.fliggy.com/item*
// @match        *://detail.tmall.hk/hk/item*
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

(function () {
  var notificationTimer; // 通知计时器
  var isHiding = false; // 标志,表示是否正在隐藏通知

  var notification_style = document.createElement('style');
  notification_style.type = 'text/css';
  notification_style.innerHTML = `
          @keyframes showNotification {
              0% {
                  transform: translateX(-50%) scale(0);
              }
              40% {
                  transform: translateX(-50%) scale(.96);
              }
              55% {
                  transform: translateX(-50%) scale(1.04);
              }
              100% {
                  transform: translateX(-50%) scale(1);
              }
          }

          @keyframes hideNotification {
              5% {
                  transform: translateX(-50%) scale(1);
              }
              100% {                
                  opacity: 0;
                  transform: translateX(-50%) scale(0.2);
              }
          }

          @keyframes notificationButtonAnimation {
              0% { transform: translateX(-50%) scale(1); }
              100% { transform: translateX(-50%) scale(1.15); opacity: 0;}
          }

          .notification {
              cursor: default;
              position: fixed;
              bottom: 60px; 
              left: 50%;
              background-color: rgba(233, 233, 233, .7);
              color: rgb(51, 51, 51);
              font-size: 16px;
              font-weight: 500;
              padding: 10px;
              border-radius: 12px;
              border: 1px solid rgba(173, 173, 173, .3);
              display: none;
              z-index: 9999999999;
              backdrop-filter: saturate(180%) blur(20px); /* 添加模糊效果 */
              -webkit-backdrop-filter: blur(20px); /* 兼容Safari浏览器 */
              transform-origin: center;
              width: auto; /* 默认宽度 */
              max-width: 68%;
              white-space: nowrap; /* 单行显示 */
              overflow: hidden; /* 超出内容隐藏 */
              text-overflow: ellipsis; /* 溢出省略号 */
              text-align: center; /* 文本居中显示 */
              transform: translateX(-50%); /* 初始水平居中 */
          }
          `;
  document.head.appendChild(notification_style);

  // 创建通知弹窗
  var NotificationContainer = document.createElement('div');
  NotificationContainer.classList.add('notification');
  NotificationContainer.id = 'showNotificationContainer';
  document.body.appendChild(NotificationContainer);

  // 添加鼠标悬浮和移出事件监听器
  NotificationContainer.addEventListener('mouseenter', function () {
      clearTimeout(notificationTimer); // 悬浮时清除计时器
      // console.log('Mouse entered notification'); // 调试日志
  });
  NotificationContainer.addEventListener('mouseleave', function () {
      // console.log('Mouse left notification'); // 调试日志
      var time = 3000;
      resetTimer(time); // 移出时重置计时器
  });

  function showNotification(message, duringTime = 3000, showImage = false) {
      // 清除之前的计时器
      if (notificationTimer) {
          clearTimeout(notificationTimer);
      }

      // 重置隐藏标志
      isHiding = false;

      // 重置通知样式
      NotificationContainer.innerHTML = '';
      NotificationContainer.style.width = 'auto';
      NotificationContainer.style.transform = 'translateX(-50%)';
      NotificationContainer.style.animation = 'none';
      NotificationContainer.style.padding = '10px';

      // 短暂移除并重新添加通知元素,强制触发动画
      document.body.removeChild(NotificationContainer);
      setTimeout(() => {
          document.body.appendChild(NotificationContainer);

          // 设置通知文本内容
          NotificationContainer.innerHTML = message;

          // 如果指定了显示图片,则读取剪贴板中的图片并显示
          if (showImage) {
              NotificationContainer.style.padding = '5px';
              navigator.clipboard.read().then(async function (data) {
                  for (const item of data) {
                      for (const type of item.types) {
                          if (type.startsWith('image/')) {
                              const blob = await item.getType(type);
                              const imageURL = URL.createObjectURL(blob);

                              const imageElement = document.createElement('img');
                              imageElement.src = imageURL;
                              imageElement.style.width = '300px';
                              imageElement.style.borderRadius = '8px';

                              const imageContainer = document.createElement('div');
                              imageContainer.style.paddingTop = '10px';
                              imageElement.style.maxWidth = 'auto';
                              imageContainer.style.borderRadius = '8px';
                              imageContainer.style.margin = 'auto';
                              imageContainer.style.display = 'block';
                              imageContainer.appendChild(imageElement);

                              NotificationContainer.appendChild(imageContainer);

                              // 图片加载完成后调整位置并设置消失定时器
                              imageElement.onload = function () {
                                  NotificationContainer.style.left = '50%';

                                  NotificationContainer.style.display = 'block';
                                  NotificationContainer.style.animation = 'showNotification 0.5s forwards';
                                  // 设置消失动画计时器
                                  resetTimer(duringTime);
                              };

                              break;
                          }
                      }
                  }
              }).catch(function (error) {
                  console.error('Error reading clipboard:', error);
              });
          } else {
              // 显示通知
              NotificationContainer.style.display = 'block';
              NotificationContainer.style.animation = 'showNotification 0.5s forwards';

              // 设置消失动画计时器
              resetTimer(duringTime);
          }
      }, 50); // 确保通知元素短暂移除再添加
  }

  function hideNotification() {
      if (isHiding) return;
      isHiding = true;

      NotificationContainer.style.animation = 'hideNotification 0.5s forwards';

      // 在动画结束后隐藏元素
      notificationTimer = setTimeout(function () {
          NotificationContainer.style.display = 'none';
          isHiding = false;
      }, 500);
  }

  function resetTimer(duringTime = 3000) {
      if (notificationTimer) {
          clearTimeout(notificationTimer);
          console.log("清除计时器");
      }
      if (duringTime > 0) {
          notificationTimer = setTimeout(function () {
              hideNotification();
              console.log("设置计时器");
          }, duringTime); // 3秒后自动隐藏通知
      }
  }

  /*
  淘宝、天猫主图复制到剪贴板功能
  */
  function createGetTmallPngButton() {
      // 找到匹配的元素的编号
      function findMatchingIndex(wrapperClass, imgClass) {
          for (let i = 0; i < wrapperClass.length; i++) {
              const wrapper = document.querySelector(wrapperClass[i]);
              if (wrapper) {
                  const img = wrapper.querySelector(imgClass[i]); // 找到图片元素
                  const button = wrapper.querySelector('#button_getTmallPngButton'); // 找到按钮元素

                  if (img && !button) {
                      return i; // 返回匹配的编号
                  } else {
                      return -1; // 如果按钮已存在,则返回 -1
                  }
              }
          }
          return -1; // 如果没有找到匹配的元素,则返回 -1
      }


      const wrapperClass = ['.itemImgWrap--bUt5RRLT', '.PicGallery--mainPicWrap--juPDFPo', '.mainPicWrap--Ns5WQiHr', '.PicGallery--mainPicWrap--1c9k21r', '.item-gallery-top.item-gallery-prepub2'];
      const imgClass = ['.itemImg--O9S7hs0i', '.PicGallery--mainPic--34u4Jrw', '.mainPic--zxTtQs0P', '.PicGallery--mainPic--1eAqOie', '.item-gallery-top__img'];

      const matchingIndex = findMatchingIndex(wrapperClass, imgClass);

      if (matchingIndex !== -1) {
          addButton(wrapperClass, imgClass, matchingIndex);
          addButton(wrapperClass, imgClass, 0);
      } else {
          // console.error('Wrapper element not found.');
      }

      function addButton(wrapperClass, imgClass, matchingIndex) {
          const wrapper = document.querySelector(wrapperClass[matchingIndex]);
          console.log("wrapper:", wrapper);

          const old_button = wrapper.querySelector('#button_getTmallPngButton'); // 找到按钮元素
          if (old_button) {
              return; // 如果按钮已存在,则直接返回
          }

          if (wrapper) {
              const button = document.createElement('button');
              button.textContent = '复制图片';
              button.id = 'button_getTmallPngButton';
              button.style.cssText = `
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  padding: 5px 20px;
                  font-size: 16px;
                  background-color: rgba(22, 22, 23, .7);
                  color: #fff;
                  border: none;
                  border-radius: 999px;
                  font-family: AlibabaPuHuiTi_2_55_Regular;
                  backdrop-filter: saturate(180%) blur(20px); /* 添加模糊效果 */
                  -webkit-backdrop-filter: blur(20px); /* 兼容Safari浏览器 */
                  text-align: center; /* 文本居中显示 */
                  cursor: pointer;
                  opacity: 0;
                  transition: opacity 0.3s ease, color 0.15s ease, background-color 0.25s ease;;
                  z-index: 999;
              `;

              // 控制按钮显示
              wrapper.addEventListener('mouseenter', () => {
                  button.style.opacity = '1';
              });

              // 控制按钮隐藏
              wrapper.addEventListener('mouseleave', () => {
                  button.style.opacity = '0';
              });

              button.addEventListener('click', async () => {
                  const img = wrapper.querySelector(imgClass[matchingIndex]);
                  // console.log("img:", img);
                  if (img) {
                      try {
                          const imageUrl = img.src;
                          const response = await fetch(imageUrl);
                          const blob = await response.blob();
                          const image = new Image();
                          image.src = URL.createObjectURL(blob);

                          image.onload = () => {
                              const canvas = document.createElement('canvas');
                              const ctx = canvas.getContext('2d');
                              canvas.width = image.width;
                              canvas.height = image.height;
                              ctx.drawImage(image, 0, 0);
                              canvas.toBlob(async (blob) => {
                                  try {
                                      await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);
                                      showNotification("图片已成功复制到剪贴板", undefined, true);
                                      button.textContent = '复制成功';
                                      button.style.backgroundColor = 'rgba(233, 233, 233, .7)'; // 按钮颜色改变
                                      button.style.color = '#000'; // 按钮文字颜色改变

                                      setTimeout(() => {
                                          button.textContent = '复制图片';
                                          button.style.backgroundColor = 'rgba(22, 22, 23, .7)'; // 按钮颜色恢复
                                          button.style.color = '#fff'; // 按钮文字颜色恢复

                                      }, 1500); // 1.5秒后恢复按钮文字
                                      // alert('Image copied to clipboard!');
                                  } catch (error) {
                                      console.error('Failed to copy image to clipboard:', error);
                                      // alert('Failed to copy image to clipboard.');
                                      showNotification('图片复制失败!');
                                  }
                              }, 'image/png');
                          };
                      } catch (error) {
                          showNotification('图片复制失败!');
                          console.error('Failed to fetch or process image:', error);
                          // alert('Failed to copy image to clipboard.');
                      }
                  } else {
                      // alert('Image not found!');
                  }
              });

              wrapper.style.position = 'relative'; // 确保按钮在图片上层
              wrapper.appendChild(button);
          }
      }
  }

  window.addEventListener('load', createGetTmallPngButton);
  const auxiliaryFunctions = new MutationObserver((mutationsList) => {

      for (let mutation of mutationsList) {
          if (mutation.type === 'childList') {
              createGetTmallPngButton();
          }
      }
  });

  // 观察目标节点的子节点添加和移除
  auxiliaryFunctions.observe(document.body, { childList: true, subtree: true });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址